changeset 26269:4d4a385e6390 stable

maint: Merge default to stable.
author John W. Eaton <jwe@octave.org>
date Thu, 20 Dec 2018 17:18:56 -0500
parents b326eeae92d0 (current diff) 6dd232798997 (diff)
children a88cf545cfca
files build-aux/subst-default-vals.in.sh etc/RELEASE.PROCESS libgui/qterminal-module.mk libgui/src/octave-settings.h libinterp/corefcn/gammainc.cc libinterp/corefcn/gripes.cc libinterp/corefcn/gripes.h libinterp/corefcn/oct-tex-parser.in.yy libinterp/corefcn/str2double.cc libinterp/corefcn/txt-eng.cc libinterp/dldfcn/__osmesa_print__.cc libinterp/mk-pkg-add.sh libinterp/mk-version-h.in.sh libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-jump.cc libinterp/version.cc libinterp/version.in.h liboctave/external/blas-xtra/xerbla.c liboctave/external/fftpack/cfftb.f liboctave/external/fftpack/cfftb1.f liboctave/external/fftpack/cfftf.f liboctave/external/fftpack/cfftf1.f liboctave/external/fftpack/cffti.f liboctave/external/fftpack/cffti1.f liboctave/external/fftpack/fftpack.doc liboctave/external/fftpack/module.mk liboctave/external/fftpack/passb.f liboctave/external/fftpack/passb2.f liboctave/external/fftpack/passb3.f liboctave/external/fftpack/passb4.f liboctave/external/fftpack/passb5.f liboctave/external/fftpack/passf.f liboctave/external/fftpack/passf2.f liboctave/external/fftpack/passf3.f liboctave/external/fftpack/passf4.f liboctave/external/fftpack/passf5.f liboctave/external/fftpack/zfftb.f liboctave/external/fftpack/zfftb1.f liboctave/external/fftpack/zfftf.f liboctave/external/fftpack/zfftf1.f liboctave/external/fftpack/zffti.f liboctave/external/fftpack/zffti1.f liboctave/external/fftpack/zpassb.f liboctave/external/fftpack/zpassb2.f liboctave/external/fftpack/zpassb3.f liboctave/external/fftpack/zpassb4.f liboctave/external/fftpack/zpassb5.f liboctave/external/fftpack/zpassf.f liboctave/external/fftpack/zpassf2.f liboctave/external/fftpack/zpassf3.f liboctave/external/fftpack/zpassf4.f liboctave/external/fftpack/zpassf5.f liboctave/numeric/lo-fftpack-proto.h liboctave/util/lo-array-gripes.cc liboctave/util/lo-array-gripes.h scripts/deprecated/bitmax.m scripts/deprecated/isstr.m scripts/deprecated/mahalanobis.m scripts/deprecated/md5sum.m scripts/deprecated/octave_config_info.m scripts/deprecated/onenormest.m scripts/deprecated/setstr.m scripts/deprecated/sleep.m scripts/deprecated/usleep.m scripts/deprecated/wavread.m scripts/deprecated/wavwrite.m scripts/general/flipdim.m scripts/io/strread.m scripts/io/textread.m scripts/miscellaneous/genvarname.m scripts/miscellaneous/isdir.m scripts/strings/findstr.m scripts/strings/strmatch.m
diffstat 916 files changed, 60964 insertions(+), 43847 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Dec 04 10:12:41 2018 -0800
+++ b/.hgignore	Thu Dec 20 17:18:56 2018 -0500
@@ -1,53 +1,121 @@
 syntax: regexp
-# The recurrent (^|/) idiom in the regexps below should be understood
-# to mean "at any directory" while the ^ idiom means "from the
-# project's top-level directory".
+## The recurrent (^|/) idiom in the regexps below should be understood
+## to mean "at any directory" while the ^ idiom means "from the
+## project's top-level directory".
 
-# gnulib makes these silly backup files
+## gnulib related files
+# gnulib makes these silly backup files.
 .~$
-
 # This directory gets created by gnulib during the build.
 # It contains no Octave files.
-^libgnu($|/)
+(^|/)libgnu($|/)
 
+## m4 related files
 # This directory mostly contains cruft during build time, but it does
-# contain some Octave code, so we gotta be a bit more careful about
-# what we ignore here
+# contain some Octave code, so be more careful about what we ignore here.
 ^m4/(?!ax_).+\.m4$
 
-# Emacs tools create these
+## Autoconf, Automake automatically generated files
+^aclocal\.m4$
+^autom4te\.cache($|/)
+^config\.in\.h$
+^configure$
+(^|/)config.cache$
+(^|/)config.h$
+(^|/)config.log$
+(^|/)config.status$
+
+^Makefile\.in$
+^INSTALL$
+
+## Emacs associated files
 (^|/)TAGS$
 (^|/)semantic.cache$
 
-(/|^)Makefile\.in$
-^INSTALL$
-
-^aclocal\.m4$
-^autom4te\.cache($|/)
+## Scripts associated with building Octave
 ^build-aux/config\.(guess|rpath|sub)$
+(^|/)build-aux/check-subst-vars\.sh$
 ^build-aux/depcomp$
 ^build-aux/install-sh$
 ^build-aux/ltmain\.sh$
 ^build-aux/mdate-sh$
 ^build-aux/missing$
 ^build-aux/move-if-change$
+(^|/)build-aux/subst-config-vals\.sh$
+(^|/)build-aux/subst-cross-config-vals\.sh$
+(^|/)build-aux/subst-script-vals\.sh$
 ^build-aux/texinfo\.tex$
 ^build-aux/ylwrap$
-^config\.in\.h$
-^configure$
+
+## Mercurial associated files
+(^|/)HG-ID$
+
+## Timestamp files used in build process
+.*/\.dirstamp$
+.*/\.octave-dirstamp$
+
+## Intermediate compilation results for libraries
+.*\.la$
+.*/\.libs/
+.*\.Plo$
+.*\.Po$
+
+
+## DLDFCN associated files
+^libinterp/dldfcn/module\.mk$
+(^|/)libinterp/dldfcn/PKG_ADD$
+(^|/)libinterp/dldfcn/.*\.oct$
 
-# e.g. doc/faq/OctaveFAQ.info
-#      doc/interpreter/octave.info-4
+## liboctave/ directory associated patterns
+# E.g., liboctave/operators/smx-op-inc.mk
+^liboctave/operators/\w+-op-\w+\.mk$
+
+## scripts/ directory associated patterns
+# Package files
+(^|/)scripts/.*/PKG_ADD$
+# Java files
+(^|/)scripts/java/octave\.jar$
+(^|/)scripts/java/org/octave/.*\.class$
+
+## libgui/ associated patterns
+# Files generated by moc tool
+(^|/)libgui/.*/moc-.*\.(cc|h)$
+(^|/)libgui/languages/.*\.qm$
+
+## Ignore patterns associated with documentation
+# Info generated files
+# E.g., doc/faq/OctaveFAQ.info, doc/interpreter/octave.info-4
 ^doc/\w+/\w+\.info(-\d+)?$
 
+# Texinfo created temporary directories
+(^|/)doc/(interpreter|liboctave)/(octave|liboctave)\.t2(d|p)/
+# Texinfo created files
+(^|/)doc/interpreter/.*\.texi$
+
+# DOCSTRINGS files built in the source tree
+(^|/)(libinterp|scripts)/DOCSTRINGS$
+
+# Generated HTML directories
+(^|/)doc/interpreter/octave\.html/
+(^|/)doc/liboctave/liboctave\.html/
+
+# Miscellaneous auto-generated files 
+(^|/)doc/interpreter/octave\.dvi$
+(^|/)doc/interpreter/octave\.ps$
+(^|/)doc/interpreter/doc-cache$
+(^|/)doc/interpreter/octave_interpreter\.q(ch|hc)$
+
+# Images and scripts for documentation
+^doc/interpreter/images\.mk$
+(^|/)doc/interpreter/.*\.eps$
+(^|/)doc/interpreter/.*\.pdf$
+(^|/)doc/interpreter/.*\.png$
+(^|/)doc/interpreter/.*\.txt$
+
+# timestamps for doc directory
 ^doc/\w+/stamp-(vti|\d+)$
 ^doc/\w+/version-\w+\.texi$
-^doc/interpreter/images\.mk$
-
-# e.g. liboctave/operators/smx-op-inc.mk
-^liboctave/operators/\w+-op-\w+\.mk$
 
-^libinterp/dldfcn/module\.mk$
+## Test associated patterns
+.*-tst$
 
-# DOCSTRINGS files are built in the source tree
-^(libinterp|scripts)/DOCSTRINGS$
--- a/.hgsubstate	Tue Dec 04 10:12:41 2018 -0800
+++ b/.hgsubstate	Thu Dec 20 17:18:56 2018 -0500
@@ -1,1 +1,1 @@
-791f51373ba1b80c8ae3b7a9d2509d8a827a3e25 gnulib
+a4bc639f000375e3522c56509d30d51a2740694b gnulib
--- a/Makefile.am	Tue Dec 04 10:12:41 2018 -0800
+++ b/Makefile.am	Thu Dec 20 17:18:56 2018 -0500
@@ -43,7 +43,7 @@
 
 # C compiler flags.
 
-AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS}
+AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} ${WARN_CFLAGS}
 
 # ifeq (${INCLUDE_DEPS},no)
 #   omit_deps = true;
@@ -51,7 +51,7 @@
 
 # C++ compiler flags.
 
-AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS}
+AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS} ${WARN_CXXFLAGS}
 
 FFTW_XCPPFLAGS = @FFTW_XCPPFLAGS@
 FFTW_XLDFLAGS = @FFTW_XLDFLAGS@
@@ -102,6 +102,10 @@
 octfonts_DATA =
 octlocale_DATA =
 
+OCT_FILES =
+OCT_FILE_LIBS =
+OCT_FILE_PKG_ADD_FILES =
+
 DOC_TARGETS =
 
 BUILT_DISTFILES =
@@ -123,6 +127,7 @@
   INSTALL \
   NEWS \
   README \
+  octave.doap \
   run-octave.in \
   $(BUILT_DISTFILES)
 
@@ -148,6 +153,7 @@
 info_TEXINFOS =
 BUILT_SOURCES =
 TEST_FILES =
+noinst_TEST_FILES =
 
 DOC_IMAGES_SRC =
 BUILT_DOC_IMAGES =
@@ -183,6 +189,8 @@
 octinclude_HEADERS =
 nodist_octinclude_HEADERS =
 
+pkgconfig_DATA =
+
 DIST_SRC =
 
 ALL_LOCAL_TARGETS =
@@ -208,7 +216,6 @@
 include src/module.mk
 include scripts/module.mk
 include doc/module.mk
-include doc/interpreter/images.mk
 include etc/module.mk
 include examples/module.mk
 include m4/module.mk
@@ -220,6 +227,7 @@
   docs-dist-hook \
   fix-file-perms-dist-hook \
   hg-id-dist-hook \
+  appdata-dist-hook \
   icons-dist-hook \
   scripts-dist-hook
 
@@ -300,6 +308,9 @@
 nodist_octinclude_HEADERS += \
   octave-config.h
 
+OCTAVE_INTERPRETER_TARGETS += \
+  $(OCT_FILE_PKG_ADD_FILES)
+
 ALL_LOCAL_TARGETS += \
   $(OCTAVE_INTERPRETER_TARGETS) \
   .gdbinit \
@@ -359,7 +370,7 @@
   rm -f $@-t && \
   if [ -d $(srcdir)/.hg ]; then \
     ( cd $(srcdir); \
-      hg log --style=build-aux/changelog.tmpl --prune=b0e60ad4ae26 --only-branch=`hg branch`; \
+      hg log --no-graph --style=build-aux/changelog.tmpl --prune=b0e60ad4ae26 --only-branch=`hg branch`; \
       echo ""; \
       echo "See the files in the directory etc/OLD-ChangeLogs for changes before 2011-04-19"; \
     ) > $@-t && \
@@ -410,6 +421,39 @@
 
 install-data-local: installdirs-local
 
+oct-file-pkg-add: $(OCT_FILE_PKG_ADD_FILES)
+	cat $(OCT_FILE_PKG_ADD_FILES) > $@-t \
+	  && mv $@-t $@
+
+install-oct: oct-file-pkg-add
+	$(MKDIR_P) $(DESTDIR)$(octfiledir)
+	if [ -n "`cat $(OCT_FILE_PKG_ADD_FILES)`" ]; then \
+	  $(INSTALL_DATA) oct-file-pkg-add $(DESTDIR)$(octfiledir)/PKG_ADD; \
+	fi
+	cd $(DESTDIR)$(octlibdir) && \
+	for ltlib in $(OCT_FILE_LIBS); do \
+	  f=`echo $$ltlib | $(SED) 's,.*/,,'`; \
+	  dl=`$(SED) -n -e "s/dlname='\([^']*\)'/\1/p" < $$f`; \
+	  if [ -n "$$dl" ]; then \
+	    $(INSTALL_PROGRAM) $$dl $(DESTDIR)$(octfiledir)/`echo $$f | $(SED) 's,^lib,,; s,\.la$$,.oct,'`; \
+	  else \
+	    echo "error: dlname is empty in $$ltlib!"; \
+	    exit 1; \
+	  fi; \
+	  lnames=`$(SED) -n -e "s/library_names='\([^']*\)'/\1/p" < $$f`; \
+	  if [ -n "$$lnames" ]; then \
+	    rm -f $$f $$lnames $$dl; \
+	  fi \
+	done
+.PHONY: install-oct
+
+uninstall-oct:
+	for f in $(notdir $(OCT_FILES)); do \
+	  rm -f $(DESTDIR)$(octfiledir)/$$f; \
+	done
+	rm -f $(DESTDIR)$(octfiledir)/PKG_ADD
+.PHONY: uninstall-oct
+
 clean-local: doc-clean
 
 distclean-local:
@@ -458,38 +502,6 @@
   mv $@-t $@
 endef
 
-define subst-bison-api-decls
-  case "${BISON_API_PREFIX_DECL_STYLE}" in \
-    *api*) \
-      case "${BISON_API_PREFIX_DECL_STYLE}" in \
-       *brace*) \
-         api_prefix_decl='%define api.prefix {$(1)}'; ;; \
-       *) \
-         api_prefix_decl='%define api.prefix "$(1)"'; ;; \
-       esac; \
-      ;; \
-    *name*) \
-      case "${BISON_API_PREFIX_DECL_STYLE}" in \
-        *brace*) \
-          api_prefix_decl='%name-prefix {$(1)}'; ;; \
-        *) \
-          api_prefix_decl='%name-prefix="$(1)"'; ;; \
-      esac; \
-    ;; \
-  esac; \
-  case "${BISON_PUSH_PULL_DECL_STYLE}" in \
-    *quote*) quote='"' ;; \
-    *) quote="" ;; \
-  esac; \
-  case "${BISON_PUSH_PULL_DECL_STYLE}" in \
-    *dash*) push_pull_decl="%define api.push-pull $${quote}both$${quote}"; ;; \
-    *underscore*) push_pull_decl="%define api.push_pull $${quote}both$${quote}"; ;; \
-  esac; \
-  ${SED} -e "s/%PUSH_PULL_DECL%/$$push_pull_decl/" \
-         -e "s/%API_PREFIX_DECL%/$$api_prefix_decl/" $< > $@-t && \
-  mv $@-t $@
-endef
-
 define gdbinit-install-rule
   if [ -f $@ ] && ! cmp -s $< $@; then \
     echo "refusing to overwrite $@ with newer version from $<" 1>&2; \
--- a/NEWS	Tue Dec 04 10:12:41 2018 -0800
+++ b/NEWS	Thu Dec 20 17:18:56 2018 -0500
@@ -1,962 +1,246 @@
-Summary of important user-visible changes for version 4.4 (2018-04-30):
+Summary of important user-visible changes for version 5.0 (yyyy-mm-dd):
 ----------------------------------------------------------------------
 
- ** A graphical Variable Editor has been added to the GUI interface.
-    It uses a spreadsheet-like interface for quick, intuitive editing
-    of variables.  The Variable Editor is launched by double-clicking
-    on a variable name in the Workspace Window or by typing
-    "openvar VARIABLE_NAME" in the Command Window.
-
- ** On systems with 64-bit pointers, --enable-64 is now the default and
-    Octave always uses 64-bit indexing.  However, if the configure
-    script determines that the BLAS library uses 32-bit integers, then
-    operations using the following libraries are limited to arrays with
-    dimensions that are smaller than 2^31 elements:
-
-      BLAS  LAPACK  QRUPDATE  SuiteSparse  ARPACK
+ ** The determination of an object's dimensions, size, and shape by the
+    functions ndims, rows, columns, isscalar, isvector, isrow, iscolumn,
+    ismatrix, and issquare now fully depends on the function size.
+    Thus, any user-defined object can ensure correct treatment by the
+    aforementioned functions by properly overloading the "size"
+    function.
 
-    Additionally, the following libraries use "int" internally, so
-    maximum problem sizes are always limited:
-
-      glpk  Qhull
-
- ** The octave command no longer starts the GUI by default.  Most users
-    starting Octave from a shell were expecting the command line
-    interface, and desktop launchers already required the `--force-gui'
-    option.  With this change, desktop launchers should be modified to
-    use the new option `--gui'.  The previous `--force-gui' option will
-    continue to work, and maps to `--gui', but it will be removed in
-    Octave 6.
-
- ** A known bug in Qt (https://bugreports.qt.io/browse/QTBUG-55357) is
-    addressed by limiting GUI sub-panel relocation capabilities for Qt
-    versions in the range >= 5.6.1 and < 5.7.1.  However, this may not
-    thoroughly avoid issues on all platforms.
+ ** The function randi has been recoded to produce an unbiased (all
+    results are equally likely) sample of integers.  This may produce
+    different results in existing code.  If it is necessary to reproduce
+    the exact random integer sequence as in previous versions use
+    
+      ri = imin + floor ((imax - imin + 1) * rand ());
 
- ** A new container data type--containers.Map--is available.  Map is a
-    key/value storage container (a.k.a, a hash) that efficiently allows
-    storing and retrieving values by name, rather than by position which
-    is how arrays work.
+ ** A new core function movfun will apply a function to a sliding
+    window of arbitrary size on a dataset and accumulate the results.
+    Many common cases have been implemented using the naming
+    scheme movXXX where "XXX" is the function that will be applied.
+    For example, the moving average over a dataset is movmean.
+    New moving window functions:
+   
+    movfun   movslice
+    movmad   movmax   movmean   movmedian   movmin   movprod
+    movstd   movsum   movvar
 
- ** The bareword "import" is now recognized in scripts and functions.
-    However, the functionality to import functions and classes from
-    other namespaces into the local scope has not yet been implemented.
-    Attempting to use "import" will provoke an error message.
-
- ** hex2num and num2hex now work for integer and char types and num2hex
-    may optionally return a cell array of strings instead of a character
-    array.  If given a cell array of strings, hex2num now returns a
-    numeric array of the same size as the input cell array.  Previously,
-    hex2num would accept a cell array of strings of arbitrary dimension
-    but would always return a column vector.
+ ** The functions issymmetric and ishermitian accept an option "nonskew"
+    or "skew" to calculate the symmetric or skew-symmetric property
+    of a matrix.  Performance has also been increased.
 
- ** New special functions cosint, sinint, and gammaincinv have been added.
+ ** The function isdefinite now returns true or false rather than
+    -1, 0, 1.  To test for a positive semi-definite matrix (old output
+    of 0) check whether the following two conditions hold:
 
- ** Special functions in Octave have been rewritten for larger input
-    domains, better accuracy, and additional options.
-    * gammainc now accepts negative real values for X.
-    * improved accuracy for gammainc, betainc, betaincinv, expint.
-    * gammainc has new options "scaledlower" and "scaledupper".
-    * betainc, betaincinv have new option "upper".
+      isdefinite (A) => 0
+      isdefinite (A + 5*TOL, TOL) => 1
 
- ** The "names" option used in regular expressions now returns a struct
-    array, rather than a struct with a cell array for each field.  This
-    change was made for Matlab compatibility.
+ ** The issorted function now uses a direction option of "ascend" or
+    "descend" to make it compatible with both the sort function and
+    with Matlab.  Change all uses of "ascending" and "descending" in
+    existing code to the new options.
 
- ** The quadcc function now uses both absolute tolerance and relative
-    tolerance to determine the stopping criteria for an integration.
-    To be compatible with other quadXXX functions, such as quadgk, the
-    calling syntax has changed to
+ ** The strncmp and strncmpi functions now return true if the two input
+    strings match, even though the number of characters specified by N
+    exceeds the string length.  This behavior more closely matches
+    common sense and is Matlab compatible.  Example:
+
+      Octave 5.0 : strncmp ("abc", "abc", 100) => true
+      Previously : strncmp ("abc", "abc", 100) => false
 
-      quadcc (f, a, b, [AbsTol, [RelTol]])
-
-    To update existing code, change instances of RelTol to [0, RelTol].
-
-      quadcc (f, a, b, tol) => quadcc (f, a, b, [0, tol])
+ ** The intmax, intmin, and flintmax functions now accept a variable
+    as input.  This supports a common programming usage which is to
+    query the range of an existing variable.  Existing code can be
+    simplified by removing the call to "class" that was previously
+    required.  Example:
 
-    A warning that a single tolerance input is now interpreted as an
-    absolute tolerance will be issued in Octave versions 4.4 and 5,
-    after which it will be removed.  The warning has ID
-    "Octave:quadcc:RelTol-conversion" and can be disabled with
+                   x = int8 (3);
+      Octave 5.0 : range = [ intmin(x), intmax(x) ]
+      Previously : range = [ intmin(class(x)), intmax(class(x)) ]
 
-      warning ("off", "Octave:quadcc:RelTol-conversion")
-
- ** The qr function now returns a standard factorization unless
-    explicitly instructed to perform an economy factorization by using a
-    final argument of 0.
+ ** The ranks function has been recoded for performance and is now 25X
+    faster.  In addition, it now supports a third argument that
+    specifies how to resolve the ranking of tie values.
 
- ** The Qt graphics toolkit now supports offscreen printing without osmesa
-    if Octave was built with Qt >= 5.1.
-
- ** The built-in pager for display of large data is now disabled by
-    default.  To re-enable it for every Octave session add the following
-    to your .octaverc file:
-
-      more on;
+ ** The fsolve function has been tweaked to use larger step sizes when
+    calculating the Jacobian of a function with finite differences.
+    This leads to faster convergence.  The default solver options have
+    also changed to be Matlab compatible.  This *may* result in existing
+    code producing different results.
 
- ** The FLTK toolkit is no longer prioritized for development.  The
-    number of Octave Maintainers is too small to support three different
-    graphic toolkits.  New development will target the Qt toolkit.
-    While no longer prioritized, the FLTK toolkit is not deprecated and
-    there is no schedule for its removal.
-
- ** The graphic object property "PickableParts" has been implemented
-    which controls whether an object can accept mouse clicks.
+          Option     |  New Default   |  Old Default
+      ------------------------------------------------
+        FinDiffType  |   "forward"    |   "central"
+        MaxFunEvals  | 100*length(x0) |     Inf
+        TolFun       |     1e-6       |     1e-7
+        TolX         |     1e-6       |     1e-7
+        Updating     |     "off"      |     "on"
 
- ** The graphic object property "Interruptible" has been fully
-    implemented which controls whether a running callback function can
-    be interrupted by another callback function.
+ ** The fminsearch function has changed default solver options for
+    Matlab compatibility.  The accuracy option TolFun is now 1e-4 rather
+    than 1e-7.  This *may* result in existing code producing different
+    results.
 
- ** The graphic object property "HitTest" has been updated to be fully
-    compatible with Matlab.
+ ** The fminbnd function has changed defaults for Matlab compatibility.
+    This *may* result in existing code producing different results.
 
- ** Text objects now implement the properties "BackgroundColor",
-    "EdgeColor", "LineStyle", "LineWidth", and "Margin".
-
- ** An initial implementation of alpha transparency has been made for
-    patch and surface objects.  Printing to svg and pdf is supported.
+          Option     |  New Default   |  Old Default
+      ------------------------------------------------
+        MaxFunEvals  |      500       |     Inf
+        MaxIter      |      500       |     Inf
+        TolX         |     1e-4       |     1e-8
 
- ** ishandle now returns true for both graphics handle objects and
-    Java objects.  The latter change was made for Matlab compatibility.
-    Use ishghandle or isgraphics if it is important not to include Java
-    objects.
-
- ** The pkg command now accepts a URL as an argument, allowing a valid
-    Octave package to be installed from any remote host with one command,
-    for example
-
-      pkg install https://example.org/download/example-package.tar.gz
+ ** The fminunc function has changed defaults for Matlab compatibility.
+    This *may* result in existing code producing different results.
 
- ** The following statistical functions have been moved from core
-    Octave to the statistics package available from Octave Forge.
+          Option     |  New Default   |  Old Default
+      ------------------------------------------------
+        FinDiffType  |   "forward"    |   "central"
+        MaxFunEvals  | 100*length(x0) |     Inf
+        TolX         |     1e-6       |     1e-7
+        TolFun       |     1e-6       |     1e-7
 
-    BASE
-      cloglog
-      logit
-      prctile
-      probit
-      qqplot
-      table  (renamed to crosstab)
+ ** Using "clear" with no arguments now removes only local variables
+    from the current workspace.  Global variables will no longer be
+    visible, but they continue to exist in the global workspace and
+    possibly other workspaces such as the base workspace.
+    This change was made for Matlab compatibility.
 
-    DISTRIBUTIONS
-      betacdf
-      betainv
-      betapdf
-      betarnd
-      binocdf
-      binoinv
-      binopdf
-      binornd
-      cauchy_cdf
-      cauchy_inv
-      cauchy_pdf
-      cauchy_rnd
-      chi2cdf
-      chi2inv
-      chi2pdf
-      chi2rnd
-      expcdf
-      expinv
-      exppdf
-      exprnd
-      fcdf
-      finv
-      fpdf
-      frnd
-      gamcdf
-      gaminv
-      gampdf
-      gamrnd
-      geocdf
-      geoinv
-      geopdf
-      geornd
-      hygecdf
-      hygeinv
-      hygepdf
-      hygernd
-      kolmogorov_smirnov_cdf
-      laplace_cdf
-      laplace_inv
-      laplace_pdf
-      laplace_rnd
-      logistic_cdf
-      logistic_inv
-      logistic_pdf
-      logistic_rnd
-      logncdf
-      logninv
-      lognpdf
-      lognrnd
-      nbincdf
-      nbininv
-      nbinpdf
-      nbinrnd
-      normcdf
-      norminv
-      normpdf
-      normrnd
-      poisscdf
-      poissinv
-      poisspdf
-      poissrnd
-      stdnormal_cdf
-      stdnormal_inv
-      stdnormal_pdf
-      stdnormal_rnd
-      tcdf
-      tinv
-      tpdf
-      trnd
-      unidcdf
-      unidinv
-      unidpdf
-      unidrnd
-      unifcdf
-      unifinv
-      unifpdf
-      unifrnd
-      wblcdf
-      wblinv
-      wblpdf
-      wblrnd
-      wienrnd
+ ** The Octave plotting system now supports high resolution screens,
+    i.e, those with greater than 96 DPI which are referred to as
+    HiDPI/Retina monitors.
+
+ ** Figure graphic objects have a new property "Number" which is
+    read-only and will return the handle (number) of the figure.
+    However, if the property "IntegerHandle" has been set to "off" then
+    the property will return an empty matrix ([]).
+
+ ** Patch and surface graphic objects now use the "FaceNormals" property
+    for flat lighting.
+
+ ** "FaceNormals" and "VertexNormals" for patch and surface graphic
+    objects are now calculated only when necessary to improve graphics
+    performance.  In order for any normals to be calculated the
+    "FaceLighting" property must be set to "flat" (FaceNormals) or
+    "gouraud" (VertexNormals), AND a light object must be present in the
+    axes.
+
+ ** The "Margin" property of text() objects has a new default of 3
+    rather than 2.  This change was made for Matlab compatibility.
+
+ ** Printing to raster formats (bitmaps like PNG or JPEG) now uses an
+    OpenGL-based method by default.  The print options "-opengl"
+    (raster) and "-painters" (vector) have been added ("qt" toolkit
+    only).  The figure property "renderer" specifies which renderer to
+    use.  When the property "renderermode" is "auto" Octave will select
+    -opengl for a raster output format and -painters for a vector output
+    format.
+
+ ** A new print option "-RGBImage" has been added which captures the
+    pixels of a figure as an image.  This is similar to screen capture
+    tools, except that print formatting options can be used to, for
+    example, change the resolution or display the image in black and
+    white.
+
+ ** Two new print options for page-based formats (PDF, PostScript) have
+    been added.  The "-fillpage" option will stretch the plot to occupy
+    the entire page with 0.25 inch margins all around.  The "-bestfit"
+    option will expand the plot to take up as much room as possible on
+    the page without distorting the original aspect ratio of the plot.
+
+ ** Printing using the -dtiff output device will now create compressed
+    images using LZW compression.  This change was made for Matlab
+    compatibility.  To produce uncompressed images use the -dtiffn
+    device.
+
+ ** A new printing device is available, -ddumb, which produces ASCII art
+    for plots.  This device is only available with the gnuplot toolkit.
 
-    MODELS
-      logistic_regression
+ ** 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.
+
+ ** It is now possible to use files and folders containing Unicode
+    characters in Windows.
+
+ ** The FFTW library is now required to perform FFT calculations.
+    The FFTPACK sources have been removed from Octave.
 
-    TESTS
-      anova
-      bartlett_test
-      chisquare_test_homogeneity
-      chisquare_test_independence
-      cor_test
-      f_test_regression
-      hotelling_test
-      hotelling_test_2
-      kolmogorov_smirnov_test
-      kolmogorov_smirnov_test_2
-      kruskal_wallis_test
-      manova
-      mcnemar_test
-      prop_test_2
-      run_test
-      sign_test
-      t_test
-      t_test_2
-      t_test_regression
-      u_test
-      var_test
-      welch_test
-      wilcoxon_test
-      z_test
-      z_test_2
+ ** The OSMesa library is no longer used.  To print invisible figures
+    when using OpenGL graphics, the Qt QOFFSCREENSURFACE feature must be
+    available and you must use the qt graphics toolkit.
 
- ** The following image functions have been moved from core Octave to
-    the image package available from Octave Forge.
+ ** The str2func function no longer accepts a second "global" argument.
+    This argument was typically used to allow functions that accept
+    function names as arguments to avoid conflicts with subfunctions or
+    nested functions.  Instead, it's best to avoid this situation
+    entirely and require users to pass function handles rather than
+    function names.
 
-      ntsc2rgb
-      rgb2ntsc
+ ** The path handling functions no longer perform variable or brace
+    expansion on path elements and Octave's load-path is no longer
+    subject to these expansions.
 
- ** Other new functions added in 4.4:
+ ** New functions added in 5.0:
 
-      bounds
-      camlookat
-      camorbit
-      campos
-      camroll
-      camtarget
-      camup
-      camva
-      camzoom
-      corrcoef
-      cosint
-      decic
-      erase
-      gammaincinv
-      getframe
-      groot
-      gsvd
-      hgtransform
-      humps
-      integral
-      integral2
-      integral3
-      isgraphics
-      isstring
-      mad
-      ode15i
-      ode15s
-      openvar
-      quad2d
-      repelem
-      rgb2gray
-      rticks
-      sinint
-      tfqmr
-      thetaticks
-      vecnorm
-      winqueryreg
-      xticklabels
-      xticks
-      yticklabels
-      yticks
-      zticklabels
-      zticks
+      clearvars
+      isfile
+      isfolder
+      matlab.lang.makeUniqueStrings
+      matlab.lang.makeValidName
+      movegui
+      movfun
+      movie
+      movmad
+      movmax
+      movmean
+      movmedian
+      movmin
+      movprod
+      movslice
+      movstd
+      movsum
+      movvar
+      openfig
+      ordeig
+      savefig
+      uitable
 
- ** Deprecated functions.
+ ** Legacy functions.
 
-    The following functions have been deprecated in Octave 4.4 and will
-    be removed from Octave 6 (or whatever version is the second major
-    release after 4.4):
+    The following functions have been declared legacy functions which
+    means they are obsolete and should not be used in any new code.
+    Unlike deprecated functions, however, their removal from Octave has
+    not yet been scheduled.
 
       Function             | Replacement
       ---------------------|------------------
-      chop                 | sprintf for visual results
-      desktop              | isguirunning
-      tmpnam               | tempname
-      toascii              | double
-      java2mat             | __java2mat__
-
-
- ** The following functions were deprecated in Octave 4.0 and have been
-    removed from Octave 4.4.
-
-      allow_noninteger_range_as_index
-      bicubic
-      delaunay3
-      do_braindead_shortcircuit_evaluation
-      dump_prefs
-      find_dir_in_path
-      finite
-      fmod
-      fnmatch
-      gmap40
-      loadaudio
-      luinc
-      mouse_wheel_zoom
-      nfields
-      octave_tmp_file_name
-      playaudio
-      saveaudio
-      setaudio
-      syl
-      usage
-
- ** The "Octave:undefined-return-values" warning ID is obsolete.  Octave
-    now throws an error for any attempts to assign undefined values that
-    might be returned from functions.
-
- ** Deprecated graphics properties.
-
-    The following properties or allowed corresponding values have been
-    deprecated in Octave 4.4 and will be removed from Octave 6 (or whatever
-    version is the second major release after 4.4):
-
-      Object               | Property                | Value
-      ---------------------|-------------------------|-------------------
-      figure               | doublebuffer            |
-                           | mincolormap             |
-                           | wvisual                 |
-                           | wvisualmode             |
-                           | xdisplay                |
-                           | xvisual                 |
-                           | xvisualmode             |
-      axes                 | drawmode                |
-      annotation           | edgecolor ("rectangle") |
-      text                 | fontweight              | "demi" and "light"
-      uicontrol            | fontweight              | "demi" and "light"
-      uipanel              | fontweight              | "demi" and "light"
-      uibuttongroup        | fontweight              | "demi" and "light"
-
- ** The rectangle and ellipse annotation property "edgecolor" has been
-    deprecated and will be removed from Octave 6 (or whatever version
-    is the second major release after 4.4).  Use the property "color"
-    instead.
-
- ** The header file oct-alloc.h has been removed along with the macros
-    that it defined (DECLARE_OCTAVE_ALLOCATOR, DEFINE_OCTAVE_ALLOCATOR,
-    and DEFINE_OCTAVE_ALLOCATOR2).
-
-
-Summary of bugs fixed for version 4.2.2 (2018-03-13):
-----------------------------------------------------
-
-Using the bug numbers listed below, find bug reports on the web using
-the URL https://savannah.gnu.org/bugs/?NNNNN
-
- ** make leftdiv work for scalar \ int-matrix (bug #51682)
-
- ** inputdlg.m: Avoid crash when prompt and defaults sizes differ (bug #53209)
-
- ** tie octave_classdef::numel method to "numel" user override method
-    (bug #46571)
-
- ** fix performance of Sparse fsolve for complex sparse matrices (bug #53140)
-
- ** fix performance of Sparse fsolve (bug #53140)
-
- ** octave.desktop.in: No repetition of Name in Comment field and start I10n
-    (bug #53078)
-
- ** don't create partially invalid graphic objects (bug #52904)
-
- ** test for incorrect regexprep on ARM platforms (bug #52810)
-
- ** fix incorrect regexprep on ARM platforms (bug #52810)
-
- ** correctly handle reading of characters >127 in scanf family (bug #52681)
-
- ** fix addpath for UNC paths on Windows (bug #51268)
-
- ** protect being-deleted objects on figure list from second deletion
-    (bug #52666)
-
- ** dlmwrite.m: Close fid if filename is only one char long (bug #52679)
-
- ** set gnuplot color data to half output range when autoscaling zero input
-    range (bug #52624)
-
- ** add polarplot() to the list of unimplemented functions (bug #52643)
-
- ** configure.ac: Fix test for Java version (bug #52617)
-
- ** for gnuplot toolkit, do not map TrueColor data to colormap size (bug #52599)
-
- ** make wheel scroll behave more consistently in pan mode (bug #52588)
-
- ** make gnuplot color have three components for interpolated edge color
-    (bug #52595)
-
- ** simplify gnuplot toolkit scripts for image/non-image data plots (bug #52589)
-
- ** fix concatenation of empty char matrices with other strings (bug #52542)
-
- ** build: Fix compiling OCTAVE_ARPACK_OK_2 Fortran code (bug #52425)
-
- ** trisurf.m, trimesh.m: Fix input validation (bug #48109)
-
- ** allow uncommenting in editor when line begins with whitespace (bug #52406)
-
- ** do not extend selection when indenting/commenting in editor (bug #45610)
-
- ** remove all delimiters from whitespace list in textscan function (bug #52479)
-
- ** calculate 1-norm of matrices to assess whether NaN or Inf are present
-    (bug #39000)
-
- ** prevent extra ampersand under KDE in cd-or-add-to-path dialog (bug #52423)
-
- ** plotyy.m: Fix error when using FUN2 argument (bug #48115)
-
- ** check ARPACK library for buggy behavior in configure (bug #52425)
-
- ** fix printing integer type images (bug #51558)
-
- ** fix segfault in delaunayn when Qhull memory is not properly cleared
-    (bug #52410)
-
- ** fix segfault with CHOLMOD library and empty matrices (bug #52365)
-
- ** tag global and persistent symbols as variables when parsing (bug #52363)
-
- ** properly restore the input stream pointer at end of textscan (bug #52116 et
-    al.)
-
- ** fix building with Qt4 for Windows (bug #52237)
-
- ** ensure numeric values are passed for the axes "clim" property (bug #52053)
-
- ** avoid abort on exit from GUI (bug #50664)
-
- ** correct auto limits on log axes with negative and zero values (bug #51861)
-
- ** fix warning in quadgk with zero size interval (bug #51867)
-
- ** sparse: correctly handle scalar column index (bug #51880)
-
- ** fix segfault in ichol under certain conditions (bug #51736)
-
- ** configure: ensure empty pkg-config results are actually empty (bug #51680)
-
- ** fix 'legend hide' for gnuplot (bug #50483)
-
- ** qqplot.m: Fix typo in input validation (bug #51458)
-
- ** add possible '\r' to smartindent regex exprepression (Bug #51279)
-
- ** make strncmp case sensitive again (bug #51384)
-
- ** fix possible infinite loop in normest1.m (bug #51241)
-
- ** also run unwind protect cleanup code on interrupt exceptions (bug #51209)
-
- ** fix crash when inverting complex matrices with NaNs (bug #51198)
-
- ** improve accuracy of residue for inputs with very different magnitudes
-    (bug #51148)
-
- ** publish.m: Fix corruption of results for some code inputs (bug #51178)
-
- ** residue.m: Remove code that filters out small return values (bug #34266, bug
-    #49291)
-
- ** avoid possible double free at interpreter exit (bug #51088)
-
- ** show stack trace for errors in command line and startup files (bug #49346)
-
- ** interp1.m: Return NA for all columns which are out of bounds (bug #51030)
-
- ** use idx_type for dimensions instead of int (bug #50934)
-
- ** show stack trace for wrong type arg errors (bug #50894)
-
- ** let mouse selection of Qt figures update "currentfigure" (bug #50666)
-
- ** disable qscintilla editor drag and drop so parent will handle it (Bug
-    #50559)
-
- ** quadgk.m: Correct error messages which point to quadv (bug #50604)
-
- ** set version on AppUserModelId (Bug #50428)
-
- ** version-rcfile: Don't try to execute startup directory, only startup.m
-    (bug #50593)
-
- ** dlmread: Return empty matrix when requested range is outside data
-    (bug #50102)
-
- ** fix eigs for generalized nonsymmetric and shift-invert problems (bug #39573)
-
- ** fix eigs for the generalized eigenvalue problem (bug #50546)
-
- ** datetick.m: Fix uneven range bugs (bug #50493)
-
- ** datenum.m: Correct calculation for fractional leap years (bug #50508)
-
- ** datenum.m: Allow horizontal vectors of dates with fractional months
-    (bug #50508)
-
- ** datenum.m: Accept legal input of vectors with fractional months (bug #50508)
-
- ** fix the anchor position in the info text of the doc browser (bug #50422)
-
- ** fix order of legend labels with plotyy axes (bug #50497)
-
- ** correct hggroup plot legends for gnuplot toolkit, add legend demo 17 items
-    (bug #49341)
-
- ** for gnuplot graphics toolkit, show only one key entry for errorbars
-    (bug #49260)
-
- ** fix compilation of jit caused by cset d0562b3159c7 (bug #50398)
-
- ** remove inline keyword on file_stat destructor which breaks MacOS compilation
-    (bug #50234)
-
-Documentation bugs fixed:
-
- ** playblocking.m: Correct documentation about start and limits inputs
-    (bug #51217)
-
- ** fix eig output argument description (bug #50524)
-
- ** remove backslashes before double quotes in m-file docstrings (bug #52870)
-
- ** tweaks to use single quotes instead of double quotes (bug #52870)
-
- ** correct fieldname of returned struct in ver (bug #52845)
-
- ** cleanup @code example in Appendix on test functions (bug #52852)
-
- ** fixes for signal, image, audio, and OOP chapters (bug #52844)
-
- ** fix issues in geometry, polynomial, and interpolation chapters (bug #52835)
-
- ** fix TeX documentation for qp and clarify size of inputs (bug #52829)
-
- ** correct errors in Diagonal matrix chapter of manual (bug #52814)
-
- ** replace @math{1e^{XXX}} sequences with raw 1eXXX (bug #52827)
-
- ** use '...' rather than deprecated '\' for line continuation (bug #52828)
-
- ** make documentation Sec 26.1 more consistent and Sec 25.4 clearer
-    (bug #52685)
-
- ** documentation fixes for linspace, logspace, lookup (bug #52785)
-
- ** atan2d.m: Correct documentation to match atan docstring (bug #52786)
-
- ** small tweaks to fplot and surfnorm docstrings (bug #52761)
-
- ** rewrite documentation for Advanced Indexing (bug #52723)
-
- ** delete extra ']' in scanf docstring (bug #52742)
-
- ** fix mistaken use of space between function and '(' in documentation
-    (bug #52723)
-
- ** fix various inconsistencies in manual (bug #52712)
-
- ** fix typo in cset 8354b505ad6b (bug #52702)
-
- ** fix inconsistencies with char, strvcat, strread docstrings (bug #52702.
-
- ** explain Matlab compatibility of fopen modes (bug #52644)
-
- ** update documentation for keywords to include classdef statements
-    (bug #52591)
-
- ** fix documentation of third input to lsode() (bug #52664)
-
- ** clarify quiver/quiver3 documentation when a linestyle is given (bug #52608)
-
- ** new section about classdef classes with example (bug #44590)
-
- ** correct surface plot explanation of  meshgridded results of 1 input
-    (bug #52536)
-
- ** fix definition of Delaunay triangulation in docstrings (bug #52416)
-
- ** accumarray.m: Add '@' to function handles in docstring (bug #52418)
-
- ** update manual to explain \deg and \circ symbols (bug #52287)
-
- ** correct documentation for randg (bug #52118)
-
- ** add documentation about PCRE library regexp stack overflow (bug #51589)
-
- ** play.m: Correct documentation about start and limits inputs (bug #51217)
-
- ** redo docstring for qz (bug #50846)
-
- ** describe optional install dependencies PortAudio and SUNDIALS (bug #50513)
-
- ** update CITATION date, version, and permalink to manual (bug #47058)
-
-
-Summary of bugs fixed for version 4.2.1 (2017-02-22):
-----------------------------------------------------
-
-Using the bug numbers listed below, find bug reports on the web using
-the URL https://savannah.gnu.org/bugs/?NNNNN
-
- ** guarantee returning std::string from tilde_expand functions (bug #50234)
-
- ** workaround segfault in file_stat (bug #50234)
-
- ** genpropdoc.m: document more graphics properties (bug #50337)
-
- ** always fork and exec when starting the gui (bug #49609)
-
- ** print.m: fix regression with -append option (bug #50318)
-
- ** don't display legend, colorbar, and annotation axes coordinates
-    (bug #50272)
-
- ** qp.m: Fix regression with incorrect vector dimensions (bug #50067)
-
- ** prevent infinite loop in global documentation search (bug #50177)
-
- ** connect execute command signal in editor constructor (bug #50171)
-
- ** connect editors execute command signal to the required slot (bug #50171)
-
- ** check if input is class method before declaring it unimplemented
-    (patch #9238) (bug #49694)
-
- ** workaround segfault when an error occurs while printing (bug #49779)
-
- ** axis.m: Do not set plotboxaspectratio to 0 (bug #49755)
-
- ** don't rethrow exception in destructor (bug #49304)
-
- ** rethrow octave::exit_exception (bug #49304)
-
- ** update appdata.xml to follow conventions (bug #49952)
-
- ** mexproto.h (mxAssert, mxAssertS): ensure operator precedence (bug #50050)
-
- ** calculate error in solution for ode solvers correctly (bug #49950)
-
- ** use GetModuleFileName for getting octave path in windows (bug #48671)
-
- ** use C++ updaters for labels color (bug #49980)
-
- ** distinguish elements vs. bytes in fread (bug #49699)
-
- ** move frame2im and im2frame to image/ directory (bug #49939)
-
- ** fix undefined return argument for more than 2 outputs from ode solver
-    (bug #49890)
-
- ** fix inv for hermitian matrices (bug #49904)
-
- ** fix gzip for certain types of gzip files (bug #49760)
-
- ** fix typo in liboctave version info (bug #49860)
-
- ** initialize ODE Event function with start time (bug #49846)
-
- ** allow configure test to succeed without implicit fcn decls (bug #49782)
-
- ** allow external docstrings from .oct files to be found again (bug #49687)
-
- ** don't require semicolon between property list elements (bug #49819)
-
- ** display.m: Correctly display output for non-class objects
-    (bug #49753, #49794)
-
- ** don't run publish.tst unless OSMESA or gnuplot are available (bug #49767)
-
- ** find help for function aliases again (bug #49687)
-
- ** legend.m: backport cset 7184b4516a68 (bug #49675)
-
- ** preserve lasterror info on rethrow (bug #49642)
-
- ** norm: fix error in input argument validation leading to segfault
-    (bug #49634)
-
-Documentation bugs fixed:
-
- ** overhaul Java interface description (bug #50299)
-
- ** add documentation for hex and binary prefix and _ separator
-    (bug #50305, #50334)
-
- ** fix build of docs broken in sub2ind (bug #50348)
-
- ** version.m: document that "-release" returns an empty string (bug #50294)
-
- ** remove trailing "\n\" from sleep and usleep docstrings (bug #50301)
-
- ** expand documentation for cast() (bug #50201)
-
- ** correct two entries in Table 34.1 (bug #50203)
-
- ** oop.txi: Improve table formatting (bug #50203)
-
- ** fix '##' in middle of docstring/comment lines (bug #50145)
-
- ** reword documentation about subplots in 15.2.4 (bug #50148)
-
- ** update unimplemented list of functions and where to find them
-    (bug #50098)
-
- ** compare_plot_demos: fix HTML syntax, simplify output, remove
-    external deps (bug #49709)
-
- ** add more depth to explanation of '~' function argument (bug #49444)
-
- ** correct documentation for javaclasspath file (bug #49873)
-
- ** small fixes to docstrings (bug #49733)
-
- ** change text describing demo plots to reflect new ColorOrder (bug #49288)
-
-Other bugs fixed:
-
- ** add missing classdef test files (bug #49819)
-
-
-Summary of important user-visible changes for version 4.2 (2016-11-13):
-----------------------------------------------------------------------
-
- ** The parser has been extended to accept, but ignore, underscore
-    characters in numbers.  This facilitates writing more legible code
-    by using '_' as a thousands separator or to group nibbles into bytes
-    in hex constants.
-
-    Examples: 1_000_000 == 1e6  or  0xDE_AD_BE_EF
-
- ** The parser has been extended to understand binary numbers which
-    begin with the prefix '0b' or '0B'.  The value returned is Octave's
-    default numeric class of double, not at unsigned integer class.
-    Therefore numbers greater than flintmax, i.e., 2^53, will lose some
-    precision.
-
-    Examples: 0b101 == 5  or  0B1100_0001 == 0xC1
-
- ** gnuplot 4.4 is now the minimum version supported by Octave.
-
- ** The default set of colors used to plot lines has been updated to be
-    compatible with Matlab's new default color scheme.  The line plot
-    color scheme can be set with the axes property "ColorOrder".
-
- ** The default colormap is now set to "viridis" which is also the
-    default colormap in matplotlib.  This new colormap fixes some of the
-    main issues with the old default colormap "jet" such as its bad
-    "luminance profile" and is also more similar to Matlab's new default
-    colormap "parula".
-
- ** The colormap function no longer supports the input argument "list"
-    to show built-in colormaps.  Use "help colormap" to find the
-    built-in colormaps.
-
- ** The graphics command "hold on" now ensures that each new plot added
-    to an existing plot has a different color or linestyle according to
-    the "ColorOrder" and/or "LineStyleOrder" properties.  This is
-    equivalent to the old command "hold all" and was made for Matlab
-    compatibility.  Existing code *may* produce differently colored
-    plots if it did not specify the color for a plot and relied on each
-    new plot having the default first color in the "ColorOrder"
-    property.
-
- ** When starting, Octave now looks in the function path for a file
-    startup.m and executes any commands found there.  This change was
-    made to accommodate Matlab users.  Octave has it's own configuration
-    system based on the file .octaverc which is preferred.
-
- ** Octal ('\NNN') and hex ('\xNN') escape sequences in single quoted
-    strings are now interpreted by the function do_string_escapes().
-    The *printf family of functions now supports octal and hex escape
-    sequences in single-quoted strings for Matlab compatibility.
-
- ** Special octal and hex escape sequences for the pattern and
-    replacement strings in regular expressions are now interpreted for
-    Matlab compatibility.
-
-    octal: '\oNNN' or '\o{NNN}'
-    hex  : '\xNN'  or '\x{NN}'
-
- ** Unknown escape sequences in the replacement string for regexprep are
-    now substituted with their unescaped version and no warning is
-    emitted.  This change was made for Matlab compatibility.
-
-    Example: regexprep ('a', 'a', 'x\yz')
-             => 'xyz'
-
- ** mkfifo now interprets the MODE argument as an octal, not decimal,
-    integer.  This is consistent with the equivalent shell command.
-
- ** linspace now returns an empty matrix if the number of requested
-    points is 0 or a negative number.  This change was made to be
-    compatible with Matlab releases newer than 2011.  In addition,
-    Octave no longer supports matrix inputs for A or B.
-
- ** The cov function now returns the complex conjugate of the result
-    from previous versions of Octave.  This change was made for
-    compatibility with Matlab.
-
- ** condest now works with a normest1 compatible syntax.
-
- ** The griddata function no longer plots the interpolated mesh if no
-    output argument is requested, instead the vector or array of
-    interpolated values is always returned for Matlab compatibility.
-
- ** The new function "light" and the corresponding graphics object
-    provide light and shadow effects for patch and surface objects.
-
- ** The surfnorm function now returns unnormalized (magnitude != 1)
-    normal vectors for compatibility with Matlab.
-
- ** The normal vectors returned from isonormals have been reversed to
-    point towards smaller values for compatibility with Matlab.
-
- ** The quadl function now uses an absolute, rather than relative,
-    tolerance for Matlab compatibility.  The default tolerance is 1e-6
-    which may result in lower precision results than previous versions
-    of Octave which used eps as the relative tolerance.  The quadl
-    function has also been extended to return a second output with the
-    total number of function evaluations.
-
- ** The textscan function is now built-in and is much faster and much
-    more Matlab-compatible than the previous m-file version.
-
- ** Dialog boxes--errordlg, helpdlg, inputdlg, listdlg, msgbox,
-    questdlg, and warndlg--now exclusively use Qt for rendering.
-    Java based versions have been removed.
-
- ** The axes properties "TitleFontSizeMultiplier" and "TitleFontWeight"
-    are now implemented which control the default appearance of text
-    created with title().
-    The axes property "LabelFontSizeMultiplier" is now implemented
-    which controls the default appearance of text created with
-    xlabel(), ylabel(), or zlabel().
-
- ** The graphics property "box" for axes now defaults to "off".
-    To obtain equivalent plots to previous versions of Octave use
-      set (0, "DefaultAxesBox", "on");
-    in your .octaverc file.
-
- ** The graphics property "boxstyle" has been implemented.  The default
-    is "back" which draws only the back planes in a 3-D view.  If the
-    option is "full" then all planes are drawn.
-
- ** The graphics property "erasemode" has been hidden, and will
-    eventually be removed.  This property has also been removed
-    from Matlab, and was never implemented in Octave.
-
- ** The graphics property "graphicssmoothing" for figures now controls
-    whether anti-aliasing will be used for lines.  The default is "on".
-
- ** The value "zero" for the axes properties "xaxislocation" and
-    "yaxislocation" has been deprecated and will be removed from
-    Octave 5.  Use "origin" instead.
-
- ** The publish function allows easy publication of Octave script files
-    in HTML or other formats, including figures and output created by
-    this script.  It comes with its counterpart grabcode, which lets one
-    literally grab the HTML published code from a remote website, for
-    example.
-
- ** The value of the MEX variable TrapFlag now defaults to 0, which will
-    cause Octave to abort execution of a MEX file and return to the
-    prompt if an error is encountered in mexCallMATLAB.
-
- ** The MEX API now includes the function mexCallMATLABWithTrap.  This
-    function will not abort if an error occurs during mexCallMATLAB, but
-    instead will return execution to the MEX function for error
-    handling.
-
- ** The MEX API functions for input validation that begin with "mxIs"
-    (e.g., mxIsDouble, mxIsEmpty, etc.) now return type bool rather than
-    type int.
-
- ** The functions mxAssert and mxAssertS for checking assertions have
-    been added.  In order to avoid a performance penalty they are only
-    compiled in to debug versions of a MEX file, i.e., that are produced
-    when the '-g' option is given to mex or mkoctfile.
-
- ** Other new MEX API functions include mexEvalStringWithTrap,
-    mxIsScalar, mxCreateUninitNumericArray, mxCreateUninitNumericMatrix.
-
- ** Other new functions added in 4.2:
-
-      audioformats
-      camlight
-      condeig
-      deg2rad
-      dialog
-      evalc
-      hash
-      im2double
-      isocaps
-      lighting
-      localfunctions
-      material
-      normest1
-      ode23
-      ode45
-      odeget
-      odeplot
-      odeset
-      padecoef
-      profexport
-      psi
-      rad2deg
-      reducepatch
-      reducevolume
-      smooth3
-      uibuttongroup
+      findstr              | strfind
+      flipdim              | flip
+      isdir                | isfolder or dir_in_loadpath
+      isequalwithequalnans | isequaln
+      isstr                | ischar
+      setstr               | char
+      strmatch             | strncmp or strcmp
+      strread              | textscan
+      textread             | textscan
 
  ** Deprecated functions.
 
-    The following functions have been deprecated in Octave 4.2 and will
-    be removed from Octave 5 (or whatever version is the second major
-    release after 4.2):
+    The following functions have been deprecated in Octave 5.0 and will
+    be removed from Octave 7 (or whatever version is the second major
+    release after 5.0):
+
+      Function             | Replacement
+      ---------------------|------------------
+                           |
+
+ ** The following functions were deprecated in Octave 4.2 and have been
+    removed from Octave 5.0.
 
       Function             | Replacement
       ---------------------|------------------
@@ -970,381 +254,39 @@
       wavread              | audioread
       wavwrite             | audiowrite
 
- ** The following functions were deprecated in Octave 3.8 and have been
-    removed from Octave 4.2.
-
-      default_save_options    java_new
-      gen_doc_cache           java_unsigned_conversion
-      interp1q                javafields
-      isequalwithequalnans    javamethods
-      java_convert_matrix     re_read_readline_init_file
-      java_debug              read_readline_init_file
-      java_invoke             saving_history
-
- ** The global error_state variable in Octave's C++ API has been
-    deprecated and will be removed in a future version.  Now the error
-    and print_usage functions throw an exception
-    (octave::execution_exception) after displaying the error message.
-    This makes the error and print_usage functions in C++ work more like
-    the corresponding functions in the scripting language.
-
- ** The default error handlers in liboctave have been updated to use
-    exceptions.  After displaying an error message they no longer return
-    control to the calling program.  The error handler function can be
-    customized through the global variables
-    "current_liboctave_error_handler" and
-    "current_liboctave_error_with_id_handler".  If a programmer has
-    installed their own custom error handling routines when directly
-    linking with liboctave then these must be updated to throw an
-    exception and not return to the calling program.
-
- ** The system for common errors and warnings has been renamed from
-    gripe_XXX to either err_XXX if error is called or warn_XXX if
-    warning is called.  The gripe_XXX functions are deprecated and will
-    be removed in version 5.
-
- ** New configure option, --enable-address-sanitizer-flags, to build
-    Octave with memory allocator checks (similar to those in valgrind)
-    built in.
-
-Summary of important user-visible changes for version 4.0 (2015-05-23):
-----------------------------------------------------------------------
+ ** Deprecated graphics properties.
 
- ** A graphical user interface is now the default when running Octave
-    interactively.  The start-up option --no-gui will run the familiar
-    command line interface, and still allows use of the GUI dialogs and
-    qt plotting toolkit.  The option --no-gui-libs runs a minimalist
-    command line interface that does not link with the Qt libraries and
-    uses the fltk toolkit for plotting.
-
- ** Octave now uses OpenGL graphics with Qt widgets by default.  If
-    OpenGL libraries are not available when Octave is built, gnuplot is
-    used.  You may choose to use the fltk or gnuplot toolkit for
-    graphics by executing the command
-
-      graphics_toolkit ("fltk")
-        OR
-      graphics_toolkit ("gnuplot")
-
-    Adding such a command to your ~/.octaverc file will set the default
-    for each session.
-
- ** A new syntax for object oriented programming termed classdef has
-    been introduced.  See the manual for more extensive documentation of
-    the classdef interface.
-
-    New keywords:
-
-      classdef      endclassdef
-      enumeration   endenumeration
-      events        endevents
-      methods       endmethods
-      properties    endproperties
-
- ** New audio functions and classes:
-
-      audiodevinfo  audioread      sound
-      audioinfo     audiorecorder  soundsc
-      audioplayer   audiowrite
-
- ** Other new classes in Octave 4.0:
-
-      audioplayer    inputParser
-      audiorecorder
-
- ** Optional stricter Matlab compatibility for ranges, diagonal
-    matrices, and permutation matrices.
-
-    Octave has internal optimizations which use space-efficient storage
-    for the three data types above.  Three new functions have been added
-    which control whether the optimizations are used (default), or
-    whether the data types are stored as full matrices.
-
-    disable_range   disable_diagonal_matrix   disable_permutation_matrix
+    The following properties or allowed corresponding values have been
+    deprecated in Octave 5.0 and will be removed from Octave 7 (or
+    whatever version is the second major release after 5.0):
 
-    All three optimizations are disabled if Octave is started with the
-    --braindead command line option.
-
- ** The preference
-
-      do_braindead_shortcircuit_evaluation
-
-    is now enabled by default.
-
- ** The preference
-
-      allow_noninteger_range_as_index
-
-    is now enabled by default and the warning ID
-
-      Octave:noninteger-range-as-index
-
-    is now set to "on" by default instead of "error" by default and "on"
-    for --traditional.
-
- ** The "backtrace" warning option is now enabled by default.  This
-    change was made for Matlab compatibility.
-
- ** For compatibility with Matlab, the "ismatrix (x)" function now only
-    checks the dimension of "x".  The old behavior of "ismatrix" is
-    obtained by "isnumeric (x) || islogical (x) || ischar (x)".
-
- ** The nextpow2 function behavior has been changed for vector inputs.
-    Instead of computing `nextpow2 (length (x))', it will now compute
-    nextpow2 for each element of the input.  This change is Matlab
-    compatible, and also prevents bugs for "vectors" of length 1.
-
- ** polyeig now returns a row vector of eigenvalues rather than a matrix
-    with the eigenvalues on the diagonal.  This change was made for
-    Matlab compatibility.
-
- ** Interpolation function changes for Matlab compatibility
-
-    The interpolation method 'cubic' is now equivalent to 'pchip' for
-    interp1, interp2, and interp3.  Previously, 'cubic' was equivalent
-    to 'spline' for interp2.  This may produce different results as
-    'spline' has continuous 1st and 2nd derivatives while 'pchip' only
-    has a continuous 1st derivative.  The methods 'next' and 'previous'
-    have been added to interp1 for compatibility.
-
- ** The delaunay function has been extended to accept 3-D inputs for
-    Matlab compatibility.  The delaunay function no longer plots the
-    triangulation if no output argument is requested, instead, the
-    triangulation is always returned.  The delaunay3 function which
-    handles 3-D inputs has been deprecated in favor of delaunay.
-
- ** The trigonometric functions asin and acos return different phase
-    values from previous versions of Octave when the input is outside
-    the principal branch ([-1, 1]).  If the real portion of the input is
-    greater than 1 then the limit from below is taken.  If the real
-    portion is less than 1 then the limit from above is taken.  This
-    criteria is consistent with several other numerical analysis
-    software packages.
-
- ** The hyperbolic function acosh now returns values with a phase in the
-    range [-pi/2, +pi/2].  Previously Octave returned values in the
-    range [0, pi].  This is consistent with several other numerical
-    analysis software packages.
-
- ** strfind changes when using empty pattern ("") for Matlab
-    compatibility
-
-    strfind now returns an empty array when the pattern itself is empty.
-    In previous versions of Octave, strfind matched at every character
-    location when the pattern was empty.
-
-      NEW
-      strfind ("abc", "") => []
-      OLD
-      strfind ("abc", "") => [1, 2, 3, 4]
-
- ** Integer formats used in the printf family of functions now work for
-    64-bit integers and are more compatible with Matlab when printing
-    non-integer values.  Now instead of truncating, Octave will switch
-    the effective format to '%g' in the following circumstances:
-
-      * the value of an integer type (int8, uint32, etc.) value exceeds
-        the maximum for the format specifier.  For '%d', the limit is
-        intmax ('int64') and for '%u' it is intmax ('uint64').
-
-      * round(x) != x or the value is outside the range allowed by the
-        integer format specifier.
-
-    There is still one difference: Matlab switches to '%e' and Octave
-    switches to '%g'.
-
- ** The functions intersect, setdiff, setxor, and union now return a
-    column vector as output unless the input was a row vector.  This
-    change was made for Matlab compatibility.
+      Object               | Property                | Value
+      ---------------------|-------------------------|-------------------
+      text                 | fontangle               | "oblique"
+      uibuttongroup        | fontangle               | "oblique"
+      uicontrol            | fontangle               | "oblique"
+      uipanel              | fontangle               | "oblique"
+      uitable              | fontangle               | "oblique"
 
- ** The inpolygon function now returns true for points that are within
-    the polygon OR on it's edge.  This change was made for Matlab
-    compatibility.
-
- ** The archive family of functions (bzip2, gzip, zip, tar) and their
-    unpacking routines (bunzip2, gunzip, unzip, untar, unpack) have been
-    recoded.  Excepting unpack, the default is now to place files in the
-    same directory as the archive (on unpack) or as the original files
-    (on archiving).
-
- ** Qt and FLTK graphics toolkits now support offscreen rendering on
-    Linux.  In other words, print will work even when the figure
-    visibility is "off".
-
- ** Z-order stacking issues with patches, grid lines, and line object
-    plot markers for on screen display and printing have all been
-    resolved.  For 2-D plots the axis grid lines can be placed on top of
-    the plot with set (gca, "layer", "top").
-
- ** The patch graphic object has been overhauled.  It now produces
-    visual results equivalent to Matlab even for esoteric combinations
-    of faces/vertices/cdata.
-
- ** The polar() plot function now draws a circular theta axis and radial
-    rho axis rather than using a rectangular x/y axis.
-
- ** linkprop has been completely re-coded for performance and Matlab
-    compatibility.  It now returns a linkprop object which must be
-    stored in a variable for as long as the graphic objects should
-    remain linked.  To unlink properties use 'clear hlink' where hlink
-    is the variable containing the linkprop object.
-
- ** isprime has been extended to operate on negative and complex inputs.
-
- ** xor has been extended to accept more than two arguments in which
-    case it performs cumulative XOR reduction.
-
- ** The following functions now support N-dimensional arrays:
-
-      fliplr   flipud   rot90   rectint
-
- ** The new warning ID "Octave:data-file-in-path" replaces the three
-    previous separate warning IDs "Octave:fopen-file-in-path",
-    "Octave:load-file-in-path", and "Octave:md5sum-file-in-path".
-
- ** The warning ID Octave:singular-matrix-div has been replaced by
-    Octave:nearly-singular-matrix and Octave:singular-matrix.
-
- ** The warning ID Octave:matlab-incompatible has been replaced by
-    Octave:language-extension to better reflect its meaning.
-
- ** The warning ID Octave:broadcast has been removed.  Instead automatic
-    broadcasting will throw an Octave:language-extension warning.  This
-    warning ID is used for broadcasting as well as other features not
-    available in Matlab.
-
- ** Other new functions added in 4.0:
-
-      annotation
-      bandwidth
-      cubehelix
-      dir_in_loadpath
-      flip
-      frame2im
-      get_home_directory
-      hgload
-      hgsave
-      ichol
-      ilu
-      im2frame
-      isbanded
-      isdiag
-      isstudent
-      istril
-      istriu
-      javachk
-      jit_failcnt
-      linkaxes
-      lscov
-      metaclass
-      numfields
-      open
-      ordschur
-      pan
-      qmr
-      rotate
-      rotate3d
-      sylvester
-      unsetenv
-      validateattributes
-      zoom
-
- ** inline() scheduled for eventual deprecation by Matlab
+ ** The following properties or allowed corresponding values were
+    deprecated in Octave 4.2 and have been removed from Octave 5.0:
 
-    Functions created through the use of inline are scheduled for
-    deprecation by Matlab.  When this occurs Octave will continue to
-    support inline functions for an indeterminate amount of time before
-    also removing support.  All new code should use anonymous functions
-    in place of inline functions.
-
- ** Deprecated functions.
-
-    The following functions have been deprecated in Octave 4.0 and will
-    be removed from Octave 4.4 (or whatever version is the second major
-    release after 4.0):
-
-      Function             | Replacement
-      ---------------------|------------------
-      bicubic              | interp2
-      delaunay3            | delaunay
-      dump_prefs           | individual preference get/set routines
-      find_dir_in_path     | dir_in_loadpath
-      finite               | isfinite
-      fmod                 | rem
-      fnmatch              | glob or regexp
-      gmap40               | ----
-      loadaudio            | audioread
-      luinc                | ilu or ichol
-      mouse_wheel_zoom     | mousewheelzoom axes property
-      nfields              | numfields
-      octave_tmp_file_name | tempname
-      playaudio            | audioplayer
-      saveaudio            | audiowrite
-      syl                  | sylvester
-      usage                | print_usage
-
-      allow_noninteger_range_as_index
-      do_braindead_shortcircuit_evaluation
-      setaudio
-
- ** The following functions were deprecated in Octave 3.8 and will be
-    removed from Octave 4.2 (or whatever version is the second major
-    release after 3.8):
+      Object               | Property                | Value
+      ---------------------|-------------------------|-------------------
+      axes                 | xaxislocation           | "zero"
+                           | yaxislocation           | "zero"
+      hggroup              | erasemode               |
+      image                | erasemode               |
+      line                 | erasemode               |
+      patch                | erasemode               |
+      patch                | normalmode              |
+      surface              | erasemode               |
+      surface              | normalmode              |
+      text                 | erasemode               |
 
-      default_save_options    java_new
-      gen_doc_cache           java_unsigned_conversion
-      interp1q                javafields
-      isequalwithequalnans    javamethods
-      java_convert_matrix     re_read_readline_init_file
-      java_debug              read_readline_init_file
-      java_invoke             saving_history
-
- ** The following functions were deprecated in Octave 3.6 and have been
-    removed from Octave 4.0.
-
-      cut                polyderiv
-      cor                shell_cmd
-      corrcoef           studentize
-      __error_text__     sylvester_matrix
-      error_text
-
- ** The following keywords were deprecated in Octave 3.8 and have been
-    removed from Octave 4.0
-
-      static
-
- ** The following configuration variables were deprecated in Octave 3.8
-    and have been removed from Octave 4.0
-
-      CC_VERSION  (now GCC_VERSION)
-      CXX_VERSION (now GXX_VERSION)
-
- ** The internal function atan2 of the sparse matrix class has been
-    deprecated in Octave 4.0 and will be removed from Octave 4.4 (or
-    whatever version is the second major release after 4.0).  Use the
-    Fatan2 function with sparse inputs as a replacement.
-
- ** The internal class Octave_map was deprecated in Octave 3.8 and has
-    been removed from Octave 4.0.  Replacement classes are octave_map
-    (struct array) or octave_scalar_map for a single structure.
-
- ** Octave now has OpenMP enabled by default if the system provides a
-    working OpenMP implementation.  This allows oct-file modules to take
-    advantage of OpenMP if desired.  This can be disabled when building
-    Octave with the configure option --disable-openmp.
-
- ** Octave now automatically truncates intermediate calculations done
-    with floating point values to 64 bits.  Some hardware math
-    co-processors, such as the x87, maintain extra precision, but this
-    leads to disagreements in calculations when compared to reference
-    implementations in software using the IEEE standard for double
-    precision.  There was no measurable performance impact to this
-    change, but it may be disabled with the configure option
-    --disable-float-truncate.  MinGW and Cygwin platforms, as well as
-    GCC compilers >= 5.0 require this feature.  Non-x87 hardware, or
-    hardware using SSE options exclusively, can disable float truncation
-    if desired.
+ ** The C++ function is_keyword has been deprecated in favor of
+    iskeyword.  The old function will be removed two versions after 5.0.
 
 ---------------------------------------------------------
 
-See NEWS.3 for old news.
+See NEWS.4 for old news.
--- a/bootstrap.conf	Tue Dec 04 10:12:41 2018 -0800
+++ b/bootstrap.conf	Thu Dec 20 17:18:56 2018 -0500
@@ -59,9 +59,11 @@
   mkdir
   mkfifo
   mkostemp
+  mkostemps
   mktime
   nanosleep
   nproc
+  nstrftime
   open
   opendir
   pipe-posix
@@ -80,7 +82,6 @@
   stdio
   strdup-posix
   strerror
-  strftime
   strptime
   strsignal
   symlink
@@ -91,9 +92,26 @@
   tempname
   tmpfile
   uname
+  unicase/u8-tolower
+  unicase/u8-toupper
   uniconv/u8-conv-from-enc
   uniconv/u8-conv-to-enc
+  unictype/ctype-alnum
+  unictype/ctype-alpha
+  unictype/ctype-blank
+  unictype/ctype-cntrl
+  unictype/ctype-digit
+  unictype/ctype-graph
+  unictype/ctype-lower
+  unictype/ctype-print
+  unictype/ctype-punct
+  unictype/ctype-space
+  unictype/ctype-upper
+  unictype/ctype-xdigit
   unistd
+  unistr/u8-strmblen
+  unistr/u8-strmbtouc
+  unistr/u8-to-u32
   unlink
   unsetenv
   vasprintf
--- a/build-aux/get-source-mtime.sh	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/get-source-mtime.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -36,11 +36,21 @@
 
 srcdir="$1"
 
+## A user's ~/.hgrc may redefine or add default options to any hg subcommand,
+## potentially altering its behavior and possibly its standard output.  Always
+## run hg subcommands with configuration variables set to ensure that the
+## user's preferences do not influence the expected behavior.
+hg_safe ()
+{
+  cmd=$1; shift
+  hg --config alias.${cmd}=${cmd} --config defaults.${cmd}= ${cmd} "$@"
+}
+
 if [ x"$SOURCE_DATE_EPOCH" != x ]; then
   # Allow the source modification time to be overridden by SOURCE_DATE_EPOCH
   t=$SOURCE_DATE_EPOCH
 elif [ -d $srcdir/.hg ]; then
-  t=$( cd $srcdir && hg log --rev . --template '{date|hgdate}' )
+  t=$( cd $srcdir && hg_safe log --rev . --template '{date|hgdate}' )
   t=$( echo $t | $SED -n 's/^\([0-9]\+\) .*/\1/p' )
 elif [ -f $srcdir/HG-ID ]; then
   t=$( $PERL -e '@s = stat($ARGV[0]); print($s[9]) if @s;' $srcdir/HG-ID )
--- a/build-aux/mk-hg-id.sh	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/mk-hg-id.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -34,11 +34,21 @@
 hg_id=HG-ID
 move_if_change="$srcdir/build-aux/move-if-change"
 
+## A user's ~/.hgrc may redefine or add default options to any hg subcommand,
+## potentially altering its behavior and possibly its standard output.  Always
+## run hg subcommands with configuration variables set to ensure that the
+## user's preferences do not influence the expected behavior.
+hg_safe ()
+{
+  cmd=$1; shift
+  hg --config alias.${cmd}=${cmd} --config defaults.${cmd}= ${cmd} "$@"
+}
+
 if [ $# -eq 2 ] && [ x"$2" = x--disable ]; then
   echo "hg-id-disabled" > ${hg_id}-t
   ${move_if_change} ${hg_id}-t ${hg_id}
 elif [ -d $srcdir/.hg ]; then
-  ( cd $srcdir && hg identify --id || echo "unknown" ) > ${hg_id}-t
+  ( cd $srcdir && hg_safe identify --id || echo "unknown" ) > ${hg_id}-t
   ${move_if_change} ${hg_id}-t ${hg_id}
 elif [ ! -f $srcdir/${hg_id} ]; then
   echo "WARNING: $srcdir/${hg_id} is missing!" 1>&2
--- a/build-aux/mk-octave-config-h.sh	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/mk-octave-config-h.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -122,6 +122,28 @@
 /* #    undef HAVE_OCTAVE_UNUSED_ATTR */
 #  endif
 
+#  if defined (__MINGW32__)
+    /* MinGW requires special handling due to different format specifiers
+     * on different platforms.  The macro __MINGW_PRINTF_FORMAT maps to
+     * either gnu_printf or ms_printf depending on where we are compiling
+     * to avoid warnings on format specifiers that are legal.
+     * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331349  */
+#    define OCTAVE_FORMAT_PRINTF(stringIndex, firstToCheck) \
+       __attribute__ ((format (__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck)))
+
+#    define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#  elif defined (__GNUC__)
+     /* The following attributes are used with gcc and clang compilers.  */
+#    define OCTAVE_FORMAT_PRINTF(index, first) \
+       __attribute__ ((__format__(printf, index, first)))
+
+#    define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#  else
+#    define OCTAVE_FORMAT_PRINTF(index, first)
+
+/* #    undef HAVE_OCTAVE_FORMAT_PRINTF_ATTR */
+#  endif
+
 #  if ! defined (OCTAVE_FALLTHROUGH)
 #    if defined (__cplusplus) && __cplusplus > 201402L
 #      define OCTAVE_FALLTHROUGH [[fallthrough]]
@@ -202,7 +224,15 @@
 $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_F77_INT_TYPE.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_IDX_TYPE.*$\)/#  \1/p' $config_h_file
 
-echo ""
+cat << EOF
+
+#  if defined (OCTAVE_ENABLE_64)
+#    define OCTAVE_IDX_TYPE_FORMAT PRId64
+#  else
+#    define OCTAVE_IDX_TYPE_FORMAT PRId32
+#  endif
+
+EOF
 
 $SED -n 's/#\(\(undef\|define\) gid_t.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) uid_t.*$\)/#  \1/p' $config_h_file
--- a/build-aux/mk-opts.pl	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/mk-opts.pl	Thu Dec 20 17:18:56 2018 -0500
@@ -512,7 +512,8 @@
 // this file.
 
 #include <iomanip>
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
 #include "$header"
 
@@ -745,7 +746,7 @@
     {
       $iftok = "else if" if ($i > 0);
 
-      print "  $iftok (keyword_almost_match (list[$i].kw_tok, list[$i].min_len,
+      print "  $iftok (octave::keyword_almost_match (list[$i].kw_tok, list[$i].min_len,
            keyword, list[$i].min_toks_to_match, MAX_TOKENS))
     {\n";
 
@@ -814,7 +815,7 @@
     {
       $iftok = "else if" if ($i > 0);
 
-      print "  $iftok (keyword_almost_match (list[$i].kw_tok, list[$i].min_len,
+      print "  $iftok (octave::keyword_almost_match (list[$i].kw_tok, list[$i].min_len,
            keyword, list[$i].min_toks_to_match, MAX_TOKENS))
     {\n";
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build-aux/mk-pkg-add.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,65 @@
+#! /bin/sh
+#
+# Copyright (C) 2005-2018 John W. Eaton
+#
+# 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/>.
+
+## Attempt to get traditional sort behavior based on byte values.
+LC_ALL=C
+export LC_ALL
+
+set -e
+
+SED=${SED:-sed}
+
+srcdir="$1"
+shift
+
+for arg
+do
+  src_file="$srcdir/$arg"
+
+  if [ -f "$src_file" ]; then
+
+    ## Compute and print the autoloads.
+
+    base=`basename "$src_file" | $SED 's/\.cc$//'`
+    fcns=`$SED -n -e 's/^ *DEFMETHOD_DLD *( *\([^, ]*\) *,.*$/\1/p' \
+                  -e 's/^ *DEFMETHODX_DLD *( *"\([^"]*\)".*$/\1/p' \
+                  -e 's/^ *DEFUN_DLD *( *\([^, ]*\) *,.*$/\1/p' \
+                  -e 's/^ *DEFUNX_DLD *( *"\([^"]*\)".*$/\1/p' "$src_file" | \
+          sort -u`
+    if [ -n "$fcns" ]; then
+      for n in $fcns; do
+        if [ "$n" = "$base" ]; then
+          true
+        else
+          echo "autoload (\"$n\", \"$base.oct\");"
+        fi
+      done
+    fi
+
+    ## Process PKG_ADD directives after autoloads so that all
+    ## necessary functions can be found before they are used.
+
+    $SED -n -e 's,^//* *PKG_ADD: *,,p' \
+            -e 's,^/\* *PKG_ADD: *\(.*\) *\*/ *$,\1,p' "$src_file"
+
+  fi
+done
+
+exit $?
--- a/build-aux/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -10,18 +10,17 @@
   %reldir%/mk-hg-id.sh \
   %reldir%/mk-octave-config-h.sh \
   %reldir%/mk-opts.pl \
+  %reldir%/mk-pkg-add.sh \
   %reldir%/move-if-change \
   %reldir%/stl_algo.h-fixed \
   %reldir%/subst-config-vals.in.sh \
   %reldir%/subst-cross-config-vals.in.sh \
-  %reldir%/subst-default-vals.in.sh \
   %reldir%/subst-script-vals.in.sh \
   %reldir%/update-bug-status.sh
 
 GEN_CONFIG_SHELL += \
   %reldir%/subst-config-vals.sh \
   %reldir%/subst-cross-config-vals.sh \
-  %reldir%/subst-default-vals.sh \
   %reldir%/subst-script-vals.sh
 
 $(GEN_CONFIG_SHELL) : %.sh : %.in.sh config.status
--- a/build-aux/subst-config-vals.in.sh	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/subst-config-vals.in.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -20,15 +20,55 @@
 
 : ${SED=@SED@}
 
+canonical_host_type="@canonical_host_type@"
+DEFAULT_PAGER="@DEFAULT_PAGER@"
+EXEEXT="@EXEEXT@"
+man1ext="@man1ext@"
+api_version="@OCTAVE_API_VERSION@"
+OCTAVE_RELEASE=""
+version="@PACKAGE_VERSION@"
+
 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}/||"`
 
+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}/||"`
 
 srcdir="@srcdir@"
 top_srcdir="@top_srcdir@"
@@ -160,10 +200,10 @@
 QT_CPPFLAGS="@QT_CPPFLAGS@"
 QT_LDFLAGS="@QT_LDFLAGS@"
 QT_LIBS="@QT_LIBS@"
+QT_OPENGL_LIBS="@QT_OPENGL_LIBS@"
 RANLIB="@RANLIB@"
 RDYNAMIC_FLAG="@RDYNAMIC_FLAG@"
 READLINE_LIBS="@READLINE_LIBS@"
-SED="@SED@"
 SHARED_LIBS="@SHARED_LIBS@"
 SH_LD="@SH_LD@"
 SH_LDFLAGS="@SH_LDFLAGS@"
@@ -196,7 +236,11 @@
 $SED \
   -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by subst-config-vals.|" \
   -e "s|%NO_OCT_FILE_STRIP%|${NO_OCT_FILE_STRIP}|" \
+  -e "s|%OCTAVE_API_VERSION%|\"${api_version}\"|" \
+  -e "s|%OCTAVE_ARCHLIBDIR%|\"${archlibdir}\"|" \
   -e "s|%OCTAVE_BINDIR%|\"${bindir}\"|" \
+  -e "s|%OCTAVE_BINDIR%|\"${bindir}\"|" \
+  -e "s|%OCTAVE_CANONICAL_HOST_TYPE%|\"${canonical_host_type}\"|" \
   -e "s|%OCTAVE_CONF_AMD_CPPFLAGS%|\"${AMD_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_AMD_LDFLAGS%|\"${AMD_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_AMD_LIBS%|\"${AMD_LIBS}\"|" \
@@ -235,25 +279,23 @@
   -e "s|%OCTAVE_CONF_CXXPICFLAG%|\"${CXXPICFLAG}\"|" \
   -e "s|%OCTAVE_CONF_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
   -e "s|%OCTAVE_CONF_DEFS%|\"${DEFS}\"|" \
+  -e "s|%OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%|\"${DEPEND_EXTRA_SED_PATTERN}\"|" \
   -e "s|%OCTAVE_CONF_DEPEND_FLAGS%|\"${DEPEND_FLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%|\"${DEPEND_EXTRA_SED_PATTERN}\"|" \
   -e "s|%OCTAVE_CONF_DL_LD%|\"${DL_LD}\"|" \
   -e "s|%OCTAVE_CONF_DL_LDFLAGS%|\"${DL_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_DL_LIBS%|\"${DL_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_EXEC_PREFIX%|\"${exec_prefix}\"|" \
   -e "s|%OCTAVE_CONF_EXEEXT%|\"${EXEEXT}\"|" \
-  -e "s|%OCTAVE_CONF_GCC_VERSION%|\"${GCC_VERSION}\"|" \
-  -e "s|%OCTAVE_CONF_GXX_VERSION%|\"${GXX_VERSION}\"|" \
   -e "s|%OCTAVE_CONF_F77%|\"${F77}\"|" \
   -e "s|%OCTAVE_CONF_F77_FLOAT_STORE_FLAG%|\"${F77_FLOAT_STORE_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_F77_INTEGER_8_FLAG%|\"${F77_INTEGER_8_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_FFLAGS%|\"${FFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_CPPFLAGS%|\"${FFTW3F_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_LDFLAGS%|\"${FFTW3F_LDFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_LIBS%|\"${FFTW3F_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_CPPFLAGS%|\"${FFTW3_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_LDFLAGS%|\"${FFTW3_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_LIBS%|\"${FFTW3_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_CPPFLAGS%|\"${FFTW3F_CPPFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_LDFLAGS%|\"${FFTW3F_LDFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_LIBS%|\"${FFTW3F_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FLIBS%|\"${FLIBS}\"|" \
   -e "s|%OCTAVE_CONF_FLTK_CPPFLAGS%|\"${FLTK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FLTK_LDFLAGS%|\"${FLTK_LDFLAGS}\"|" \
@@ -261,22 +303,25 @@
   -e "s|%OCTAVE_CONF_FONTCONFIG_CPPFLAGS%|\"${FONTCONFIG_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FONTCONFIG_LIBS%|\"${FONTCONFIG_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FPICFLAG%|\"${FPICFLAG}\"|" \
-  -e "s|%OCTAVE_CONF_FT2_CPPFLAGS%|\"${FT2_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FT2_CPPFLAGS%|\"${FT2_CPPFLAGS}\"|" | \
+  $SED \
   -e "s|%OCTAVE_CONF_FT2_LIBS%|\"${FT2_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_GCC_VERSION%|\"${GCC_VERSION}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_CPPFLAGS%|\"${GLPK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_LDFLAGS%|\"${GLPK_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_LIBS%|\"${GLPK_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_GNUPLOT%|\"${GNUPLOT}\"|" \
-  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" | \
-  $SED -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_GXX_VERSION%|\"${GXX_VERSION}\"|" \
+  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_HDF5_LIBS%|\"${HDF5_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_INCLUDEDIR%|\"${includedir}\"|" \
   -e "s|%OCTAVE_CONF_KLU_CPPFLAGS%|\"${KLU_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_KLU_LDFLAGS%|\"${KLU_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_KLU_LIBS%|\"${KLU_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_LAPACK_LIBS%|\"${LAPACK_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_LDFLAGS%|\"${LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_LD_CXX%|\"${LD_CXX}\"|" \
-  -e "s|%OCTAVE_CONF_LDFLAGS%|\"${LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_LD_STATIC_FLAG%|\"${LD_STATIC_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_LEX%|\"${LEX}\"|" \
   -e "s|%OCTAVE_CONF_LEXLIB%|\"${LEXLIB}\"|" \
@@ -299,9 +344,9 @@
   -e "s|%OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%|\"${MKOCTFILE_DL_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_F77%|\"${MKOCTFILE_F77}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_LD_CXX%|\"${MKOCTFILE_LD_CXX}\"|" \
-  -e "s|%OCTAVE_CONF_MKOCTFILE_RANLIB%|\"${MKOCTFILE_RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_OCTAVE_LINK_DEPS%|\"${MKOCTFILE_OCTAVE_LINK_DEPS}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_OCT_LINK_DEPS%|\"${MKOCTFILE_OCT_LINK_DEPS}\"|" \
+  -e "s|%OCTAVE_CONF_MKOCTFILE_RANLIB%|\"${MKOCTFILE_RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_OCTAVE_LINK_DEPS%|\"${OCTAVE_LINK_DEPS}\"|" \
   -e "s|%OCTAVE_CONF_OCTAVE_LINK_OPTS%|\"${OCTAVE_LINK_OPTS}\"|" \
   -e "s|%OCTAVE_CONF_OCTINCLUDEDIR%|\"${octincludedir}\"|" \
@@ -327,10 +372,11 @@
   -e "s|%OCTAVE_CONF_QT_CPPFLAGS%|\"${QT_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_QT_LDFLAGS%|\"${QT_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_QT_LIBS%|\"${QT_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_QT_OPENGL_LIBS%|\"${QT_OPENGL_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_RANLIB%|\"${RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_RDYNAMIC_FLAG%|\"${RDYNAMIC_FLAG}\"|" \
-  -e "s|%OCTAVE_CONF_READLINE_LIBS%|\"${READLINE_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_SED%|\"${SED}\"|" \
+  -e "s|%OCTAVE_CONF_READLINE_LIBS%|\"${READLINE_LIBS}\"|" | \
+  $SED \
   -e "s|%OCTAVE_CONF_SHARED_LIBS%|\"${SHARED_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_SH_LD%|\"${SH_LD}\"|" \
   -e "s|%OCTAVE_CONF_SH_LDFLAGS%|\"${SH_LDFLAGS}\"|" \
@@ -358,4 +404,45 @@
   -e "s|%OCTAVE_CONF_Z_CPPFLAGS%|\"${Z_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LDFLAGS%|\"${Z_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LIBS%|\"${Z_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|"
+  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|" \
+  -e "s|%OCTAVE_DATADIR%|\"${datadir}\"|" \
+  -e "s|%OCTAVE_DATAROOTDIR%|\"${datarootdir}\"|" \
+  -e "s|%OCTAVE_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
+  -e "s|%OCTAVE_DOCDIR%|\"${docdir}\"|" \
+  -e "s|%OCTAVE_DOC_CACHE_FILE%|\"${doc_cache_file}\"|" \
+  -e "s|%OCTAVE_EXEC_PREFIX%|\"${exec_prefix}\"|" \
+  -e "s|%OCTAVE_EXEEXT%|\"${EXEEXT}\"|" \
+  -e "s|%OCTAVE_FCNFILEDIR%|\"${fcnfiledir}\"|" \
+  -e "s|%OCTAVE_IMAGEDIR%|\"${imagedir}\"|" \
+  -e "s|%OCTAVE_INCLUDEDIR%|\"${includedir}\"|" \
+  -e "s|%OCTAVE_INFODIR%|\"${infodir}\"|" \
+  -e "s|%OCTAVE_INFOFILE%|\"${infofile}\"|" \
+  -e "s|%OCTAVE_LIBDIR%|\"${libdir}\"|" \
+  -e "s|%OCTAVE_LIBEXECDIR%|\"${libexecdir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIARCHLIBDIR%|\"${localapiarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIFCNFILEDIR%|\"${localapifcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIOCTFILEDIR%|\"${localapioctfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALARCHLIBDIR%|\"${localarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALFCNFILEDIR%|\"${localfcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALOCTFILEDIR%|\"${localoctfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALSTARTUPFILEDIR%|\"${localstartupfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALVERARCHLIBDIR%|\"${localverarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALVERFCNFILEDIR%|\"${localverfcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALVEROCTFILEDIR%|\"${localveroctfiledir}\"|" \
+  -e "s|%OCTAVE_MAN1DIR%|\"${man1dir}\"|" \
+  -e "s|%OCTAVE_MAN1EXT%|\"${man1ext}\"|" \
+  -e "s|%OCTAVE_MANDIR%|\"${mandir}\"|" \
+  -e "s|%OCTAVE_OCTDATADIR%|\"${octdatadir}\"|" \
+  -e "s|%OCTAVE_OCTDOCDIR%|\"${octdocdir}\"|" \
+  -e "s|%OCTAVE_OCTETCDIR%|\"${octetcdir}\"|" \
+  -e "s|%OCTAVE_OCTFILEDIR%|\"${octfiledir}\"|" \
+  -e "s|%OCTAVE_OCTFONTSDIR%|\"${octfontsdir}\"|" \
+  -e "s|%OCTAVE_OCTINCLUDEDIR%|\"${octincludedir}\"|" \
+  -e "s|%OCTAVE_OCTLIBDIR%|\"${octlibdir}\"|" \
+  -e "s|%OCTAVE_OCTLOCALEDIR%|\"${octlocaledir}\"|" \
+  -e "s|%OCTAVE_OCTTESTSDIR%|\"${octtestsdir}\"|" \
+  -e "s|%OCTAVE_PREFIX%|\"${prefix}\"|" \
+  -e "s|%OCTAVE_RELEASE%|\"${OCTAVE_RELEASE}\"|" \
+  -e "s|%OCTAVE_STARTUPFILEDIR%|\"${startupfiledir}\"|" \
+  -e "s|%OCTAVE_TEXI_MACROS_FILE%|\"${texi_macros_file}\"|" \
+  -e "s|%OCTAVE_VERSION%|\"${version}\"|"
--- a/build-aux/subst-cross-config-vals.in.sh	Tue Dec 04 10:12:41 2018 -0800
+++ b/build-aux/subst-cross-config-vals.in.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -32,15 +32,55 @@
 ##   OCTAVE_CONF_MKOCTFILE_LD_CXX
 ##   OCTAVE_CONF_MKOCTFILE_RANLIB
 
+canonical_host_type="@canonical_host_type@"
+DEFAULT_PAGER="@DEFAULT_PAGER@"
+EXEEXT="@EXEEXT@"
+man1ext="@man1ext@"
+api_version="@OCTAVE_API_VERSION@"
+OCTAVE_RELEASE=""
+version="@PACKAGE_VERSION@"
+
 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}/||"`
 
+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}/||"`
 
 srcdir="@srcdir@"
 top_srcdir="@top_srcdir@"
@@ -164,10 +204,10 @@
 QT_CPPFLAGS="@QT_CPPFLAGS@"
 QT_LDFLAGS="@QT_LDFLAGS@"
 QT_LIBS="@QT_LIBS@"
+QT_OPENGL_LIBS="@QT_OPENGL_LIBS@"
 RANLIB="@RANLIB@"
 RDYNAMIC_FLAG="@RDYNAMIC_FLAG@"
 READLINE_LIBS="@READLINE_LIBS@"
-SED="@SED@"
 SHARED_LIBS="@SHARED_LIBS@"
 SH_LD="@SH_LD@"
 SH_LDFLAGS="@SH_LDFLAGS@"
@@ -198,9 +238,13 @@
 config_opts="@config_opts@"
 
 $SED \
-  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by subst-config-vals.|" \
+  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by subst-cross-config-vals.|" \
   -e "s|%NO_OCT_FILE_STRIP%|${NO_OCT_FILE_STRIP}|" \
+  -e "s|%OCTAVE_API_VERSION%|\"${api_version}\"|" \
+  -e "s|%OCTAVE_ARCHLIBDIR%|\"${archlibdir}\"|" \
   -e "s|%OCTAVE_BINDIR%|\"${bindir}\"|" \
+  -e "s|%OCTAVE_BINDIR%|\"${bindir}\"|" \
+  -e "s|%OCTAVE_CANONICAL_HOST_TYPE%|\"${canonical_host_type}\"|" \
   -e "s|%OCTAVE_CONF_AMD_CPPFLAGS%|\"${AMD_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_AMD_LDFLAGS%|\"${AMD_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_AMD_LIBS%|\"${AMD_LIBS}\"|" \
@@ -239,25 +283,23 @@
   -e "s|%OCTAVE_CONF_CXXPICFLAG%|\"${CXXPICFLAG}\"|" \
   -e "s|%OCTAVE_CONF_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
   -e "s|%OCTAVE_CONF_DEFS%|\"${DEFS}\"|" \
+  -e "s|%OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%|\"${DEPEND_EXTRA_SED_PATTERN}\"|" \
   -e "s|%OCTAVE_CONF_DEPEND_FLAGS%|\"${DEPEND_FLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%|\"${DEPEND_EXTRA_SED_PATTERN}\"|" \
   -e "s|%OCTAVE_CONF_DL_LD%|\"${DL_LD}\"|" \
   -e "s|%OCTAVE_CONF_DL_LDFLAGS%|\"${DL_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_DL_LIBS%|\"${DL_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_EXEC_PREFIX%|\"${exec_prefix}\"|" \
   -e "s|%OCTAVE_CONF_EXEEXT%|\"${EXEEXT}\"|" \
-  -e "s|%OCTAVE_CONF_GCC_VERSION%|\"${GCC_VERSION}\"|" \
-  -e "s|%OCTAVE_CONF_GXX_VERSION%|\"${GXX_VERSION}\"|" \
   -e "s|%OCTAVE_CONF_F77%|\"${F77}\"|" \
   -e "s|%OCTAVE_CONF_F77_FLOAT_STORE_FLAG%|\"${F77_FLOAT_STORE_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_F77_INTEGER_8_FLAG%|\"${F77_INTEGER_8_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_FFLAGS%|\"${FFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_CPPFLAGS%|\"${FFTW3F_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_LDFLAGS%|\"${FFTW3F_LDFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FFTW3F_LIBS%|\"${FFTW3F_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_CPPFLAGS%|\"${FFTW3_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_LDFLAGS%|\"${FFTW3_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FFTW3_LIBS%|\"${FFTW3_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_CPPFLAGS%|\"${FFTW3F_CPPFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_LDFLAGS%|\"${FFTW3F_LDFLAGS}\"|" \
-  -e "s|%OCTAVE_CONF_FFTW3F_LIBS%|\"${FFTW3F_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FLIBS%|\"${FLIBS}\"|" \
   -e "s|%OCTAVE_CONF_FLTK_CPPFLAGS%|\"${FLTK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FLTK_LDFLAGS%|\"${FLTK_LDFLAGS}\"|" \
@@ -265,22 +307,25 @@
   -e "s|%OCTAVE_CONF_FONTCONFIG_CPPFLAGS%|\"${FONTCONFIG_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_FONTCONFIG_LIBS%|\"${FONTCONFIG_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_FPICFLAG%|\"${FPICFLAG}\"|" \
-  -e "s|%OCTAVE_CONF_FT2_CPPFLAGS%|\"${FT2_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_FT2_CPPFLAGS%|\"${FT2_CPPFLAGS}\"|" | \
+  $SED \
   -e "s|%OCTAVE_CONF_FT2_LIBS%|\"${FT2_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_GCC_VERSION%|\"${GCC_VERSION}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_CPPFLAGS%|\"${GLPK_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_LDFLAGS%|\"${GLPK_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_GLPK_LIBS%|\"${GLPK_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_GNUPLOT%|\"${GNUPLOT}\"|" \
-  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" | \
-  $SED -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_GXX_VERSION%|\"${GXX_VERSION}\"|" \
+  -e "s|%OCTAVE_CONF_HDF5_CPPFLAGS%|\"${HDF5_CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_HDF5_LDFLAGS%|\"${HDF5_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_HDF5_LIBS%|\"${HDF5_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_INCLUDEDIR%|\"${includedir}\"|" \
   -e "s|%OCTAVE_CONF_KLU_CPPFLAGS%|\"${KLU_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_KLU_LDFLAGS%|\"${KLU_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_KLU_LIBS%|\"${KLU_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_LAPACK_LIBS%|\"${LAPACK_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_LDFLAGS%|\"${LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_LD_CXX%|\"${LD_CXX}\"|" \
-  -e "s|%OCTAVE_CONF_LDFLAGS%|\"${LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_LD_STATIC_FLAG%|\"${LD_STATIC_FLAG}\"|" \
   -e "s|%OCTAVE_CONF_LEX%|\"${LEX}\"|" \
   -e "s|%OCTAVE_CONF_LEXLIB%|\"${LEXLIB}\"|" \
@@ -303,9 +348,9 @@
   -e "s|%OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%|\"${DL_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_F77%|\"${F77}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_LD_CXX%|\"${LD_CXX}\"|" \
-  -e "s|%OCTAVE_CONF_MKOCTFILE_RANLIB%|\"${RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_OCTAVE_LINK_DEPS%|\"${MKOCTFILE_OCTAVE_LINK_DEPS}\"|" \
   -e "s|%OCTAVE_CONF_MKOCTFILE_OCT_LINK_DEPS%|\"${MKOCTFILE_OCT_LINK_DEPS}\"|" \
+  -e "s|%OCTAVE_CONF_MKOCTFILE_RANLIB%|\"${RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_OCTAVE_LINK_DEPS%|\"${OCTAVE_LINK_DEPS}\"|" \
   -e "s|%OCTAVE_CONF_OCTAVE_LINK_OPTS%|\"${OCTAVE_LINK_OPTS}\"|" \
   -e "s|%OCTAVE_CONF_OCTINCLUDEDIR%|\"${octincludedir}\"|" \
@@ -331,10 +376,11 @@
   -e "s|%OCTAVE_CONF_QT_CPPFLAGS%|\"${QT_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_QT_LDFLAGS%|\"${QT_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_QT_LIBS%|\"${QT_LIBS}\"|" \
+  -e "s|%OCTAVE_CONF_QT_OPENGL_LIBS%|\"${QT_OPENGL_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_RANLIB%|\"${RANLIB}\"|" \
   -e "s|%OCTAVE_CONF_RDYNAMIC_FLAG%|\"${RDYNAMIC_FLAG}\"|" \
-  -e "s|%OCTAVE_CONF_READLINE_LIBS%|\"${READLINE_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_SED%|\"${SED}\"|" \
+  -e "s|%OCTAVE_CONF_READLINE_LIBS%|\"${READLINE_LIBS}\"|" | \
+  $SED \
   -e "s|%OCTAVE_CONF_SHARED_LIBS%|\"${SHARED_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_SH_LD%|\"${SH_LD}\"|" \
   -e "s|%OCTAVE_CONF_SH_LDFLAGS%|\"${SH_LDFLAGS}\"|" \
@@ -362,4 +408,45 @@
   -e "s|%OCTAVE_CONF_Z_CPPFLAGS%|\"${Z_CPPFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LDFLAGS%|\"${Z_LDFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_Z_LIBS%|\"${Z_LIBS}\"|" \
-  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|"
+  -e "s|%OCTAVE_CONF_config_opts%|\"${config_opts}\"|" \
+  -e "s|%OCTAVE_DATADIR%|\"${datadir}\"|" \
+  -e "s|%OCTAVE_DATAROOTDIR%|\"${datarootdir}\"|" \
+  -e "s|%OCTAVE_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
+  -e "s|%OCTAVE_DOCDIR%|\"${docdir}\"|" \
+  -e "s|%OCTAVE_DOC_CACHE_FILE%|\"${doc_cache_file}\"|" \
+  -e "s|%OCTAVE_EXEC_PREFIX%|\"${exec_prefix}\"|" \
+  -e "s|%OCTAVE_EXEEXT%|\"${EXEEXT}\"|" \
+  -e "s|%OCTAVE_FCNFILEDIR%|\"${fcnfiledir}\"|" \
+  -e "s|%OCTAVE_IMAGEDIR%|\"${imagedir}\"|" \
+  -e "s|%OCTAVE_INCLUDEDIR%|\"${includedir}\"|" \
+  -e "s|%OCTAVE_INFODIR%|\"${infodir}\"|" \
+  -e "s|%OCTAVE_INFOFILE%|\"${infofile}\"|" \
+  -e "s|%OCTAVE_LIBDIR%|\"${libdir}\"|" \
+  -e "s|%OCTAVE_LIBEXECDIR%|\"${libexecdir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIARCHLIBDIR%|\"${localapiarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIFCNFILEDIR%|\"${localapifcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALAPIOCTFILEDIR%|\"${localapioctfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALARCHLIBDIR%|\"${localarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALFCNFILEDIR%|\"${localfcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALOCTFILEDIR%|\"${localoctfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALSTARTUPFILEDIR%|\"${localstartupfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALVERARCHLIBDIR%|\"${localverarchlibdir}\"|" \
+  -e "s|%OCTAVE_LOCALVERFCNFILEDIR%|\"${localverfcnfiledir}\"|" \
+  -e "s|%OCTAVE_LOCALVEROCTFILEDIR%|\"${localveroctfiledir}\"|" \
+  -e "s|%OCTAVE_MAN1DIR%|\"${man1dir}\"|" \
+  -e "s|%OCTAVE_MAN1EXT%|\"${man1ext}\"|" \
+  -e "s|%OCTAVE_MANDIR%|\"${mandir}\"|" \
+  -e "s|%OCTAVE_OCTDATADIR%|\"${octdatadir}\"|" \
+  -e "s|%OCTAVE_OCTDOCDIR%|\"${octdocdir}\"|" \
+  -e "s|%OCTAVE_OCTETCDIR%|\"${octetcdir}\"|" \
+  -e "s|%OCTAVE_OCTFILEDIR%|\"${octfiledir}\"|" \
+  -e "s|%OCTAVE_OCTFONTSDIR%|\"${octfontsdir}\"|" \
+  -e "s|%OCTAVE_OCTINCLUDEDIR%|\"${octincludedir}\"|" \
+  -e "s|%OCTAVE_OCTLIBDIR%|\"${octlibdir}\"|" \
+  -e "s|%OCTAVE_OCTLOCALEDIR%|\"${octlocaledir}\"|" \
+  -e "s|%OCTAVE_OCTTESTSDIR%|\"${octtestsdir}\"|" \
+  -e "s|%OCTAVE_PREFIX%|\"${prefix}\"|" \
+  -e "s|%OCTAVE_RELEASE%|\"${OCTAVE_RELEASE}\"|" \
+  -e "s|%OCTAVE_STARTUPFILEDIR%|\"${startupfiledir}\"|" \
+  -e "s|%OCTAVE_TEXI_MACROS_FILE%|\"${texi_macros_file}\"|" \
+  -e "s|%OCTAVE_VERSION%|\"${version}\"|"
--- a/build-aux/subst-default-vals.in.sh	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-#! /bin/sh
-#
-# Copyright (C) 2016-2018 John W. Eaton
-#
-# 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@}
-
-canonical_host_type="@canonical_host_type@"
-DEFAULT_PAGER="@DEFAULT_PAGER@"
-EXEEXT="@EXEEXT@"
-man1ext="@man1ext@"
-api_version="@OCTAVE_API_VERSION@"
-OCTAVE_RELEASE=""
-version="@PACKAGE_VERSION@"
-
-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}/||"`
-
-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}/||"`
-
-$SED \
-  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by subst-default-vals.|" \
-  -e "s|%OCTAVE_ARCHLIBDIR%|\"${archlibdir}\"|" \
-  -e "s|%OCTAVE_BINDIR%|\"${bindir}\"|" \
-  -e "s|%OCTAVE_CANONICAL_HOST_TYPE%|\"${canonical_host_type}\"|" \
-  -e "s|%OCTAVE_DATADIR%|\"${datadir}\"|" \
-  -e "s|%OCTAVE_DATAROOTDIR%|\"${datarootdir}\"|" \
-  -e "s|%OCTAVE_DOCDIR%|\"${docdir}\"|" \
-  -e "s|%OCTAVE_DEFAULT_PAGER%|\"${DEFAULT_PAGER}\"|" \
-  -e "s|%OCTAVE_DOC_CACHE_FILE%|\"${doc_cache_file}\"|" \
-  -e "s|%OCTAVE_EXEC_PREFIX%|\"${exec_prefix}\"|" \
-  -e "s|%OCTAVE_EXEEXT%|\"${EXEEXT}\"|" \
-  -e "s|%OCTAVE_FCNFILEDIR%|\"${fcnfiledir}\"|" \
-  -e "s|%OCTAVE_IMAGEDIR%|\"${imagedir}\"|" \
-  -e "s|%OCTAVE_INCLUDEDIR%|\"${includedir}\"|" \
-  -e "s|%OCTAVE_INFODIR%|\"${infodir}\"|" \
-  -e "s|%OCTAVE_INFOFILE%|\"${infofile}\"|" \
-  -e "s|%OCTAVE_LIBDIR%|\"${libdir}\"|" \
-  -e "s|%OCTAVE_LIBEXECDIR%|\"${libexecdir}\"|" \
-  -e "s|%OCTAVE_LOCALAPIFCNFILEDIR%|\"${localapifcnfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALAPIOCTFILEDIR%|\"${localapioctfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALARCHLIBDIR%|\"${localarchlibdir}\"|" \
-  -e "s|%OCTAVE_LOCALFCNFILEDIR%|\"${localfcnfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALOCTFILEDIR%|\"${localoctfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALSTARTUPFILEDIR%|\"${localstartupfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALAPIARCHLIBDIR%|\"${localapiarchlibdir}\"|" \
-  -e "s|%OCTAVE_LOCALVERARCHLIBDIR%|\"${localverarchlibdir}\"|" \
-  -e "s|%OCTAVE_LOCALVERFCNFILEDIR%|\"${localverfcnfiledir}\"|" \
-  -e "s|%OCTAVE_LOCALVEROCTFILEDIR%|\"${localveroctfiledir}\"|" \
-  -e "s|%OCTAVE_MAN1DIR%|\"${man1dir}\"|" \
-  -e "s|%OCTAVE_MAN1EXT%|\"${man1ext}\"|" \
-  -e "s|%OCTAVE_MANDIR%|\"${mandir}\"|" \
-  -e "s|%OCTAVE_OCTDATADIR%|\"${octdatadir}\"|" \
-  -e "s|%OCTAVE_OCTDOCDIR%|\"${octdocdir}\"|" \
-  -e "s|%OCTAVE_OCTETCDIR%|\"${octetcdir}\"|" \
-  -e "s|%OCTAVE_OCTFILEDIR%|\"${octfiledir}\"|" \
-  -e "s|%OCTAVE_OCTFONTSDIR%|\"${octfontsdir}\"|" \
-  -e "s|%OCTAVE_OCTINCLUDEDIR%|\"${octincludedir}\"|" \
-  -e "s|%OCTAVE_OCTLIBDIR%|\"${octlibdir}\"|" \
-  -e "s|%OCTAVE_OCTLOCALEDIR%|\"${octlocaledir}\"|" \
-  -e "s|%OCTAVE_OCTTESTSDIR%|\"${octtestsdir}\"|" \
-  -e "s|%OCTAVE_STARTUPFILEDIR%|\"${startupfiledir}\"|" \
-  -e "s|%OCTAVE_PREFIX%|\"${prefix}\"|" \
-  -e "s|%OCTAVE_API_VERSION%|\"${api_version}\"|" \
-  -e "s|%OCTAVE_RELEASE%|\"${OCTAVE_RELEASE}\"|" \
-  -e "s|%OCTAVE_TEXI_MACROS_FILE%|\"${texi_macros_file}\"|" \
-  -e "s|%OCTAVE_VERSION%|\"${version}\"|"
--- a/configure.ac	Tue Dec 04 10:12:41 2018 -0800
+++ b/configure.ac	Thu Dec 20 17:18:56 2018 -0500
@@ -20,7 +20,7 @@
 
 ### Initialize Autoconf
 AC_PREREQ([2.65])
-AC_INIT([GNU Octave], [4.4.1], [https://octave.org/bugs.html], [octave],
+AC_INIT([GNU Octave], [5.0.0], [https://octave.org/bugs.html], [octave],
         [https://www.gnu.org/software/octave/])
 
 ### Declare version numbers
@@ -28,9 +28,13 @@
 dnl Note that the version number is duplicated here and in AC_INIT because
 dnl AC_INIT requires it to be static, not computed from shell variables.
 
-OCTAVE_MAJOR_VERSION=4
-OCTAVE_MINOR_VERSION=4
-OCTAVE_PATCH_VERSION=1
+## The description of the Octave version number in the etc/HACKING.md
+## explains how to update these numbers for release and development
+## versions.
+
+OCTAVE_MAJOR_VERSION=5
+OCTAVE_MINOR_VERSION=0
+OCTAVE_PATCH_VERSION=0
 
 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument.
 OCTAVE_VERSION="$PACKAGE_VERSION"
@@ -52,7 +56,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-v52"
+OCTAVE_API_VERSION="api-v52+"
 
 AC_SUBST(OCTAVE_MAJOR_VERSION)
 AC_SUBST(OCTAVE_MINOR_VERSION)
@@ -188,6 +192,10 @@
 ## Programs used in configuring Octave.
 dnl Find pkg-config executable (sets $PKG_CONFIG)
 PKG_PROG_PKG_CONFIG
+## And where we will install our own .pc files.
+PKG_INSTALLDIR
+AC_SUBST([liboctave_pkgconfigdir], [$pkgconfigdir])
+AC_SUBST([libinterp_pkgconfigdir], [$pkgconfigdir])
 
 ## Programs used in Makefiles.
 AC_PROG_AWK
@@ -640,21 +648,6 @@
 fi
 AC_SUBST(XTRA_EXTERNAL_SH_LDFLAGS)
 
-### Enable dynamic linking.
-### --enable-shared implies this, thus --enable-dl is only needed if you are
-### only building static libraries and want to try dynamic linking too
-### (works on some systems, for example, OS X and Windows).
-
-AC_ARG_ENABLE([dl],
-  [AS_HELP_STRING([--disable-dl],
-    [disable loading of dynamically linked modules])],
-  [case $enableval in
-     yes) ENABLE_DYNAMIC_LINKING=yes ;;
-     no) ENABLE_DYNAMIC_LINKING=no ;;
-     *) AC_MSG_ERROR([bad value $enableval for --enable-dl]) ;;
-   esac],
-  [ENABLE_DYNAMIC_LINKING=no])
-
 if test $STATIC_LIBS = no && test $SHARED_LIBS = no; then
   AC_MSG_ERROR([You can't disable building both static AND shared libraries!])
 fi
@@ -833,6 +826,10 @@
   AC_SUBST(F77_FLOAT_STORE_FLAG)
 ])
 
+if test $ac_cv_f77_compiler_gnu = yes; then
+  OCTAVE_F77_FLAG([-std=legacy])
+fi
+
 BUILD_EXTERNAL_LIBXERBLA=
 case $host_os in
   msdosmsvc | mingw*)
@@ -857,57 +854,38 @@
 loadlibrary_api=no
 dyld_api=no
 
-if test $SHARED_LIBS = yes || test $ENABLE_DYNAMIC_LINKING = yes; then
-
-  case $lt_cv_dlopen in
-    dlopen)
-      dlopen_api=yes
-      DL_API_MSG="(dlopen)"
-      AC_DEFINE(HAVE_DLOPEN_API, 1,
-        [Define to 1 if system has dlopen, dlsym, dlerror, and dlclose for dynamic linking.])
-      OCTAVE_CXX_FLAG([-rdynamic], [RDYNAMIC_FLAG=-rdynamic])
-    ;;
-    shl_load)
-      shl_load_api=yes
-      DL_API_MSG="(shl_load)"
-      AC_DEFINE(HAVE_SHL_LOAD_API, 1,
-        [Define to 1 if system has shl_load and shl_findsym for dynamic linking.])
-    ;;
-    LoadLibrary)
-      loadlibrary_api=yes
-      DL_API_MSG="(LoadLibrary)"
-      AC_DEFINE(HAVE_LOADLIBRARY_API, 1,
-        [Define to 1 if system has LoadLibrary for dynamic linking.])
-    ;;
-    dyld)
-      dyld_api=yes
-      DL_API_MSG="(dyld)"
-      AC_DEFINE(HAVE_DYLD_API, 1,
-        [Define to 1 if system has dyld for dynamic linking.])
-    ;;
-  esac
-
-  DL_LIBS="$lt_cv_dlopen_libs"
-  AC_SUBST(DL_LIBS)
-
-  ## Disable dynamic linking if capability is not present.
-  if test $dlopen_api = yes \
-      || test $shl_load_api = yes \
-      || test $loadlibrary_api = yes \
-      || test $dyld_api = yes; then
-    ## some form of dynamic linking present
-    ENABLE_DYNAMIC_LINKING=yes
-  else
-    ENABLE_DYNAMIC_LINKING=no
-  fi
-fi
-
-if test $ENABLE_DYNAMIC_LINKING = yes; then
-  AC_DEFINE(ENABLE_DYNAMIC_LINKING, 1, [Define to 1 if using dynamic linking.])
-fi
-
-AM_CONDITIONAL([AMCOND_ENABLE_DYNAMIC_LINKING],
-  [test $ENABLE_DYNAMIC_LINKING = yes])
+case $lt_cv_dlopen in
+  dlopen)
+    dlopen_api=yes
+    DL_API_MSG="dlopen"
+    AC_DEFINE(HAVE_DLOPEN_API, 1,
+      [Define to 1 if system has dlopen, dlsym, dlerror, and dlclose for dynamic linking.])
+    OCTAVE_CXX_FLAG([-rdynamic], [RDYNAMIC_FLAG=-rdynamic])
+  ;;
+  shl_load)
+    shl_load_api=yes
+    DL_API_MSG="shl_load"
+    AC_DEFINE(HAVE_SHL_LOAD_API, 1,
+      [Define to 1 if system has shl_load and shl_findsym for dynamic linking.])
+  ;;
+  LoadLibrary)
+    loadlibrary_api=yes
+    DL_API_MSG="LoadLibrary"
+    AC_DEFINE(HAVE_LOADLIBRARY_API, 1,
+      [Define to 1 if system has LoadLibrary for dynamic linking.])
+  ;;
+  dyld)
+    dyld_api=yes
+    DL_API_MSG="dyld"
+    AC_DEFINE(HAVE_DYLD_API, 1,
+      [Define to 1 if system has dyld for dynamic linking.])
+  ;;
+  *)
+    AC_MSG_ERROR([Octave requires some way to perform dynamic linking.])
+  ;;
+esac
+
+DL_LIBS="$lt_cv_dlopen_libs"
 
 if test $SHARED_LIBS = yes; then
   LIBOCTINTERP="-loctinterp"
@@ -919,7 +897,6 @@
 
 AC_SUBST(LD_CXX)
 AC_SUBST(RDYNAMIC_FLAG)
-AC_SUBST(ENABLE_DYNAMIC_LINKING)
 AC_SUBST(LIBOCTINTERP)
 AC_SUBST(LIBOCTAVE)
 
@@ -1395,7 +1372,6 @@
     [(EXPERIMENTAL) enable JIT compiler])],
   [if test "$enableval" = yes; then ENABLE_JIT=yes; fi], [])
 
-LLVM_CXXFLAGS=
 LLVM_CPPFLAGS=
 LLVM_LDFLAGS=
 LLVM_LIBS=
@@ -1413,7 +1389,6 @@
     warn_llvm="LLVM was not found or is to old.  JIT compiler is disabled."
 
     save_CPPFLAGS="$CPPFLAGS"
-    save_CXXFLAGS="$CXXFLAGS"
     save_LDFLAGS="$LDFLAGS"
 
     dnl Use -isystem if available because we don't want to see warnings in LLVM
@@ -1424,7 +1399,6 @@
 
     dnl Use -isystem so we don't get warnings from llvm headers
     LLVM_CPPFLAGS="$LLVM_INCLUDE_FLAG `$LLVM_CONFIG --includedir`"
-    LLVM_CXXFLAGS=
     LLVM_LDFLAGS="-L`$LLVM_CONFIG --libdir`"
 
     LDFLAGS="$LDFLAGS $LLVM_LDFLAGS"
@@ -1436,7 +1410,6 @@
     dnl Ideally we should get these from llvm-config, but llvm-config isn't
     dnl very helpful.
     CPPFLAGS="-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS $LLVM_CPPFLAGS $CPPFLAGS"
-    CXXFLAGS="$LLVM_CXXFLAGS $CXXFLAGS"
     AC_LANG_PUSH(C++)
     AC_CHECK_HEADER([llvm/Support/TargetSelect.h], [warn_llvm=""])
 
@@ -1469,7 +1442,6 @@
     OCTAVE_LLVM_LEGACY_PASSMANAGER_API
     AC_LANG_POP(C++)
     CPPFLAGS="$save_CPPFLAGS"
-    CXXFLAGS="$save_CXXFLAGS"
     LDFLAGS="$save_LDFLAGS"
   fi
 
@@ -1478,7 +1450,6 @@
   else
     ENABLE_JIT=no
     LLVM_CPPFLAGS=
-    LLVM_CXXFLAGS=
     LLVM_LDFLAGS=
     LLVM_LIBS=
     OCTAVE_CONFIGURE_WARNING([warn_llvm])
@@ -1494,7 +1465,6 @@
 fi
 
 AC_SUBST(LLVM_CPPFLAGS)
-AC_SUBST(LLVM_CXXFLAGS)
 AC_SUBST(LLVM_LDFLAGS)
 AC_SUBST(LLVM_LIBS)
 AM_CONDITIONAL([AMCOND_HAVE_LLVM], [test -z "$warn_llvm"])
@@ -1906,76 +1876,6 @@
 AC_SUBST(DEFAULT_TERMINAL_FONT)
 AC_SUBST(DEFAULT_TERMINAL_FONT_SIZE)
 
-### Check for OSMesa.
-## Library is needed for offscreen rendering with Qt < 5.1 or FLTK.
-use_osmesa=auto
-AC_ARG_WITH([osmesa],
-  [AS_HELP_STRING([--with-osmesa],
-    [use OSMesa library for offscreen rendering of invisible figures])],
-  [if test x"$withval" = xyes; then
-     use_osmesa=yes
-   else
-     use_osmesa=no
-   fi])
-
-dnl If no argument given, only use OSMesa when Qt is too old
-if test $use_osmesa = auto; then
-  ## Quote $octave_cv_qt_opengl_os_ok because it will only be set if
-  ## Qt is found.
-  if test "$octave_cv_qt_opengl_os_ok" = yes; then
-    use_osmesa=no
-  else
-    use_osmesa=yes
-  fi
-fi
-
-if test $use_osmesa = yes; then
-  dnl Pre-declare warning message, and unset if library is found
-  ## Quote $octave_cv_qt_opengl_os_ok because it will only be set if
-  ## Qt is found.
-  if test "$octave_cv_qt_opengl_os_ok" = no; then
-    warn_osmesa="OSMesa library not found and Qt < 5.1.  Offscreen rendering with OpenGL will be disabled."
-  else
-    warn_osmesa="OSMesa library not found.  Offscreen rendering with FLTK will be disabled."
-  fi
-
-  OSMESA_LIBS="-lOSMesa"
-  save_CPPFLAGS="$CPPFLAGS"
-  save_LDFLAGS="$LDFLAGS"
-  save_LIBS="$LIBS"
-  CPPFLAGS="$OSMESA_CPPFLAGS $CPPFLAGS"
-  LDFLAGS="$OSMESA_LDFLAGS $LDFLAGS"
-  LIBS="$OSMESA_LIBS $LIBS"
-  AC_LANG_PUSH(C++)
-  ac_octave_osmesa_check_for_lib=no
-  AC_CHECK_HEADERS([osmesa.h GL/osmesa.h],
-                   [ac_octave_osmesa_check_for_lib=yes; break])
-  if test $ac_octave_osmesa_check_for_lib = yes; then
-    AC_CACHE_CHECK([for OSMesaCreateContext in OSMesa],
-      octave_cv_lib_osmesa,
-      [AC_LINK_IFELSE([AC_LANG_CALL([], [OSMesaCreateContext])],
-        [octave_cv_lib_osmesa=yes], [octave_cv_lib_osmesa=no])
-    ])
-    if test $octave_cv_lib_osmesa = yes; then
-      warn_osmesa=
-      AC_DEFINE(HAVE_OSMESA, 1, [Define to 1 if OSMesa is available.])
-    fi
-  fi
-  AC_LANG_POP(C++)
-  CPPFLAGS="$save_CPPFLAGS"
-  LDFLAGS="$save_LDFLAGS"
-  LIBS="$save_LIBS"
-
-  if test -n "$warn_osmesa"; then
-    OCTAVE_CONFIGURE_WARNING([warn_osmesa])
-    OSMESA_LIBS=
-  fi
-fi
-
-AC_SUBST(OSMESA_CPPFLAGS)
-AC_SUBST(OSMESA_LDFLAGS)
-AC_SUBST(OSMESA_LIBS)
-
 ### Check for FLTK library
 
 check_fltk=yes
@@ -2632,7 +2532,7 @@
      OCTAVE_CONFIGURE_WARNING([warn_docs])
    fi], [])
 if test $ENABLE_DOCS = yes; then
-  if test $opengl_graphics = no || { test "$have_qt_opengl_offscreen" = no && test -n "$warn_osmesa"; }; then
+  if test $opengl_graphics = no || test "$have_qt_opengl_offscreen" = no; then
     if test -n "$warn_gnuplot"; then
       ENABLE_DOCS=no
       warn_docs_graphics="building documentation disabled because no suitable graphics toolkit is available; make dist will fail."
@@ -2841,13 +2741,7 @@
 AC_SUBST(LIBOCTAVE_LINK_DEPS)
 AC_SUBST(LIBOCTAVE_LINK_OPTS)
 
-if test $ENABLE_DYNAMIC_LINKING = yes; then
-  LIBOCTINTERP_LINK_DEPS=""
-else
-  LIBOCTINTERP_LINK_DEPS="$DLDFCN_LIBS"
-fi
-
-LIBOCTINTERP_LINK_DEPS="$LIBOCTINTERP_LINK_DEPS $FT2_LIBS $HDF5_LIBS $MAGICK_LIBS $Z_LIBS $FFTW_XLIBS $OPENGL_LIBS $FONTCONFIG_LIBS $FREETYPE_LIBS $X11_LIBS $CARBON_LIBS $GL2PS_LIBS $LLVM_LIBS $JAVA_LIBS $LAPACK_LIBS"
+LIBOCTINTERP_LINK_DEPS="$FT2_LIBS $HDF5_LIBS $MAGICK_LIBS $Z_LIBS $FFTW_XLIBS $OPENGL_LIBS $FONTCONFIG_LIBS $FREETYPE_LIBS $X11_LIBS $CARBON_LIBS $GL2PS_LIBS $LLVM_LIBS $JAVA_LIBS $LAPACK_LIBS"
 
 LIBOCTINTERP_LINK_OPTS="$FT2_LDFLAGS $HDF5_LDFLAGS $MAGICK_LDFLAGS $Z_LDFLAGS $FFTW_XLDFLAGS $LLVM_LDFLAGS"
 
@@ -2855,9 +2749,15 @@
 OCTAVE_LINK_OPTS=""
 
 OCT_LINK_DEPS=""
+OCT_GUI_LINK_DEPS=""
+
 OCT_LINK_OPTS="$LDFLAGS"
-
-if test $link_all_deps = yes || test -n "$QT_LDFLAGS"; then
+OCT_GUI_LINK_OPTS="$LDFLAGS"
+
+if test $link_all_deps = yes; then
+  OCT_LINK_DEPS="libinterp/liboctinterp.la liboctave/liboctave.la"
+  OCT_GUI_LINK_DEPS="libgui/liboctgui.la libinterp/liboctinterp.la liboctave/liboctave.la"
+
   MKOCTFILE_OCTAVE_LINK_DEPS="$LIBOCTINTERP_LINK_DEPS $MKOCTFILE_LIBOCTAVE_LINK_DEPS"
   MKOCTFILE_OCT_LINK_DEPS="$OCT_LINK_DEPS $MKOCTFILE_LIBOCTINTERP_LINK_DEPS"
 
@@ -2866,9 +2766,13 @@
 
   OCTAVE_LINK_DEPS="$LIBOCTINTERP_LINK_DEPS"
   OCTAVE_LINK_OPTS="$LIBOCTINTERP_LINK_OPTS"
-
-  OCT_LINK_DEPS="$OCT_LINK_DEPS $LIBOCTINTERP_LINK_DEPS"
-  OCT_LINK_OPTS="$OCT_LINK_OPTS $LIBOCTINTERP_LINK_OPTS"
+else
+  case $host_os in
+    mingw* | msdosmsvc)
+      OCT_LINK_DEPS="libinterp/liboctinterp.la liboctave/liboctave.la"
+      OCT_GUI_LINK_DEPS="libgui/liboctgui.la libinterp/liboctinterp.la liboctave/liboctave.la"
+    ;;
+  esac
 fi
 
 AC_SUBST(LIBOCTINTERP_LINK_DEPS)
@@ -2880,6 +2784,9 @@
 AC_SUBST(OCT_LINK_DEPS)
 AC_SUBST(OCT_LINK_OPTS)
 
+AC_SUBST(OCT_GUI_LINK_DEPS)
+AC_SUBST(OCT_GUI_LINK_OPTS)
+
 AC_SUBST(MKOCTFILE_OCTAVE_LINK_DEPS)
 AC_SUBST(MKOCTFILE_OCT_LINK_DEPS)
 
@@ -2890,13 +2797,7 @@
 OCTAVE_GUI_LINK_OPTS=""
 
 if test $build_qt_gui = yes; then
-  if test $ENABLE_DYNAMIC_LINKING = yes; then
-    LIBOCTGUI_LINK_DEPS=""
-  else
-    LIBOCTGUI_LINK_DEPS="$DLDFCN_LIBS"
-  fi
-
-  LIBOCTGUI_LINK_DEPS="$LIBOCTGUI_LINK_DEPS $QT_LIBS $OPENGL_LIBS"
+  LIBOCTGUI_LINK_DEPS="$QT_LIBS"
   LIBOCTGUI_LINK_OPTS="$QT_LDFLAGS"
 
   if test $link_all_deps = yes || test -n "$QT_LDFLAGS"; then
@@ -3016,7 +2917,9 @@
   Makefile
   build-aux/check-subst-vars.sh:build-aux/check-subst-vars.in.sh
   doc/doxyhtml/Doxyfile
-  libgnu/Makefile])
+  libgnu/Makefile
+  liboctave/octave.pc:liboctave/octave.in.pc
+  libinterp/octinterp.pc:libinterp/octinterp.in.pc])
 
 dnl We use a .in.h file for oct-conf-post.h simply to copy it to the build tree
 dnl so that we don't have to add the -I${top_srcdir} to any CPPFLAGS variables.
@@ -3028,11 +2931,10 @@
 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/mk-version-h.sh
   build-aux/subst-config-vals.sh
   build-aux/subst-cross-config-vals.sh
-  build-aux/subst-default-vals.sh
   build-aux/subst-script-vals.sh])
 
 AC_OUTPUT
@@ -3134,7 +3036,8 @@
   QRUPDATE libraries:            $QRUPDATE_LIBS
   Qt CPPFLAGS:                   $QT_CPPFLAGS
   Qt LDFLAGS:                    $QT_LDFLAGS
-  Qt libraries:                  $QT_LIBS
+  Qt GUI libraries:              $QT_LIBS
+  Qt OpenGL libraries:           $QT_OPENGL_LIBS
   Qt moc:                        $MOC $MOCFLAGS
   Qt uic:                        $UIC $UICFLAGS
   Qt rcc:                        $RCC $RCCFLAGS
@@ -3170,7 +3073,7 @@
   Build Java interface:                 $build_java
   Build static libraries:               $STATIC_LIBS
   Build shared libraries:               $SHARED_LIBS
-  Dynamic Linking:                      $ENABLE_DYNAMIC_LINKING $DL_API_MSG
+  Dynamic Linking API:                  $DL_API_MSG
   Include support for GNU readline:     $USE_READLINE
   64-bit array dims and indexing:       $ENABLE_64
   64-bit BLAS array dims and indexing:  $HAVE_64_BIT_BLAS
@@ -3184,15 +3087,6 @@
 
 OCTAVE_CONFIGURE_WARNING_SUMMARY
 
-if test $ENABLE_DYNAMIC_LINKING = yes; then
-  if test $SHARED_LIBS = no; then
-    AC_MSG_WARN([])
-    AC_MSG_WARN([You used --enable-dl but not --enable-shared.])
-    AC_MSG_WARN([Are you sure that is what you want to do?])
-    warn_msg_printed=true
-  fi
-fi
-
 if test $opengl_graphics = no; then
   AC_MSG_WARN([])
   AC_MSG_WARN([The libraries needed for OpenGL graphics were not found.])
--- a/doc/interpreter/container.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/container.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -67,26 +67,28 @@
 @end group
 @end example
 
-@opindex . @ @ @ 
+@c The following line should have a trailing space.
+@opindex . @ @ @
 @noindent
 create a structure with three elements.  The @samp{.} character separates
-the structure name from the field name and indicates to Octave that this
-variable is a structure.  To print the value of the
-structure you can type its name, just as for any other variable:
+the structure name (in the example above @code{x}) from the field name and
+indicates to Octave that this variable is a structure.  To print the value
+of the structure you can type its name, just as for any other variable:
 
 @example
 @group
 x
      @result{} x =
-        @{
-          a = 1
-          b =
+
+         scalar structure containing the fields:
 
-            1  2
-            3  4
+           a =  1
+           b =
 
-          c = string
-        @}
+              1   2
+              3   4
+
+           c = string
 @end group
 @end example
 
@@ -99,43 +101,51 @@
 @group
 y = x
      @result{} y =
-        @{
-          a = 1
-          b =
+
+         scalar structure containing the fields:
 
-            1  2
-            3  4
+           a =  1
+           b =
 
-          c = string
-        @}
+              1   2
+              3   4
+
+           c = string
 @end group
 @end example
 
 Since structures are themselves values, structure elements may reference
-other structures.  The following statements change the value of the
-element @code{b} of the structure @code{x} to be a data structure
-containing the single element @code{d}, which has a value of 3.
+other structures, as well.  The following statement adds the field @code{d}
+to the structure @code{x}.  The value of field @code{d} is itself a data
+structure containing the single field @code{a}, which has a value of 3.
 
 @example
 @group
-x.b.d = 3;
-x.b
+x.d.a = 3;
+x.d
      @result{} ans =
-        @{
-          d = 3
-        @}
+
+         scalar structure containing the fields:
+
+           a =  3
 
 x
      @result{} x =
-        @{
-          a = 1
-          b =
-          @{
-            d = 3
-          @}
+
+         scalar structure containing the fields:
+
+           a =  1
+           b =
 
-          c = string
-        @}
+              1   2
+              3   4
+
+           c = string
+           d =
+
+             scalar structure containing the fields:
+
+               a =  3
 @end group
 @end example
 
@@ -147,17 +157,18 @@
 a.b.c.d.e = 1;
 a
      @result{} a =
-        @{
-          b =
-          @{
-            c =
-            @{
-              1x1 struct array containing the fields:
+
+         scalar structure containing the fields:
+
+           b =
 
-              d: 1x1 struct
-            @}
-          @}
-        @}
+             scalar structure containing the fields:
+
+               c =
+
+                 scalar structure containing the fields:
+
+                   d: 1x1 scalar struct
 @end group
 @end example
 
@@ -174,7 +185,7 @@
 
 Functions can return structures.  For example, the following function
 separates the real and complex parts of a matrix and stores them in two
-elements of the same structure variable.
+elements of the same structure variable @code{y}.
 
 @example
 @group
@@ -185,26 +196,26 @@
 @end group
 @end example
 
-When called with a complex-valued argument, @code{f} returns the data
-structure containing the real and imaginary parts of the original
+When called with a complex-valued argument, the function @code{f} returns
+the data structure containing the real and imaginary parts of the original
 function argument.
 
 @example
 @group
 f (rand (2) + rand (2) * I)
      @result{} ans =
-        @{
-          im =
 
-            0.26475  0.14828
-            0.18436  0.83669
+         scalar structure containing the fields:
+
+           re =
 
-          re =
+              0.040239  0.242160
+              0.238081  0.402523
 
-            0.040239  0.242160
-            0.238081  0.402523
+           im =
 
-        @}
+              0.26475  0.14828
+              0.18436  0.83669
 @end group
 @end example
 
@@ -214,25 +225,26 @@
 @example
 [ x.u, x.s(2:3,2:3), x.v ] = svd ([1, 2; 3, 4]);
 x
+
      @result{} x =
-        @{
-          u =
+
+         scalar structure containing the fields:
 
-            -0.40455  -0.91451
-            -0.91451   0.40455
+           u =
 
-          s =
+             -0.40455  -0.91451
+             -0.91451   0.40455
 
-             0.00000   0.00000   0.00000
-             0.00000   5.46499   0.00000
-             0.00000   0.00000   0.36597
+           s =
 
-          v =
+              0.00000   0.00000   0.00000
+              0.00000   5.46499   0.00000
+              0.00000   0.00000   0.36597
 
-            -0.57605   0.81742
-            -0.81742  -0.57605
+           v =
 
-        @}
+             -0.57605   0.81742
+             -0.81742  -0.57605
 @end example
 
 It is also possible to cycle through all the elements of a structure in
--- a/doc/interpreter/contributors.in	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/contributors.in	Thu Dec 20 17:18:56 2018 -0500
@@ -113,6 +113,7 @@
 Nicolo Giorgetti
 Arun Giridhar
 Michael D. Godfrey
+Dave Goel
 Michael Goffioul
 Glenn Golden
 Tomislav Goles
@@ -133,6 +134,7 @@
 Benjamin Hall
 Alexander Hansen
 Kim Hansen
+Gene Harvey
 Søren Hauberg
 Dave Hawthorne
 Oliver Heimlich
@@ -412,6 +414,7 @@
 Marco Vitetta
 Daniel Wagenaar
 Thomas Walter
+Jun Wang
 Andreas Weber
 Olaf Weber
 Thomas Weber
--- a/doc/interpreter/doccheck/aspell-octave.en.pws	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/doccheck/aspell-octave.en.pws	Thu Dec 20 17:18:56 2018 -0500
@@ -1,8 +1,8 @@
 personal_ws-1.1 en 1
 AbsTol
 accumarray
+acknowledgements
 Acknowledgements
-acknowledgements
 adams
 Affero
 afterwards
@@ -51,8 +51,8 @@
 Barycentric
 basevalue
 BaseValue
+bdf
 BDF
-bdf
 benchmarking
 betacdf
 betainc
@@ -84,8 +84,8 @@
 broadcastable
 BufSize
 builtin
+bulleted
 Bulleted
-bulleted
 ButtonDownFcn
 buttondownfcn
 BV
@@ -143,11 +143,11 @@
 colorcube
 colormap
 colormaps
+ColorOrder
 colororder
-ColorOrder
 colperm
+CommentStyle
 commentstyle
-CommentStyle
 ComplexEqn
 cond
 condest
@@ -159,6 +159,7 @@
 convhull
 Convolve
 copyrightable
+CorelDraw
 corrcoef
 cosecant
 courseware
@@ -174,8 +175,8 @@
 CSV
 csymamd
 ctranspose
+CTRL
 Ctrl
-CTRL
 cubehelix
 cummax
 cummin
@@ -207,10 +208,11 @@
 deconv
 Deconvolve
 decrement
+defaultaxesbox
 defaultuicontrolbackgroundcolor
 deftypefn
+Delaunay
 delaunay
-Delaunay
 delaunayn
 DeleteFcn
 deletefcn
@@ -221,8 +223,8 @@
 dggsvd
 diag
 diagcomp
+Dialogs
 dialogs
-Dialogs
 diamondsuit
 differentiable
 digamma
@@ -230,8 +232,8 @@
 dimensionally
 dir
 disp
+displayname
 DisplayName
-displayname
 displayrange
 dMatrix
 dmperm
@@ -266,27 +268,27 @@
 emptyvalue
 EmptyValue
 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
@@ -307,8 +309,9 @@
 facecolor
 FaceColor
 FaceLighting
+FaceNormals
+FaceVertexCData
 facevertexcdata
-FaceVertexCData
 factorizations
 fcdf
 femmodel
@@ -323,6 +326,7 @@
 fieldnames
 FIFOs
 filename
+FileName
 filenames
 filepaths
 Filesystem
@@ -333,8 +337,9 @@
 fitboxtotext
 FIXME
 flac
+FLTK
 fltk
-FLTK
+fminsearch
 fminunc
 fontconfig
 fontname
@@ -347,8 +352,8 @@
 FreeBSD
 FreeSans
 freespacing
+FreeType
 freetype
-FreeType
 frnd
 Fs
 FSF
@@ -387,10 +392,10 @@
 GLS
 glyphs
 GMRES
+gnuplot
 Gnuplot
-gnuplot
+Goto
 goto
-Goto
 gouraud
 gperf
 GPL
@@ -408,23 +413,24 @@
 gzip
 gzipped
 Hadamard
+handlevisibility
 HandleVisibility
-handlevisibility
 Hankel
 Hanning
 hanning
 hardcode
 hardcoded
 hardcoding
+hdf
 HDF
-hdf
+HeaderLines
 headerlines
-HeaderLines
 headlength
 headstyle
 headwidth
 heartsuit
 helpdlg
+Helvetica
 Hermitian
 Hessenberg
 heteroscedascity
@@ -432,6 +438,7 @@
 hggroup
 hggroups
 hgid
+hgload
 HH
 hh
 histc
@@ -451,8 +458,8 @@
 ict
 IDE
 IEC
+IEEE
 ieee
-IEEE
 ifelse
 ifft
 ifftn
@@ -521,11 +528,11 @@
 JConstant
 JDK
 JIS
+jit
 JIT
-jit
 JPattern
+jpeg
 JPEG
-jpeg
 jpg
 jvm
 JVM's
@@ -627,6 +634,7 @@
 metadata
 metafile
 Metafile
+MetaFile
 metafiles
 Metafont
 mex
@@ -649,6 +657,7 @@
 mmmm
 mmmyy
 mmmyyyy
+movegui
 mpoles
 mpower
 mput
@@ -661,8 +670,8 @@
 Multi
 multibyte
 multipage
+MultipleDelimsAsOne
 multipledelimsasone
-MultipleDelimsAsOne
 MultiSelect
 multistep
 MvPattern
@@ -670,10 +679,10 @@
 myclass
 myfun
 nabla
+NAMESPACE
 namespace
-NAMESPACE
+nan
 NaN
-nan
 nanflag
 NaNs
 nargin
@@ -707,6 +716,7 @@
 nonnan
 NonNegative
 nonnegativity
+nonskew
 nonsmooth
 nonsparse
 nonzeros
@@ -734,8 +744,10 @@
 octaverc
 ODEPACK
 ODEs
+offscreen
+ofig
+Ogg
 ogg
-Ogg
 OKString
 OLS
 omitnan
@@ -743,6 +755,7 @@
 online
 OpenBLAS
 OpenGL
+opengl
 OpenJDK
 oplus
 optimizations
@@ -769,8 +782,8 @@
 PaperUnits
 parametrically
 parseparams
+pbm
 PBM
-pbm
 PBMplus
 pc
 pcg
@@ -780,8 +793,8 @@
 PCRE
 pcre
 PCX
+pdf
 PDF
-pdf
 pdflatex
 pentadiagonal
 periodogram
@@ -794,8 +807,8 @@
 Piecewise
 pinv
 PixelRegion
+PNG
 png
-PNG
 poisscdf
 poissinv
 poisspdf
@@ -826,8 +839,8 @@
 presolver
 printf
 priori
+profiler
 Profiler
-profiler
 programmatically
 prolate
 PromptString
@@ -845,24 +858,24 @@
 Qhull
 QP
 QQ
+QRUPDATE
 qrupdate
-QRUPDATE
 QScintilla
 quadcc
 quadgk
 quadl
 quadpack
 quadv
+Quantile
 quantile
-Quantile
 quantiles
 quantization
 quartic
 quartile
 questdlg
 Quickhull
+qz
 QZ
-qz
 radian
 radians
 radices
@@ -878,8 +891,8 @@
 ranlib
 rceil
 rdivide
+Readline
 readline
-Readline
 RECT
 recursing
 redistributable
@@ -890,6 +903,7 @@
 relicensing
 RelTol
 renderer
+renderers
 repelems
 replacechildren
 repmat
@@ -897,8 +911,8 @@
 reproducibility
 resampled
 resampling
+resize
 Resize
-resize
 resized
 Resizing
 resizing
@@ -909,13 +923,14 @@
 restorePrevious
 RET
 retarget
+returnonerror
 ReturnOnError
-returnonerror
 rfloor
+rgb
 RGB
-rgb
+RGBImage
+rightarrow
 Rightarrow
-rightarrow
 rle
 rline
 rmdir
@@ -983,8 +998,8 @@
 ss
 sT
 stairstep
+Startup
 startup
-Startup
 statinfo
 stdin
 stdout
@@ -1000,8 +1015,9 @@
 struct
 structs
 subarrays
+subclasses
 Subclasses
-subclasses
+subdiagonal
 subdiagonals
 subdirectories
 subdirectory
@@ -1011,8 +1027,8 @@
 Subfunctions
 subfunctions
 subinterval
+subintervals
 Subintervals
-subintervals
 sublicenses
 Sublicensing
 submatrices
@@ -1020,16 +1036,16 @@
 submenu
 suboptimal
 subprocess
+subprocesses
 Subprocesses
-subprocesses
 subsasgn
+subscripted
 Subscripted
-subscripted
 subscripting
 subseteq
 subsindex
+subspaces
 Subspaces
-subspaces
 subsref
 substring
 substrings
@@ -1047,15 +1063,15 @@
 supseteq
 surd
 SV
+svd
 SVD
-svd
 svds
-svg
 SVG
-Sym
+svg
 sym
+Sym
+SYMAMD
 symamd
-SYMAMD
 symbfact
 symrcm
 Syntaxes
@@ -1092,8 +1108,8 @@
 TolF
 TolFun
 TolX
+Toolkits
 toolkits
-Toolkits
 toplevel
 TP
 tpdf
@@ -1111,8 +1127,8 @@
 trisurf
 trivariate
 trnd
+TrueColor
 truecolor
-TrueColor
 tuples
 txi
 typedefs
@@ -1122,13 +1138,13 @@
 uchar
 UHESS
 UI
+Uibuttongroup
 uibuttongroup
-Uibuttongroup
 uibuttongroups
 uicontextmenu
 Uicontextmenu
+Uicontrol
 uicontrol
-Uicontrol
 uicontrols
 UID
 uimenu
@@ -1148,8 +1164,8 @@
 Ultrix
 umfpack
 uminus
+unary
 Unary
-unary
 unconvertible
 undirected
 unifcdf
@@ -1212,29 +1228,29 @@
 waitbar
 waitbars
 warndlg
+WAV
 wav
-WAV
-waypoints
 Waypoints
 WayPoints
+waypoints
 wblcdf
 wblinv
 wblpdf
 wblrnd
 WestOutside
+whitespace
 Whitespace
-whitespace
 whos
 wienrnd
 Wikipedia
 wildcard
+Wildcards
 wildcards
-Wildcards
 windowbuttondownfcn
 windowbuttonmotionfcn
 windowbuttonupfcn
+windowstyle
 WindowStyle
-windowstyle
 WIPO
 wireframe
 workspace
@@ -1247,10 +1263,12 @@
 xerrorbar
 xerrorbars
 XFig
+xfirst
 xGBTRF
 xGELSD
 xGETRF
 xGTSV
+xlast
 xlim
 xlimmode
 xmax
@@ -1278,17 +1296,19 @@
 ydata
 yerrorbar
 yerrorbars
+yfirst
 ylabel
+ylast
 ylim
 ymax
 ymin
 ypos
 yticklabels
 yticks
+YY
 yy
-YY
+yyyy
 YYYY
-yyyy
 yyyymmddTHHMMSS
 zggsvd
 Ziggurat
--- a/doc/interpreter/external.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/external.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -1805,7 +1805,7 @@
 @menu
 * Making Java Classes Available::
 * How to use Java from within Octave::
-* Passing parameters to the JVM::
+* Set up the JVM::
 * Java Interface Functions::
 @end menu
 
@@ -2089,18 +2089,33 @@
 
 
 
-@node Passing parameters to the JVM
-@subsection Passing parameters to the JVM
+@node Set up the JVM
+@subsection Set up the JVM
 @cindex memory, limitations on JVM
-
-In order to execute Java code Octave creates a Java Virtual Machine (JVM).
-Such a JVM allocates a fixed amount of initial memory and may expand this pool
-up to a fixed maximum memory limit.  The default values depend on the Java
-version (@pxref{XREFjavamem,,javamem}).  The memory pool is shared by all Java
-objects running in the JVM@.  This strict memory limit is intended mainly to
-avoid runaway applications inside web browsers or in enterprise servers which
-can consume all memory and crash the system.  When the maximum memory limit is
-hit, Java code will throw exceptions so that applications will fail or behave
+@cindex select JVM version
+
+In order to execute Java code Octave creates a Java Virtual Machine (JVM).  By
+default the version of the JVM is used that was detected during configuration
+on Unix-like systems or that is pointed to from the registry keys at
+@file{HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JRE} or
+@file{HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment} on
+Windows.  The default path to the JVM can be overridden by setting the
+environment variable @w{@env{JAVA_HOME}} to the path where the JVM is
+installed.  On Windows that might be, for example,
+@file{C:\Program Files\Java\jre-10.0.2}.  Make sure that you select a directory
+that contains the JVM with a @nospell{bit-ness} that matches Octave's.
+
+The JVM is only loaded once per Octave session.  Thus, to change the used
+version of the JVM, you might have to re-start Octave.  To check which version
+of the JVM is currently being used, run @code{version -java}.
+
+The JVM allocates a fixed amount of initial memory and may expand this pool up
+to a fixed maximum memory limit.  The default values depend on the Java version
+(@pxref{XREFjavamem,,javamem}).  The memory pool is shared by all Java objects
+running in the JVM@.  This strict memory limit is intended mainly to avoid
+runaway applications inside web browsers or in enterprise servers which can
+consume all memory and crash the system.  When the maximum memory limit is hit,
+Java code will throw exceptions so that applications will fail or behave
 unexpectedly.
 
 You can specify options for the creation of the JVM inside a file named
--- a/doc/interpreter/func.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/func.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -1097,11 +1097,8 @@
 @node Function Locking
 @subsection Function Locking
 
-It is sometime desirable to lock a function into memory with the
-@code{mlock} function.  This is typically used for dynamically linked
-functions in Oct-files or mex-files that contain some initialization,
-and it is desirable that calling @code{clear} does not remove this
-initialization.
+It is sometime desirable to lock a function into memory with the @code{mlock}
+function.  This is typically used for dynamically linked functions in oct-files or mex-files that contain some initialization, and it is desirable that calling @code{clear} does not remove this initialization.
 
 As an example,
 
@@ -1110,14 +1107,15 @@
 function my_function ()
   mlock ();
   @dots{}
+endfunction
 @end group
 @end example
 
 @noindent
-prevents @code{my_function} from being removed from memory after it is
-called, even if @code{clear} is called.  It is possible to determine if
-a function is locked into memory with the @code{mislocked}, and to unlock
-a function with @code{munlock}, which the following illustrates.
+prevents @code{my_function} from being removed from memory after it is called,
+even if @code{clear} is called.  It is possible to determine if a function is
+locked into memory with the @code{mislocked}, and to unlock a function with
+@code{munlock}, which the following code illustrates.
 
 @example
 @group
@@ -1130,30 +1128,29 @@
 @end group
 @end example
 
-A common use of @code{mlock} is to prevent persistent variables from
-being removed from memory, as the following example shows:
+A common use of @code{mlock} is to prevent persistent variables from being
+removed from memory, as the following example shows:
 
 @example
 @group
 function count_calls ()
   mlock ();
   persistent calls = 0;
-  printf ("'count_calls' has been called %d times\n",
-          ++calls);
+  printf ("count_calls() has been called %d times\n", ++calls);
 endfunction
 
 count_calls ();
-@print{} 'count_calls' has been called 1 times
+@print{} count_calls() has been called 1 times
 
 clear count_calls
 count_calls ();
-@print{} 'count_calls' has been called 2 times
+@print{} count_calls() has been called 2 times
 @end group
 @end example
 
-@code{mlock} might equally be used to prevent changes to a function from having
-effect in Octave, though a similar effect can be had with the
-@code{ignore_function_time_stamp} function.
+@code{mlock} might also be used to prevent changes to an m-file, such as in an
+external editor, from having any effect in the current Octave session; A
+similar effect can be had with the @code{ignore_function_time_stamp} function.
 
 @DOCSTRING(mlock)
 
--- a/doc/interpreter/genpropdoc.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/genpropdoc.m	Thu Dec 20 17:18:56 2018 -0500
@@ -31,10 +31,11 @@
 ## @end deftypefn
 
 function genpropdoc (objname, fname)
-  objnames = {"root", "figure", "axes", "line", ...
-              "text", "image", "patch", "surface", "light", ...
-              "uimenu", "uibuttongroup", "uicontextmenu", "uipanel", ...
-              "uicontrol", "uitoolbar", "uipushtool", "uitoggletool"};
+  objnames = {"root", "figure", "axes", ...
+              "image", "light", "line", "patch", "surface", "text", ...
+              "uibuttongroup", "uicontextmenu", "uicontrol", "uipanel", ...
+              "uimenu", "uipushtool", "uitable", "uitoggletool" "uitoolbar"
+             };
 
   ## Base properties
   base = getstructure ("base");
@@ -89,7 +90,7 @@
   ##
   ## -"printdefault": a boolean (def. true) that specifies whether the
   ##   default value should be printed.  It is useful for properties
-  ##   like root "screendepth" that default to screen dependant values.
+  ##   like root "screendepth" that default to screen dependent values.
 
   packopt = @(c) strjoin (c, " | ");
   markdef = @(s) ["@{" s "@}"];
@@ -516,13 +517,19 @@
         s.valid = valid_4elvec;
 
       case "renderer"
-        s.doc = doc_unused;
+        s.doc = "Renderering engine used for printing when @code{renderermode} \
+is \"manual\".  __modemsg__.";
 
       case "renderermode"
-        s.doc = doc_unused;
+        s.doc = "Control whether the renderering engine used for printing is \
+chosen automatically or specified by the @code{renderer} property.  \
+@xref{XREFprint, , @w{print function}}.";
 
       case "resize"
-        s.doc = doc_unused;
+        s.doc = "Control whether the figure can be resized by dragging the \
+window borders and corners using a mouse.  When __prop__ is @qcode{\"off\"} \
+mouse interactions are disabled but the figure can still be resized by \
+changing its @qcode{\"position\"} property.";
 
       case "resizefcn"
         s.doc = "__prop__ is deprecated.  Use @code{sizechangedfcn} instead.";
@@ -1147,7 +1154,7 @@
         s.valid = valid_cellstring;
 
       case "xdata"
-        s.doc = "Two-element vector @code{[xmin xmax]} specifying the x \
+        s.doc = "Two-element vector @code{[xfirst xlast]} specifying the x \
 coordinates of the centers of the first and last columns of the image.\n\
 \n\
 Setting @code{xdata} to the empty matrix ([]) will restore the default value \
@@ -1155,7 +1162,7 @@
         s.valid = valid_2elvec;
 
       case "ydata"
-        s.doc = "Two-element vector @code{[ymin ymax]} specifying the y \
+        s.doc = "Two-element vector @code{[yfirst ylast]} specifying the y \
 coordinates of the centers of the first and last rows of the image.\n\
 \n\
 Setting @code{ydata} to the empty matrix ([]) will restore the default value \
@@ -1236,6 +1243,17 @@
 the vertices). @qcode{\"phong\"} is deprecated and has the same effect as \
 @qcode{\"gouraud\"}.";
 
+      case "facenormals"
+        s.doc = "Face normals are used for lighting the edges or faces if the \
+@code{edgelighting} or @code{facelighting} properties are set to \
+@qcode{\"flat\"}.  __modemsg__";
+
+      case "facenormalsmode"
+        s.doc = "If this property is set to @qcode{\"auto\"}, \
+@code{facenormals} are automatically calculated if the @code{edgelighting} or \
+@code{facelighting} property are set to @qcode{\"flat\"} and at least one \
+@code{light} object is present and visible in the same axes.";
+
       case "interpreter"
       case "linestyle"
         s.doc = "@xref{Line Styles}.";
@@ -1260,7 +1278,6 @@
         s.valid = "scalar";
 
       case "meshstyle"
-      case "normalmode"
       case "specularcolorreflectance"
         s.doc = "Reflectance for specular color. Value between 0.0 (color \
 of underlying face) and 1.0 (color of light source).";
@@ -1277,6 +1294,16 @@
         s.valid = "scalar";
 
       case "vertexnormals"
+        s.doc = "Vertex normals are used for lighting the edges or faces if \
+the @code{edgelighting} or @code{facelighting} properties are set to \
+@qcode{\"gouraud\"}.  __modemsg__";
+
+      case "vertexnormalsmode"
+        s.doc = "If this property is set to @qcode{\"auto\"}, \
+@code{vertexnormals} are automatically calculated if the @code{edgelighting} \
+or @code{facelighting} property are set to @qcode{\"gouraud\"} and at least \
+one @code{light} object is present and visible in the same axes.";
+
       case "xdata"
         s.valid = "matrix";
 
@@ -1374,8 +1401,18 @@
 the vertices). @qcode{\"phong\"} is deprecated and has the same effect as \
 @qcode{\"gouraud\"}.";
 
+      case "facenormals"
+        s.doc = "Face normals are used for lighting the edges or faces if the \
+@code{edgelighting} or @code{facelighting} properties are set to \
+@qcode{\"flat\"}.  __modemsg__";
+
+      case "facenormalsmode"
+        s.doc = "If this property is set to @qcode{\"auto\"}, \
+@code{facenormals} are automatically calculated if the @code{edgelighting} or \
+@code{facelighting} property are set to @qcode{\"flat\"} and at least one \
+@code{light} object is present and visible in the same axes.";
+
       case "faces"
-      case "xdata"
         s.valid = valid_vecmat;
 
       case "facevertexalphadata"
@@ -1403,7 +1440,6 @@
         s.doc = "@xref{XREFlinemarkersize, , @w{line markersize property}}.";
         s.valid = "scalar";
 
-      case "normalmode"
       case "specularcolorreflectance"
         s.doc = "Reflectance for specular color.  Value between 0.0 (color \
 of underlying face) and 1.0 (color of light source).";
@@ -1420,6 +1456,16 @@
         s.valid = "scalar";
 
       case "vertexnormals"
+        s.doc = "Vertex normals are used for lighting the edges or faces if \
+the @code{edgelighting} or @code{facelighting} properties are set to \
+@qcode{\"gouraud\"}.  __modemsg__";
+
+      case "vertexnormalsmode"
+        s.doc = "If this property is set to @qcode{\"auto\"}, \
+@code{vertexnormals} are automatically calculated if the @code{edgelighting} \
+or @code{facelighting} property are set to @qcode{\"gouraud\"} and at least \
+one @code{light} object is present and visible in the same axes.";
+
       case "vertices"
         s.valid = valid_vecmat;
 
@@ -1517,8 +1563,18 @@
       case "foregroundcolor"
       case "highlightcolor"
       case "position"
+
       case "resizefcn"
+        s.doc = "__prop__ is deprecated.  Use @code{sizechangedfcn} instead.";
+        s.valid = valid_fcn;
+
       case "shadowcolor"
+
+      case "sizechangedfcn"
+        s.doc = "Callback triggered when the uipanel size is changed.\
+\n\n__fcnmsg__";
+        s.valid = valid_fcn;
+
       case "title"
       case "titleposition"
       case "units"
@@ -1554,10 +1610,20 @@
       case "foregroundcolor"
       case "highlightcolor"
       case "position"
+
       case "resizefcn"
+        s.doc = "__prop__ is deprecated.  Use @code{sizechangedfcn} instead.";
+        s.valid = valid_fcn;
+
       case "selectedobject"
       case "selectionchangedfcn"
       case "shadowcolor"
+
+      case "sizechangedfcn"
+        s.doc = "Callback triggered when the uibuttongroup size is changed.\
+\n\n__fcnmsg__";
+        s.valid = valid_fcn;
+
       case "title"
       case "titleposition"
       case "units"
@@ -1612,6 +1678,54 @@
 
     endswitch
 
+  ## uitable Properties
+  elseif (strcmp (objname, "uitable"))
+    switch (field)
+      ## Overridden shared properties
+
+      ## Specific properties
+      case "backgroundcolor"
+      case "celleditcallback"
+      case "cellselectioncallback"
+      case "columneditable"
+      case "columnformat"
+      case "columnname"
+      case "columnwidth"
+      case "data"
+      case "enable"
+      case "extent"
+        s.valid = valid_4elvec;
+        s.printdefault = false;
+
+      case "fontangle"
+        s.doc = doc_fontangle;
+
+      case "fontname"
+        s.doc = doc_fontname;
+        s.valid = valid_string;
+
+      case "fontsize"
+        s.doc = doc_fontsize;
+        s.valid = "scalar";
+
+      case "fontunits"
+        s.doc = doc_fontunits;
+
+      case "fontweight"
+        s.doc = doc_fontweight;
+
+      case "foregroundcolor"
+      case "keypressfcn"
+      case "keyreleasefcn"
+      case "position"
+      case "rearrangeablecolumns"
+      case "rowname"
+      case "rowstriping"
+      case "tooltipstring"
+      case "units"
+
+    endswitch
+
   ## uitoolbar properties
   elseif (strcmp (objname, "uitoolbar"))
     switch (field)
@@ -1750,7 +1864,7 @@
   def = get (h, field);
 
   ## Don't print default values for graphics handles
-  if (isscalar (def) && def != 0 && ishghandle (def))
+  if (ishghandle (def) && isscalar (def) && def != 0)
     def = "";
   else
     if (ischar (def))
@@ -1773,9 +1887,9 @@
         endif
 
         ## Replace texinfo reserved characters
-        def = strrep (str, "{", "@{");
+        def = strrep (str, "@", "@@");  # must occur first
+        def = strrep (def, "{", "@{");
         def = strrep (def, "}", "@}");
-        def = strrep (def, "@", "@@");
 
         def = ["@code{" def "}"];
       else
--- a/doc/interpreter/geometryimages.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/geometryimages.m	Thu Dec 20 17:18:56 2018 -0500
@@ -156,7 +156,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/doc/interpreter/gui.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/gui.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,8 @@
 results a script can open a dialog box and allow the user to choose a file.
 Similarly, if a calculation is expected to take a long time a script can
 display a progress bar.  The various UI elements can be used to fully customize
-the plot window with menubars, context menus,
+the plot window with menubars, toolbars, context menus, pushbuttons, sliders,
+etc.
 
 Several utility functions make it possible to store private data for use with
 a GUI which will not pollute the user's variable space.
@@ -61,8 +62,8 @@
 @cindex dialog, displaying a dialog for storing files
 @DOCSTRING(uiputfile)
 
-Additionally, there are dialog boxes for printing further help, warnings or
-errors and to get textual input from the user.
+Additionally, there are dialog boxes for displaying help messages, warnings, or
+errors, and for getting text input from the user.
 
 @cindex dialog, displaying an error dialog
 @DOCSTRING(errordlg)
@@ -103,22 +104,24 @@
 toolkit, although some functionality is available with the @code{fltk} toolkit.
 There is no support for the @code{gnuplot} toolkit.
 
-@DOCSTRING(uimenu)
+@DOCSTRING(uipanel)
 
 @DOCSTRING(uibuttongroup)
 
+@DOCSTRING(uicontrol)
+
+@DOCSTRING(uitable)
+
+@DOCSTRING(uimenu)
+
 @DOCSTRING(uicontextmenu)
 
-@DOCSTRING(uicontrol)
-
-@DOCSTRING(uipanel)
+@DOCSTRING(uitoolbar)
 
 @DOCSTRING(uipushtool)
 
 @DOCSTRING(uitoggletool)
 
-@DOCSTRING(uitoolbar)
-
 @node GUI Utility Functions
 @section GUI Utility Functions
 
@@ -134,6 +137,8 @@
 
 @DOCSTRING(isguirunning)
 
+@DOCSTRING(movegui)
+
 @c Not sure where this should go...
 @DOCSTRING(openvar)
 
--- a/doc/interpreter/image.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/image.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -140,9 +140,10 @@
 an RGB color.  The color map must be of class @code{double} with values
 between 0 and 1.
 
-@DOCSTRING(im2double)
+The following convenience functions are available for conversion between image 
+formats.
 
-@DOCSTRING(iscolormap)
+@DOCSTRING(im2double)
 
 @DOCSTRING(gray2ind)
 
@@ -152,14 +153,27 @@
 
 @DOCSTRING(ind2rgb)
 
+Octave also provides tools to produce and work with movie frame structures. 
+Those structures encapsulate the image data (@qcode{"cdata"} field) together 
+with the corresponding colormap (@qcode{"colormap"} field).
+
 @DOCSTRING(getframe)
 
+@DOCSTRING(movie)
+
 @DOCSTRING(frame2im)
 
 @DOCSTRING(im2frame)
 
+The @code{colormap} function is used to change the colormap of the current axes or figure.
+
 @DOCSTRING(colormap)
 
+@DOCSTRING(iscolormap)
+
+The following functions return predefined colormaps, the same that can be 
+requested by name using the @code{colormap} function. 
+
 @DOCSTRING(rgbplot)
 
 @DOCSTRING(autumn)
--- a/doc/interpreter/install.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/install.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -313,7 +313,7 @@
 
 @item Qt
 GUI and utility libraries (@url{https://www.qt.io}).  Qt is required for
-building the GUI.  It is a large framework, but the only components
+building the GUI@.  It is a large framework, but the only components
 required are the GUI, core, and network modules.
 
 @item SuiteSparse
@@ -419,14 +419,6 @@
 You may also want to build a shared version of @code{libstdc++}, if your
 system doesn't already have one.
 
-@item --enable-dl
-Use @code{dlopen} and friends to make Octave capable of dynamically
-linking externally compiled functions (this is the default if
-@option{--enable-shared} is specified).  This option only works on
-systems that actually have these functions.  If you plan on using this
-feature, you should probably also use @option{--enable-shared} to reduce
-the size of your @file{.oct} files.
-
 @item --with-blas=<lib>
 By default, configure looks for the best @sc{blas} matrix libraries on
 your system, including optimized implementations such as the free ATLAS
--- a/doc/interpreter/interpimages.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/interpimages.m	Thu Dec 20 17:18:56 2018 -0500
@@ -99,7 +99,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/doc/interpreter/linalg.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/linalg.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -183,6 +183,8 @@
 
 @DOCSTRING(ordschur)
 
+@DOCSTRING(ordeig)
+
 @DOCSTRING(subspace)
 
 @DOCSTRING(svd)
--- a/doc/interpreter/mkoctfile.1	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/mkoctfile.1	Thu Dec 20 17:18:56 2018 -0500
@@ -70,7 +70,7 @@
 Pass flags to the compiler such as \fB\-Wa,\fP\fIOPTION\fP.
 .TP
 .B \-Wl,...
-Pass flags to the linker such as \fB\-Wl,-rpath=...\fP
+Pass flags to the linker such as \fB\-Wl,\-rpath=...\fP
 .TP
 .B \-M\fR,\fB \-\-depend
 Generate dependency files (.d) for C and C++ source files.
@@ -78,10 +78,10 @@
 .B \-c
 Compile but do not link.
 .TP
-.B \-\-link-stand-alone
+.B \-\-link\-stand\-alone
 Link a stand-alone executable file.
 .TP
-.B \-s\fR,\fB --strip
+.B \-s\fR,\fB \-\-strip
 Strip the output file.
 .TP
 .B \-\-mex
@@ -92,40 +92,91 @@
 specified) unless linking a stand-alone executable.
 .TP
 .B \-p \fIVAR\fP\fR,\fB \-\-print \fIVAR\fP
-Print configuration variable \fIVAR\fP.  Recognized variables are:
+Print configuration variable \fIVAR\fP.  There are three categories of
+variables:
+.IP
+Octave configuration variables that users may override with environment
+variables.  These are used in commands that mkoctfile executes.
+.RS
+.Vb
+    ALL_CFLAGS                  LAPACK_LIBS
+    ALL_CXXFLAGS                LDFLAGS
+    ALL_FFLAGS                  LD_CXX
+    ALL_LDFLAGS                 LD_STATIC_FLAG
+    BLAS_LIBS                   LFLAGS
+    CC                          LIBDIR
+    CFLAGS                      LIBOCTAVE
+    CPICFLAG                    LIBOCTINTERP
+    CPPFLAGS                    OCTAVE_LINK_OPTS
+    CXX                         OCTINCLUDEDIR
+    CXXFLAGS                    OCTAVE_LIBS
+    CXXPICFLAG                  OCTAVE_LINK_DEPS
+    DL_LD                       OCTLIBDIR
+    DL_LDFLAGS                  OCT_LINK_DEPS
+    F77                         OCT_LINK_OPTS
+    F77_INTEGER8_FLAG           RDYNAMIC_FLAG
+    FFLAGS                      SPECIAL_MATH_LIB
+    FPICFLAG                    XTRA_CFLAGS
+    INCFLAGS                    XTRA_CXXFLAGS
+    INCLUDEDIR
+.Ve
+.RE
+.IP
+Octave configuration variables as above, but currently unused by mkoctfile.
 .RS
 .Vb
-    ALL_CFLAGS                FFTW3F_LDFLAGS
-    ALL_CXXFLAGS              FFTW3F_LIBS
-    ALL_FFLAGS                FLIBS
-    ALL_LDFLAGS               FPICFLAG
-    AR                        INCFLAGS
-    BLAS_LIBS                 LAPACK_LIBS
-    CC                        LDFLAGS
-    CFLAGS                    LD_CXX
-    CPICFLAG                  LD_STATIC_FLAG
-    CPPFLAGS                  LFLAGS
-    CXX                       LIBOCTAVE
-    CXXFLAGS                  LIBOCTINTERP
-    CXXPICFLAG                LIBS
-    DEPEND_EXTRA_SED_PATTERN  OCTAVE_LIBS
-    DEPEND_FLAGS              OCTAVE_LINK_DEPS
-    DL_LD                     OCT_LINK_DEPS
-    DL_LDFLAGS                RANLIB
-    EXEEXT                    RDYNAMIC_FLAG
-    F77                       READLINE_LIBS
-    F77_INTEGER_8_FLAG        SED
-    FFLAGS                    XTRA_CFLAGS
-    FFTW3_LDFLAGS             XTRA_CXXFLAGS
+    AR
+    DEPEND_EXTRA_SED_PATTERN
+    DEPEND_FLAGS
+    FFTW3F_LDFLAGS
+    FFTW3F_LIBS
+    FFTW3_LDFLAGS
     FFTW3_LIBS
+    FFTW_LIBS
+    FLIBS
+    LIBS
+    RANLIB
+    READLINE_LIBS
+.Ve
+.RE
+.IP
+Octave configuration variables that are provided for informational purposes
+only.  Except for OCTAVE_HOME and OCTAVE_EXEC_HOME, users may not override
+these variables.
+.IP
+If OCTAVE_HOME or OCTAVE_EXEC_HOME are set in the environment, then other
+variables are adjusted accordingly with OCTAVE_HOME or OCTAVE_EXEC_HOME
+substituted for the original value of the directory specified by the
+\-\-prefix or \-\-exec\-prefix options that were used when Octave was
+configured.
+.RS
+.Vb
+    API_VERSION                 LOCALFCNFILEDIR
+    ARCHLIBDIR                  LOCALOCTFILEDIR
+    BINDIR                      LOCALSTARTUPFILEDIR
+    CANONICAL_HOST_TYPE         LOCALVERARCHLIBDIR
+    DATADIR                     LOCALVERFCNFILEDIR
+    DATAROOTDIR                 LOCALVEROCTFILEDIR
+    DEFAULT_PAGER               MAN1DIR
+    EXEC_PREFIX                 MAN1EXT
+    EXEEXT                      MANDIR
+    FCNFILEDIR                  OCTAVE_EXEC_HOME
+    IMAGEDIR                    OCTAVE_HOME
+    INFODIR                     OCTDATADIR
+    INFOFILE                    OCTDOCDIR
+    LIBEXECDIR                  OCTFILEDIR
+    LOCALAPIARCHLIBDIR          OCTFONTSDIR
+    LOCALAPIFCNFILEDIR          STARTUPFILEDIR
+    LOCALAPIOCTFILEDIR          VERSION
+    LOCALARCHLIBDIR
 .Ve
 .RE
 .TP
-.B \-v\fR,\fB --verbose
+.B \-v\fR,\fB \-\-verbose
 Echo commands as they are executed.
 .TP
 .B file
-Compile or link file.  Recognized file types are
+Compile or link file.  Recognized file types are:
 .RS
 .Vb
    .c    C source
--- a/doc/interpreter/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -15,6 +15,7 @@
   %reldir%/plot-uicontextmenuproperties.texi \
   %reldir%/plot-uipanelproperties.texi \
   %reldir%/plot-uicontrolproperties.texi \
+  %reldir%/plot-uitableproperties.texi \
   %reldir%/plot-uitoolbarproperties.texi \
   %reldir%/plot-uipushtoolproperties.texi \
   %reldir%/plot-uitoggletoolproperties.texi
@@ -27,55 +28,60 @@
   mv $@-t $@
 endef
 
-%reldir%/plot-axesproperties.texi: %reldir%/genpropdoc.m
+GRAPHICS_PROPS_SRC = libinterp/corefcn/graphics.in.h libinterp/corefcn/genprops.awk
+
+%reldir%/plot-axesproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,axes)
 
-%reldir%/plot-figureproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-figureproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,figure)
 
-%reldir%/plot-imageproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-imageproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,image)
 
-%reldir%/plot-lightproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-lightproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,light)
 
-%reldir%/plot-lineproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-lineproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,line)
 
-%reldir%/plot-patchproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-patchproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,patch)
 
-%reldir%/plot-rootproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-rootproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,root)
 
-%reldir%/plot-surfaceproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-surfaceproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,surface)
 
-%reldir%/plot-textproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-textproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,text)
 
-%reldir%/plot-uimenuproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uimenuproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uimenu)
 
-%reldir%/plot-uibuttongroupproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uibuttongroupproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uibuttongroup)
 
-%reldir%/plot-uicontextmenuproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uicontextmenuproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uicontextmenu)
 
-%reldir%/plot-uipanelproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uipanelproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uipanel)
 
-%reldir%/plot-uicontrolproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uicontrolproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uicontrol)
 
-%reldir%/plot-uitoolbarproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uitableproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
+	$(AM_V_GEN)$(call gen-propdoc-texi,uitable)
+
+%reldir%/plot-uitoolbarproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uitoolbar)
 
-%reldir%/plot-uipushtoolproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uipushtoolproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uipushtool)
 
-%reldir%/plot-uitoggletoolproperties.texi: %reldir%/genpropdoc.m
+%reldir%/plot-uitoggletoolproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,uitoggletool)
 
 dist_man_MANS = \
@@ -323,6 +329,7 @@
 if AMCOND_BUILD_QT_DOCS
 DOC_TARGETS += \
   $(OCTAVE_QTHELP_FILES)
+
 endif
 
 ## Distribute both OCTAVE_CSS and HTMLDIR_CSS so that the rules for
@@ -422,6 +429,13 @@
 
 endif
 
+## These actions should happen even if we are not building docs
+
+include doc/interpreter/images.mk
+
+$(srcdir)/%reldir%/images.mk: $(srcdir)/%reldir%/config-images.sh $(srcdir)/%reldir%/images.awk $(srcdir)/%reldir%/images
+	$(AM_V_GEN)$(SHELL) $(srcdir)/%reldir%/config-images.sh $(top_srcdir)
+
 DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
 
 ## The doc-cache file can be built without TeX but it does require
@@ -443,19 +457,19 @@
 
 %reldir%/undocumented_list:
 	rm -f $@-t $@
-	-cd $(srcdir)/doc/interpreter; $(PERL) ./doccheck/mk_undocumented_list > $(@F)-t
+	-cd $(srcdir)/%reldir%; $(PERL) ./doccheck/mk_undocumented_list > $(@F)-t
 	mv $@-t $@
 .PHONY: %reldir%/undocumented_list
 
 SPELLCHECK_FILES = $(MUNGED_TEXI_SRC:.texi=.scheck)
 
 %.scheck: %.texi | %reldir%/$(octave_dirstamp)
-	cd $(srcdir)/doc/interpreter; ./doccheck/spellcheck $(<F) > $(@F)-t
+	cd $(srcdir)/%reldir%; ./doccheck/spellcheck $(<F) > $(@F)-t
 	mv $@-t $@
 	[ -s $@ ] || rm -f $@
 
 spellcheck: $(SPELLCHECK_FILES)
-	@cd $(srcdir)/doc/interpreter ; \
+	@cd $(srcdir)/%reldir% ; \
 	if ls *.scheck >/dev/null 2>&1 ; then \
 		echo "Spellcheck failed"; \
 		echo "Review the following files:"; \
--- a/doc/interpreter/munge-texi.pl	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/munge-texi.pl	Thu Dec 20 17:18:56 2018 -0500
@@ -84,6 +84,7 @@
     }
 
     $func =~ s/^@/@@/;   # Texinfo uses @@ to produce '@'
+    $func =~ s/\./_/g;   # Texinfo doesn't like '.' in node names
     $docstring =~ s/^$tex_delim$/\@anchor{XREF$func}/m;
     print $docstring,"\n";
 
@@ -133,7 +134,9 @@
       foreach $func (split (/,/, $func_list))
       {
         $func =~ s/^@/@@/;   # Texinfo uses @@ to produce '@'
-        $repl .= "\@ref{XREF$func,,$func}, ";
+        $node = $func;
+        $node =~ s/\./_/g;  # Texinfo doesn't like '.' in node names
+        $repl .= "\@ref{XREF$node,,$func}, ";
       }
       substr($repl,-2) = "";   # Remove last ', '
       $_ = "\@seealso{$repl}$rest_of_line";
--- a/doc/interpreter/octave.texi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/octave.texi	Thu Dec 20 17:18:56 2018 -0500
@@ -93,7 +93,7 @@
 @c        is automatically generated by Automake in version-octave.texi.
 @c        Need to use sed to strip off MINOR.PATCH numbers and place
 @c        the results in a new file, and then @include that new file.
-@subtitle Edition 4 for Octave version @value{VERSION}
+@subtitle Edition 5 for Octave version @value{VERSION}
 @subtitle @value{UPDATED-MONTH}
 @sp 2
 @multitable @columnfractions 0.4 0.025 0.65
@@ -716,6 +716,7 @@
 Statistics
 
 * Descriptive Statistics::
+* Statistics on Sliding Windows of Data::
 * Basic Statistical Functions::
 * Correlation and Regression Analysis::
 * Distributions::
@@ -883,7 +884,7 @@
 
 * Making Java Classes Available::
 * How to use Java from within Octave::
-* Passing parameters to the JVM::
+* Set up the JVM::
 * Java Interface Functions::
 
 Test and Demo Functions
--- a/doc/interpreter/oop.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/oop.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -150,7 +150,13 @@
 @DOCSTRING(ismethod)
 
 @noindent
-For example:
+For a polynomial class it makes sense to have a method to compute its roots.
+
+@example
+@EXAMPLEFILE(@polynomial/roots.m)
+@end example
+
+We can check for the existence of the @code{roots}-method by calling:
 
 @example
 @group
--- a/doc/interpreter/plot.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/plot.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -1108,6 +1108,10 @@
 
 @DOCSTRING(hgload)
 
+@DOCSTRING(openfig)
+
+@DOCSTRING(savefig)
+
 @node Interacting with Plots
 @subsection Interacting with Plots
 
@@ -1480,6 +1484,7 @@
 * Uicontextmenu Properties::
 * Uipanel Properties::
 * Uicontrol Properties::
+* Uitable Properties::
 * Uitoolbar Properties::
 * Uipushtool Properties::
 * Uitoggletool Properties::
@@ -1618,6 +1623,14 @@
 
 @include plot-uicontrolproperties.texi
 
+@node Uitable Properties
+@subsubsection Uitable Properties
+@cindex uitable properties
+
+The @code{uitable} properties are:
+
+@include plot-uitableproperties.texi
+
 @node Uitoolbar Properties
 @subsubsection Uitoolbar Properties
 @prindex @sortas{@ Uitoolbar Properties} Uitoolbar Properties
--- a/doc/interpreter/preface.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/preface.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -99,7 +99,7 @@
 
 @item
 The industrial members of the Texas-Wisconsin Modeling and Control
-Consortium (TWMCC).
+Consortium (@nospell{TWMCC}).
 
 @item
 The @nospell{Paul A. Elfers} Endowed Chair in Chemical Engineering at the
--- a/doc/interpreter/splineimages.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/splineimages.m	Thu Dec 20 17:18:56 2018 -0500
@@ -189,7 +189,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/doc/interpreter/stats.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/stats.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -47,6 +47,7 @@
 
 @menu
 * Descriptive Statistics::
+* Statistics on Sliding Windows of Data::
 * Basic Statistical Functions::
 * Correlation and Regression Analysis::
 * Distributions::
@@ -107,6 +108,36 @@
 
 @DOCSTRING(statistics)
 
+@node Statistics on Sliding Windows of Data
+@section Statistics on Sliding Windows of Data
+
+It is often useful to calculate descriptive statistics over a subsection (i.e., window) of a full dataset.  Octave provides the function @code{movfun} which
+will call an arbitrary function handle with windows of data and accumulate
+the results.  Many of the most commonly desired functions, such as the moving
+average over a window of data (@code{movmean}), are already provided.
+
+@DOCSTRING(movfun)
+
+@DOCSTRING(movslice)
+
+@DOCSTRING(movmad)
+
+@DOCSTRING(movmax)
+
+@DOCSTRING(movmean)
+
+@DOCSTRING(movmedian)
+
+@DOCSTRING(movmin)
+
+@DOCSTRING(movprod)
+
+@DOCSTRING(movstd)
+
+@DOCSTRING(movsum)
+
+@DOCSTRING(movvar)
+
 @node Basic Statistical Functions
 @section Basic Statistical Functions
 
--- a/doc/interpreter/strings.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/strings.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -53,6 +53,9 @@
 produces the string whose contents are @samp{foobarbaz}.  @xref{Numeric Data
 Types}, for more information about creating matrices.
 
+While strings can in principal store arbitrary content, most functions expect
+them to be UTF-8 encoded Unicode strings.
+
 @menu
 * Escape Sequences in String Constants::
 * Character Arrays::
@@ -468,6 +471,8 @@
 
 @DOCSTRING(untabify)
 
+@DOCSTRING(unicode_idx)
+
 @node String Conversions
 @section String Conversions
 
--- a/doc/interpreter/system.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/system.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -196,8 +196,12 @@
 
 @DOCSTRING(fileattrib)
 
+@DOCSTRING(isfile)
+
 @DOCSTRING(isdir)
 
+@DOCSTRING(isfolder)
+
 @DOCSTRING(readdir)
 
 @DOCSTRING(glob)
--- a/doc/interpreter/var.txi	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/interpreter/var.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -67,7 +67,9 @@
 
 @DOCSTRING(isvarname)
 
-@DOCSTRING(genvarname)
+@DOCSTRING(matlab.lang.makeValidName)
+
+@DOCSTRING(matlab.lang.makeUniqueStrings)
 
 @DOCSTRING(namelengthmax)
 
@@ -367,10 +369,12 @@
 @noindent
 Since having this variable in memory might slow down other computations,
 it can be necessary to remove it manually from memory.  The @code{clear}
-function allows this.
+or @code{clearvars} functions do this.
 
 @DOCSTRING(clear)
 
+@DOCSTRING(clearvars)
+
 @DOCSTRING(pack)
 
 Information about a function or variable such as its location in the
--- a/doc/refcard/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/doc/refcard/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -44,9 +44,6 @@
 %reldir%/refcard-letter.ps: %reldir%/refcard-letter.dvi
 	-$(AM_V_DVIPS)$(DVIPS) $(AM_V_texinfo) -T 11in,8.5in -o $@ $<
 
-$(srcdir)/doc/interpreter/images.mk: $(srcdir)/doc/interpreter/config-images.sh $(srcdir)/doc/interpreter/images.awk $(srcdir)/doc/interpreter/images
-	$(AM_V_GEN)$(SHELL) $(srcdir)/doc/interpreter/config-images.sh $(top_srcdir)
-
 $(refcard_DVI) : %.dvi : %.tex | %reldir%/$(octave_dirstamp)
 	-$(AM_V_TEX)cd $(@D) && \
 	TEXINPUTS="$(abs_top_srcdir)/doc/refcard:$(TEXINPUTS):" \
--- a/etc/HACKING.md	Tue Dec 04 10:12:41 2018 -0800
+++ b/etc/HACKING.md	Thu Dec 20 17:18:56 2018 -0500
@@ -297,6 +297,94 @@
   - `fntests.m`
        script to run function tests embedded in C++ and .m files.
 
+Release Numbering
+-----------------
+
+Since version 5, Octave uses the following rules for release numbering:
+
+  Version Dev Phase       When
+
+  5.0.0   (experimental)  active development of Octave 5 on default branch
+  5.0.1   (pre-release)   stabilization period of Octave 5 on stable branch
+  6.0.0   (experimental)  active development of Octave 6 on default branch
+  5.1.0   (release)       first release of Octave 5 from stable branch
+  5.1.1   (pre-release)   bug fixing on stable branch after 5.1.0 release
+  5.2.0   (release)       second release of Octave 5 from stable branch
+  5.2.1   (pre-release)   bug fixing on stable branch after 5.2.0 release
+  ...
+
+To summarize, the first release of Octave 5 will be Octave 5.1.0 while
+development snapshots will be Octave 5.0.0 and snapshots from the
+release branch Octave 5.n.1.
+
+With this numbering scheme:
+
+  * Any version X.0.0 means "this is an experimental development
+    version".
+
+  * Any version X.Y.1 means, "this is a pre-release version meant
+    for bug fixing and testing".
+
+  * Any version X.Y.0 with Y != 0 means "this is a released version".
+
+Shared Library Versioning
+-------------------------
+
+Version numbers for the liboctave, liboctinterp, and liboctgui shared
+libraries are set in the module.mk files in the top-level directory for
+each library using the variables
+
+  %canon_reldir%_%canon_reldir%_current
+  %canon_reldir%_%canon_reldir%_revision
+  %canon_reldir%_%canon_reldir%_age
+
+The rules for updating these version numbers are:
+
+  * Start with version information of ‘0:0:0’ for each libtool library.
+
+  * Update the version information only immediately before a public
+    release of your software.  More frequent updates are unnecessary,
+    and only guarantee that the current interface number gets larger
+    faster.
+
+  * If the library source code has changed at all since the last update,
+    then increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
+
+  * If any interfaces have been added, removed, or changed since the
+    last update, increment current, and set revision to 0.
+
+  * If any interfaces have been added since the last public release,
+    then increment age.
+
+  * If any interfaces have been removed or changed since the last public
+    release, then set age to 0.
+
+Never try to set the interface numbers so that they correspond to the
+Octave version number.  This is an abuse that only fosters
+misunderstanding of the purpose of library versions.
+
+The following explanation may help to understand the above rules a bit
+better: consider that there are three possible kinds of reactions from
+users of your library to changes in a shared library:
+
+  * Programs using the previous version may use the new version as
+    drop-in replacement, and programs using the new version can also
+    work with the previous one.  In other words, no recompiling nor
+    relinking is needed.  In this case, bump revision only, don’t touch
+    current nor age.
+
+  * Programs using the previous version may use the new version as
+    drop-in replacement, but programs using the new version may use APIs
+    not present in the previous one.  In other words, a program linking
+    against the new version may fail with unresolved symbols if linking
+    against the old version at runtime: set revision to 0, bump current
+    and age.
+
+  * Programs may need to be changed, recompiled, and relinked in order
+    to use the new version.  Bump current, set revision and age to 0.
+
+These guidelines also appear in the automake manual.
+
 
 ################################################################################
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/NEWS.4	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,1350 @@
+Summary of important user-visible changes for version 4.4 (2018-04-30):
+----------------------------------------------------------------------
+
+ ** A graphical Variable Editor has been added to the GUI interface.
+    It uses a spreadsheet-like interface for quick, intuitive editing
+    of variables.  The Variable Editor is launched by double-clicking
+    on a variable name in the Workspace Window or by typing
+    "openvar VARIABLE_NAME" in the Command Window.
+
+ ** On systems with 64-bit pointers, --enable-64 is now the default and
+    Octave always uses 64-bit indexing.  However, if the configure
+    script determines that the BLAS library uses 32-bit integers, then
+    operations using the following libraries are limited to arrays with
+    dimensions that are smaller than 2^31 elements:
+
+      BLAS  LAPACK  QRUPDATE  SuiteSparse  ARPACK
+
+    Additionally, the following libraries use "int" internally, so
+    maximum problem sizes are always limited:
+
+      glpk  Qhull
+
+ ** The octave command no longer starts the GUI by default.  Most users
+    starting Octave from a shell were expecting the command line
+    interface, and desktop launchers already required the `--force-gui'
+    option.  With this change, desktop launchers should be modified to
+    use the new option `--gui'.  The previous `--force-gui' option will
+    continue to work, and maps to `--gui', but it will be removed in
+    Octave 6.
+
+ ** A known bug in Qt (https://bugreports.qt.io/browse/QTBUG-55357) is
+    addressed by limiting GUI sub-panel relocation capabilities for Qt
+    versions in the range >= 5.6.1 and < 5.7.1.  However, this may not
+    thoroughly avoid issues on all platforms.
+
+ ** A new container data type--containers.Map--is available.  Map is a
+    key/value storage container (a.k.a, a hash) that efficiently allows
+    storing and retrieving values by name, rather than by position which
+    is how arrays work.
+
+ ** The bareword "import" is now recognized in scripts and functions.
+    However, the functionality to import functions and classes from
+    other namespaces into the local scope has not yet been implemented.
+    Attempting to use "import" will provoke an error message.
+
+ ** hex2num and num2hex now work for integer and char types and num2hex
+    may optionally return a cell array of strings instead of a character
+    array.  If given a cell array of strings, hex2num now returns a
+    numeric array of the same size as the input cell array.  Previously,
+    hex2num would accept a cell array of strings of arbitrary dimension
+    but would always return a column vector.
+
+ ** New special functions cosint, sinint, and gammaincinv have been added.
+
+ ** Special functions in Octave have been rewritten for larger input
+    domains, better accuracy, and additional options.
+    * gammainc now accepts negative real values for X.
+    * improved accuracy for gammainc, betainc, betaincinv, expint.
+    * gammainc has new options "scaledlower" and "scaledupper".
+    * betainc, betaincinv have new option "upper".
+
+ ** The "names" option used in regular expressions now returns a struct
+    array, rather than a struct with a cell array for each field.  This
+    change was made for Matlab compatibility.
+
+ ** The quadcc function now uses both absolute tolerance and relative
+    tolerance to determine the stopping criteria for an integration.
+    To be compatible with other quadXXX functions, such as quadgk, the
+    calling syntax has changed to
+
+      quadcc (f, a, b, [AbsTol, [RelTol]])
+
+    To update existing code, change instances of RelTol to [0, RelTol].
+
+      quadcc (f, a, b, tol) => quadcc (f, a, b, [0, tol])
+
+    A warning that a single tolerance input is now interpreted as an
+    absolute tolerance will be issued in Octave versions 4.4 and 5,
+    after which it will be removed.  The warning has ID
+    "Octave:quadcc:RelTol-conversion" and can be disabled with
+
+      warning ("off", "Octave:quadcc:RelTol-conversion")
+
+ ** The qr function now returns a standard factorization unless
+    explicitly instructed to perform an economy factorization by using a
+    final argument of 0.
+
+ ** The Qt graphics toolkit now supports offscreen printing without osmesa
+    if Octave was built with Qt >= 5.1.
+
+ ** The built-in pager for display of large data is now disabled by
+    default.  To re-enable it for every Octave session add the following
+    to your .octaverc file:
+
+      more on;
+
+ ** The FLTK toolkit is no longer prioritized for development.  The
+    number of Octave Maintainers is too small to support three different
+    graphic toolkits.  New development will target the Qt toolkit.
+    While no longer prioritized, the FLTK toolkit is not deprecated and
+    there is no schedule for its removal.
+
+ ** The graphic object property "PickableParts" has been implemented
+    which controls whether an object can accept mouse clicks.
+
+ ** The graphic object property "Interruptible" has been fully
+    implemented which controls whether a running callback function can
+    be interrupted by another callback function.
+
+ ** The graphic object property "HitTest" has been updated to be fully
+    compatible with Matlab.
+
+ ** Text objects now implement the properties "BackgroundColor",
+    "EdgeColor", "LineStyle", "LineWidth", and "Margin".
+
+ ** An initial implementation of alpha transparency has been made for
+    patch and surface objects.  Printing to svg and pdf is supported.
+
+ ** ishandle now returns true for both graphics handle objects and
+    Java objects.  The latter change was made for Matlab compatibility.
+    Use ishghandle or isgraphics if it is important not to include Java
+    objects.
+
+ ** The pkg command now accepts a URL as an argument, allowing a valid
+    Octave package to be installed from any remote host with one command,
+    for example
+
+      pkg install https://example.org/download/example-package.tar.gz
+
+ ** The following statistical functions have been moved from core
+    Octave to the statistics package available from Octave Forge.
+
+    BASE
+      cloglog
+      logit
+      prctile
+      probit
+      qqplot
+      table  (renamed to crosstab)
+
+    DISTRIBUTIONS
+      betacdf
+      betainv
+      betapdf
+      betarnd
+      binocdf
+      binoinv
+      binopdf
+      binornd
+      cauchy_cdf
+      cauchy_inv
+      cauchy_pdf
+      cauchy_rnd
+      chi2cdf
+      chi2inv
+      chi2pdf
+      chi2rnd
+      expcdf
+      expinv
+      exppdf
+      exprnd
+      fcdf
+      finv
+      fpdf
+      frnd
+      gamcdf
+      gaminv
+      gampdf
+      gamrnd
+      geocdf
+      geoinv
+      geopdf
+      geornd
+      hygecdf
+      hygeinv
+      hygepdf
+      hygernd
+      kolmogorov_smirnov_cdf
+      laplace_cdf
+      laplace_inv
+      laplace_pdf
+      laplace_rnd
+      logistic_cdf
+      logistic_inv
+      logistic_pdf
+      logistic_rnd
+      logncdf
+      logninv
+      lognpdf
+      lognrnd
+      nbincdf
+      nbininv
+      nbinpdf
+      nbinrnd
+      normcdf
+      norminv
+      normpdf
+      normrnd
+      poisscdf
+      poissinv
+      poisspdf
+      poissrnd
+      stdnormal_cdf
+      stdnormal_inv
+      stdnormal_pdf
+      stdnormal_rnd
+      tcdf
+      tinv
+      tpdf
+      trnd
+      unidcdf
+      unidinv
+      unidpdf
+      unidrnd
+      unifcdf
+      unifinv
+      unifpdf
+      unifrnd
+      wblcdf
+      wblinv
+      wblpdf
+      wblrnd
+      wienrnd
+
+    MODELS
+      logistic_regression
+
+    TESTS
+      anova
+      bartlett_test
+      chisquare_test_homogeneity
+      chisquare_test_independence
+      cor_test
+      f_test_regression
+      hotelling_test
+      hotelling_test_2
+      kolmogorov_smirnov_test
+      kolmogorov_smirnov_test_2
+      kruskal_wallis_test
+      manova
+      mcnemar_test
+      prop_test_2
+      run_test
+      sign_test
+      t_test
+      t_test_2
+      t_test_regression
+      u_test
+      var_test
+      welch_test
+      wilcoxon_test
+      z_test
+      z_test_2
+
+ ** The following image functions have been moved from core Octave to
+    the image package available from Octave Forge.
+
+      ntsc2rgb
+      rgb2ntsc
+
+ ** Other new functions added in 4.4:
+
+      bounds
+      camlookat
+      camorbit
+      campos
+      camroll
+      camtarget
+      camup
+      camva
+      camzoom
+      corrcoef
+      cosint
+      decic
+      erase
+      gammaincinv
+      getframe
+      groot
+      gsvd
+      hgtransform
+      humps
+      integral
+      integral2
+      integral3
+      isgraphics
+      isstring
+      mad
+      ode15i
+      ode15s
+      openvar
+      quad2d
+      repelem
+      rgb2gray
+      rticks
+      sinint
+      tfqmr
+      thetaticks
+      vecnorm
+      winqueryreg
+      xticklabels
+      xticks
+      yticklabels
+      yticks
+      zticklabels
+      zticks
+
+ ** Deprecated functions.
+
+    The following functions have been deprecated in Octave 4.4 and will
+    be removed from Octave 6 (or whatever version is the second major
+    release after 4.4):
+
+      Function             | Replacement
+      ---------------------|------------------
+      chop                 | sprintf for visual results
+      desktop              | isguirunning
+      tmpnam               | tempname
+      toascii              | double
+      java2mat             | __java2mat__
+
+
+ ** The following functions were deprecated in Octave 4.0 and have been
+    removed from Octave 4.4.
+
+      allow_noninteger_range_as_index
+      bicubic
+      delaunay3
+      do_braindead_shortcircuit_evaluation
+      dump_prefs
+      find_dir_in_path
+      finite
+      fmod
+      fnmatch
+      gmap40
+      loadaudio
+      luinc
+      mouse_wheel_zoom
+      nfields
+      octave_tmp_file_name
+      playaudio
+      saveaudio
+      setaudio
+      syl
+      usage
+
+ ** The "Octave:undefined-return-values" warning ID is obsolete.  Octave
+    now throws an error for any attempts to assign undefined values that
+    might be returned from functions.
+
+ ** Deprecated graphics properties.
+
+    The following properties or allowed corresponding values have been
+    deprecated in Octave 4.4 and will be removed from Octave 6 (or whatever
+    version is the second major release after 4.4):
+
+      Object               | Property                | Value
+      ---------------------|-------------------------|-------------------
+      figure               | doublebuffer            |
+                           | mincolormap             |
+                           | wvisual                 |
+                           | wvisualmode             |
+                           | xdisplay                |
+                           | xvisual                 |
+                           | xvisualmode             |
+      axes                 | drawmode                |
+      annotation           | edgecolor ("rectangle") |
+      text                 | fontweight              | "demi" and "light"
+      uicontrol            | fontweight              | "demi" and "light"
+      uipanel              | fontweight              | "demi" and "light"
+      uibuttongroup        | fontweight              | "demi" and "light"
+
+ ** The rectangle and ellipse annotation property "edgecolor" has been
+    deprecated and will be removed from Octave 6 (or whatever version
+    is the second major release after 4.4).  Use the property "color"
+    instead.
+
+ ** The header file oct-alloc.h has been removed along with the macros
+    that it defined (DECLARE_OCTAVE_ALLOCATOR, DEFINE_OCTAVE_ALLOCATOR,
+    and DEFINE_OCTAVE_ALLOCATOR2).
+
+
+Summary of bugs fixed for version 4.2.2 (2018-03-13):
+----------------------------------------------------
+
+Using the bug numbers listed below, find bug reports on the web using
+the URL https://savannah.gnu.org/bugs/?NNNNN
+
+ ** make leftdiv work for scalar \ int-matrix (bug #51682)
+
+ ** inputdlg.m: Avoid crash when prompt and defaults sizes differ (bug #53209)
+
+ ** tie octave_classdef::numel method to "numel" user override method
+    (bug #46571)
+
+ ** fix performance of Sparse fsolve for complex sparse matrices (bug #53140)
+
+ ** fix performance of Sparse fsolve (bug #53140)
+
+ ** octave.desktop.in: No repetition of Name in Comment field and start I10n
+    (bug #53078)
+
+ ** don't create partially invalid graphic objects (bug #52904)
+
+ ** test for incorrect regexprep on ARM platforms (bug #52810)
+
+ ** fix incorrect regexprep on ARM platforms (bug #52810)
+
+ ** correctly handle reading of characters >127 in scanf family (bug #52681)
+
+ ** fix addpath for UNC paths on Windows (bug #51268)
+
+ ** protect being-deleted objects on figure list from second deletion
+    (bug #52666)
+
+ ** dlmwrite.m: Close fid if filename is only one char long (bug #52679)
+
+ ** set gnuplot color data to half output range when autoscaling zero input
+    range (bug #52624)
+
+ ** add polarplot() to the list of unimplemented functions (bug #52643)
+
+ ** configure.ac: Fix test for Java version (bug #52617)
+
+ ** for gnuplot toolkit, do not map TrueColor data to colormap size (bug #52599)
+
+ ** make wheel scroll behave more consistently in pan mode (bug #52588)
+
+ ** make gnuplot color have three components for interpolated edge color
+    (bug #52595)
+
+ ** simplify gnuplot toolkit scripts for image/non-image data plots (bug #52589)
+
+ ** fix concatenation of empty char matrices with other strings (bug #52542)
+
+ ** build: Fix compiling OCTAVE_ARPACK_OK_2 Fortran code (bug #52425)
+
+ ** trisurf.m, trimesh.m: Fix input validation (bug #48109)
+
+ ** allow uncommenting in editor when line begins with whitespace (bug #52406)
+
+ ** do not extend selection when indenting/commenting in editor (bug #45610)
+
+ ** remove all delimiters from whitespace list in textscan function (bug #52479)
+
+ ** calculate 1-norm of matrices to assess whether NaN or Inf are present
+    (bug #39000)
+
+ ** prevent extra ampersand under KDE in cd-or-add-to-path dialog (bug #52423)
+
+ ** plotyy.m: Fix error when using FUN2 argument (bug #48115)
+
+ ** check ARPACK library for buggy behavior in configure (bug #52425)
+
+ ** fix printing integer type images (bug #51558)
+
+ ** fix segfault in delaunayn when Qhull memory is not properly cleared
+    (bug #52410)
+
+ ** fix segfault with CHOLMOD library and empty matrices (bug #52365)
+
+ ** tag global and persistent symbols as variables when parsing (bug #52363)
+
+ ** properly restore the input stream pointer at end of textscan (bug #52116 et
+    al.)
+
+ ** fix building with Qt4 for Windows (bug #52237)
+
+ ** ensure numeric values are passed for the axes "clim" property (bug #52053)
+
+ ** avoid abort on exit from GUI (bug #50664)
+
+ ** correct auto limits on log axes with negative and zero values (bug #51861)
+
+ ** fix warning in quadgk with zero size interval (bug #51867)
+
+ ** sparse: correctly handle scalar column index (bug #51880)
+
+ ** fix segfault in ichol under certain conditions (bug #51736)
+
+ ** configure: ensure empty pkg-config results are actually empty (bug #51680)
+
+ ** fix 'legend hide' for gnuplot (bug #50483)
+
+ ** qqplot.m: Fix typo in input validation (bug #51458)
+
+ ** add possible '\r' to smartindent regex exprepression (Bug #51279)
+
+ ** make strncmp case sensitive again (bug #51384)
+
+ ** fix possible infinite loop in normest1.m (bug #51241)
+
+ ** also run unwind protect cleanup code on interrupt exceptions (bug #51209)
+
+ ** fix crash when inverting complex matrices with NaNs (bug #51198)
+
+ ** improve accuracy of residue for inputs with very different magnitudes
+    (bug #51148)
+
+ ** publish.m: Fix corruption of results for some code inputs (bug #51178)
+
+ ** residue.m: Remove code that filters out small return values (bug #34266, bug
+    #49291)
+
+ ** avoid possible double free at interpreter exit (bug #51088)
+
+ ** show stack trace for errors in command line and startup files (bug #49346)
+
+ ** interp1.m: Return NA for all columns which are out of bounds (bug #51030)
+
+ ** use idx_type for dimensions instead of int (bug #50934)
+
+ ** show stack trace for wrong type arg errors (bug #50894)
+
+ ** let mouse selection of Qt figures update "currentfigure" (bug #50666)
+
+ ** disable qscintilla editor drag and drop so parent will handle it (Bug
+    #50559)
+
+ ** quadgk.m: Correct error messages which point to quadv (bug #50604)
+
+ ** set version on AppUserModelId (Bug #50428)
+
+ ** version-rcfile: Don't try to execute startup directory, only startup.m
+    (bug #50593)
+
+ ** dlmread: Return empty matrix when requested range is outside data
+    (bug #50102)
+
+ ** fix eigs for generalized nonsymmetric and shift-invert problems (bug #39573)
+
+ ** fix eigs for the generalized eigenvalue problem (bug #50546)
+
+ ** datetick.m: Fix uneven range bugs (bug #50493)
+
+ ** datenum.m: Correct calculation for fractional leap years (bug #50508)
+
+ ** datenum.m: Allow horizontal vectors of dates with fractional months
+    (bug #50508)
+
+ ** datenum.m: Accept legal input of vectors with fractional months (bug #50508)
+
+ ** fix the anchor position in the info text of the doc browser (bug #50422)
+
+ ** fix order of legend labels with plotyy axes (bug #50497)
+
+ ** correct hggroup plot legends for gnuplot toolkit, add legend demo 17 items
+    (bug #49341)
+
+ ** for gnuplot graphics toolkit, show only one key entry for errorbars
+    (bug #49260)
+
+ ** fix compilation of jit caused by cset d0562b3159c7 (bug #50398)
+
+ ** remove inline keyword on file_stat destructor which breaks MacOS compilation
+    (bug #50234)
+
+Documentation bugs fixed:
+
+ ** playblocking.m: Correct documentation about start and limits inputs
+    (bug #51217)
+
+ ** fix eig output argument description (bug #50524)
+
+ ** remove backslashes before double quotes in m-file docstrings (bug #52870)
+
+ ** tweaks to use single quotes instead of double quotes (bug #52870)
+
+ ** correct fieldname of returned struct in ver (bug #52845)
+
+ ** cleanup @code example in Appendix on test functions (bug #52852)
+
+ ** fixes for signal, image, audio, and OOP chapters (bug #52844)
+
+ ** fix issues in geometry, polynomial, and interpolation chapters (bug #52835)
+
+ ** fix TeX documentation for qp and clarify size of inputs (bug #52829)
+
+ ** correct errors in Diagonal matrix chapter of manual (bug #52814)
+
+ ** replace @math{1e^{XXX}} sequences with raw 1eXXX (bug #52827)
+
+ ** use '...' rather than deprecated '\' for line continuation (bug #52828)
+
+ ** make documentation Sec 26.1 more consistent and Sec 25.4 clearer
+    (bug #52685)
+
+ ** documentation fixes for linspace, logspace, lookup (bug #52785)
+
+ ** atan2d.m: Correct documentation to match atan docstring (bug #52786)
+
+ ** small tweaks to fplot and surfnorm docstrings (bug #52761)
+
+ ** rewrite documentation for Advanced Indexing (bug #52723)
+
+ ** delete extra ']' in scanf docstring (bug #52742)
+
+ ** fix mistaken use of space between function and '(' in documentation
+    (bug #52723)
+
+ ** fix various inconsistencies in manual (bug #52712)
+
+ ** fix typo in cset 8354b505ad6b (bug #52702)
+
+ ** fix inconsistencies with char, strvcat, strread docstrings (bug #52702.
+
+ ** explain Matlab compatibility of fopen modes (bug #52644)
+
+ ** update documentation for keywords to include classdef statements
+    (bug #52591)
+
+ ** fix documentation of third input to lsode() (bug #52664)
+
+ ** clarify quiver/quiver3 documentation when a linestyle is given (bug #52608)
+
+ ** new section about classdef classes with example (bug #44590)
+
+ ** correct surface plot explanation of  meshgridded results of 1 input
+    (bug #52536)
+
+ ** fix definition of Delaunay triangulation in docstrings (bug #52416)
+
+ ** accumarray.m: Add '@' to function handles in docstring (bug #52418)
+
+ ** update manual to explain \deg and \circ symbols (bug #52287)
+
+ ** correct documentation for randg (bug #52118)
+
+ ** add documentation about PCRE library regexp stack overflow (bug #51589)
+
+ ** play.m: Correct documentation about start and limits inputs (bug #51217)
+
+ ** redo docstring for qz (bug #50846)
+
+ ** describe optional install dependencies PortAudio and SUNDIALS (bug #50513)
+
+ ** update CITATION date, version, and permalink to manual (bug #47058)
+
+
+Summary of bugs fixed for version 4.2.1 (2017-02-22):
+----------------------------------------------------
+
+Using the bug numbers listed below, find bug reports on the web using
+the URL https://savannah.gnu.org/bugs/?NNNNN
+
+ ** guarantee returning std::string from tilde_expand functions (bug #50234)
+
+ ** workaround segfault in file_stat (bug #50234)
+
+ ** genpropdoc.m: document more graphics properties (bug #50337)
+
+ ** always fork and exec when starting the gui (bug #49609)
+
+ ** print.m: fix regression with -append option (bug #50318)
+
+ ** don't display legend, colorbar, and annotation axes coordinates
+    (bug #50272)
+
+ ** qp.m: Fix regression with incorrect vector dimensions (bug #50067)
+
+ ** prevent infinite loop in global documentation search (bug #50177)
+
+ ** connect execute command signal in editor constructor (bug #50171)
+
+ ** connect editors execute command signal to the required slot (bug #50171)
+
+ ** check if input is class method before declaring it unimplemented
+    (patch #9238) (bug #49694)
+
+ ** workaround segfault when an error occurs while printing (bug #49779)
+
+ ** axis.m: Do not set plotboxaspectratio to 0 (bug #49755)
+
+ ** don't rethrow exception in destructor (bug #49304)
+
+ ** rethrow octave::exit_exception (bug #49304)
+
+ ** update appdata.xml to follow conventions (bug #49952)
+
+ ** mexproto.h (mxAssert, mxAssertS): ensure operator precedence (bug #50050)
+
+ ** calculate error in solution for ode solvers correctly (bug #49950)
+
+ ** use GetModuleFileName for getting octave path in windows (bug #48671)
+
+ ** use C++ updaters for labels color (bug #49980)
+
+ ** distinguish elements vs. bytes in fread (bug #49699)
+
+ ** move frame2im and im2frame to image/ directory (bug #49939)
+
+ ** fix undefined return argument for more than 2 outputs from ode solver
+    (bug #49890)
+
+ ** fix inv for hermitian matrices (bug #49904)
+
+ ** fix gzip for certain types of gzip files (bug #49760)
+
+ ** fix typo in liboctave version info (bug #49860)
+
+ ** initialize ODE Event function with start time (bug #49846)
+
+ ** allow configure test to succeed without implicit fcn decls (bug #49782)
+
+ ** allow external docstrings from .oct files to be found again (bug #49687)
+
+ ** don't require semicolon between property list elements (bug #49819)
+
+ ** display.m: Correctly display output for non-class objects
+    (bug #49753, #49794)
+
+ ** don't run publish.tst unless OSMESA or gnuplot are available (bug #49767)
+
+ ** find help for function aliases again (bug #49687)
+
+ ** legend.m: backport cset 7184b4516a68 (bug #49675)
+
+ ** preserve lasterror info on rethrow (bug #49642)
+
+ ** norm: fix error in input argument validation leading to segfault
+    (bug #49634)
+
+Documentation bugs fixed:
+
+ ** overhaul Java interface description (bug #50299)
+
+ ** add documentation for hex and binary prefix and _ separator
+    (bug #50305, #50334)
+
+ ** fix build of docs broken in sub2ind (bug #50348)
+
+ ** version.m: document that "-release" returns an empty string (bug #50294)
+
+ ** remove trailing "\n\" from sleep and usleep docstrings (bug #50301)
+
+ ** expand documentation for cast() (bug #50201)
+
+ ** correct two entries in Table 34.1 (bug #50203)
+
+ ** oop.txi: Improve table formatting (bug #50203)
+
+ ** fix '##' in middle of docstring/comment lines (bug #50145)
+
+ ** reword documentation about subplots in 15.2.4 (bug #50148)
+
+ ** update unimplemented list of functions and where to find them
+    (bug #50098)
+
+ ** compare_plot_demos: fix HTML syntax, simplify output, remove
+    external deps (bug #49709)
+
+ ** add more depth to explanation of '~' function argument (bug #49444)
+
+ ** correct documentation for javaclasspath file (bug #49873)
+
+ ** small fixes to docstrings (bug #49733)
+
+ ** change text describing demo plots to reflect new ColorOrder (bug #49288)
+
+Other bugs fixed:
+
+ ** add missing classdef test files (bug #49819)
+
+
+Summary of important user-visible changes for version 4.2 (2016-11-13):
+----------------------------------------------------------------------
+
+ ** The parser has been extended to accept, but ignore, underscore
+    characters in numbers.  This facilitates writing more legible code
+    by using '_' as a thousands separator or to group nibbles into bytes
+    in hex constants.
+
+    Examples: 1_000_000 == 1e6  or  0xDE_AD_BE_EF
+
+ ** The parser has been extended to understand binary numbers which
+    begin with the prefix '0b' or '0B'.  The value returned is Octave's
+    default numeric class of double, not at unsigned integer class.
+    Therefore numbers greater than flintmax, i.e., 2^53, will lose some
+    precision.
+
+    Examples: 0b101 == 5  or  0B1100_0001 == 0xC1
+
+ ** gnuplot 4.4 is now the minimum version supported by Octave.
+
+ ** The default set of colors used to plot lines has been updated to be
+    compatible with Matlab's new default color scheme.  The line plot
+    color scheme can be set with the axes property "ColorOrder".
+
+ ** The default colormap is now set to "viridis" which is also the
+    default colormap in matplotlib.  This new colormap fixes some of the
+    main issues with the old default colormap "jet" such as its bad
+    "luminance profile" and is also more similar to Matlab's new default
+    colormap "parula".
+
+ ** The colormap function no longer supports the input argument "list"
+    to show built-in colormaps.  Use "help colormap" to find the
+    built-in colormaps.
+
+ ** The graphics command "hold on" now ensures that each new plot added
+    to an existing plot has a different color or linestyle according to
+    the "ColorOrder" and/or "LineStyleOrder" properties.  This is
+    equivalent to the old command "hold all" and was made for Matlab
+    compatibility.  Existing code *may* produce differently colored
+    plots if it did not specify the color for a plot and relied on each
+    new plot having the default first color in the "ColorOrder"
+    property.
+
+ ** When starting, Octave now looks in the function path for a file
+    startup.m and executes any commands found there.  This change was
+    made to accommodate Matlab users.  Octave has it's own configuration
+    system based on the file .octaverc which is preferred.
+
+ ** Octal ('\NNN') and hex ('\xNN') escape sequences in single quoted
+    strings are now interpreted by the function do_string_escapes().
+    The *printf family of functions now supports octal and hex escape
+    sequences in single-quoted strings for Matlab compatibility.
+
+ ** Special octal and hex escape sequences for the pattern and
+    replacement strings in regular expressions are now interpreted for
+    Matlab compatibility.
+
+    octal: '\oNNN' or '\o{NNN}'
+    hex  : '\xNN'  or '\x{NN}'
+
+ ** Unknown escape sequences in the replacement string for regexprep are
+    now substituted with their unescaped version and no warning is
+    emitted.  This change was made for Matlab compatibility.
+
+    Example: regexprep ('a', 'a', 'x\yz')
+             => 'xyz'
+
+ ** mkfifo now interprets the MODE argument as an octal, not decimal,
+    integer.  This is consistent with the equivalent shell command.
+
+ ** linspace now returns an empty matrix if the number of requested
+    points is 0 or a negative number.  This change was made to be
+    compatible with Matlab releases newer than 2011.  In addition,
+    Octave no longer supports matrix inputs for A or B.
+
+ ** The cov function now returns the complex conjugate of the result
+    from previous versions of Octave.  This change was made for
+    compatibility with Matlab.
+
+ ** condest now works with a normest1 compatible syntax.
+
+ ** The griddata function no longer plots the interpolated mesh if no
+    output argument is requested, instead the vector or array of
+    interpolated values is always returned for Matlab compatibility.
+
+ ** The new function "light" and the corresponding graphics object
+    provide light and shadow effects for patch and surface objects.
+
+ ** The surfnorm function now returns unnormalized (magnitude != 1)
+    normal vectors for compatibility with Matlab.
+
+ ** The normal vectors returned from isonormals have been reversed to
+    point towards smaller values for compatibility with Matlab.
+
+ ** The quadl function now uses an absolute, rather than relative,
+    tolerance for Matlab compatibility.  The default tolerance is 1e-6
+    which may result in lower precision results than previous versions
+    of Octave which used eps as the relative tolerance.  The quadl
+    function has also been extended to return a second output with the
+    total number of function evaluations.
+
+ ** The textscan function is now built-in and is much faster and much
+    more Matlab-compatible than the previous m-file version.
+
+ ** Dialog boxes--errordlg, helpdlg, inputdlg, listdlg, msgbox,
+    questdlg, and warndlg--now exclusively use Qt for rendering.
+    Java based versions have been removed.
+
+ ** The axes properties "TitleFontSizeMultiplier" and "TitleFontWeight"
+    are now implemented which control the default appearance of text
+    created with title().
+    The axes property "LabelFontSizeMultiplier" is now implemented
+    which controls the default appearance of text created with
+    xlabel(), ylabel(), or zlabel().
+
+ ** The graphics property "box" for axes now defaults to "off".
+    To obtain equivalent plots to previous versions of Octave use
+      set (0, "DefaultAxesBox", "on");
+    in your .octaverc file.
+
+ ** The graphics property "boxstyle" has been implemented.  The default
+    is "back" which draws only the back planes in a 3-D view.  If the
+    option is "full" then all planes are drawn.
+
+ ** The graphics property "erasemode" has been hidden, and will
+    eventually be removed.  This property has also been removed
+    from Matlab, and was never implemented in Octave.
+
+ ** The graphics property "graphicssmoothing" for figures now controls
+    whether anti-aliasing will be used for lines.  The default is "on".
+
+ ** The value "zero" for the axes properties "xaxislocation" and
+    "yaxislocation" has been deprecated and will be removed from
+    Octave 5.  Use "origin" instead.
+
+ ** The publish function allows easy publication of Octave script files
+    in HTML or other formats, including figures and output created by
+    this script.  It comes with its counterpart grabcode, which lets one
+    literally grab the HTML published code from a remote website, for
+    example.
+
+ ** The value of the MEX variable TrapFlag now defaults to 0, which will
+    cause Octave to abort execution of a MEX file and return to the
+    prompt if an error is encountered in mexCallMATLAB.
+
+ ** The MEX API now includes the function mexCallMATLABWithTrap.  This
+    function will not abort if an error occurs during mexCallMATLAB, but
+    instead will return execution to the MEX function for error
+    handling.
+
+ ** The MEX API functions for input validation that begin with "mxIs"
+    (e.g., mxIsDouble, mxIsEmpty, etc.) now return type bool rather than
+    type int.
+
+ ** The functions mxAssert and mxAssertS for checking assertions have
+    been added.  In order to avoid a performance penalty they are only
+    compiled in to debug versions of a MEX file, i.e., that are produced
+    when the '-g' option is given to mex or mkoctfile.
+
+ ** Other new MEX API functions include mexEvalStringWithTrap,
+    mxIsScalar, mxCreateUninitNumericArray, mxCreateUninitNumericMatrix.
+
+ ** Other new functions added in 4.2:
+
+      audioformats
+      camlight
+      condeig
+      deg2rad
+      dialog
+      evalc
+      hash
+      im2double
+      isocaps
+      lighting
+      localfunctions
+      material
+      normest1
+      ode23
+      ode45
+      odeget
+      odeplot
+      odeset
+      padecoef
+      profexport
+      psi
+      rad2deg
+      reducepatch
+      reducevolume
+      smooth3
+      uibuttongroup
+
+ ** Deprecated functions.
+
+    The following functions have been deprecated in Octave 4.2 and will
+    be removed from Octave 5 (or whatever version is the second major
+    release after 4.2):
+
+      Function             | Replacement
+      ---------------------|------------------
+      bitmax               | flintmax
+      mahalanobis          | mahal in Octave Forge statistics pkg
+      md5sum               | hash
+      octave_config_info   | __octave_config_info__
+      onenormest           | normest1
+      sleep                | pause
+      usleep               | pause
+      wavread              | audioread
+      wavwrite             | audiowrite
+
+ ** The following functions were deprecated in Octave 3.8 and have been
+    removed from Octave 4.2.
+
+      default_save_options    java_new
+      gen_doc_cache           java_unsigned_conversion
+      interp1q                javafields
+      isequalwithequalnans    javamethods
+      java_convert_matrix     re_read_readline_init_file
+      java_debug              read_readline_init_file
+      java_invoke             saving_history
+
+ ** The global error_state variable in Octave's C++ API has been
+    deprecated and will be removed in a future version.  Now the error
+    and print_usage functions throw an exception
+    (octave::execution_exception) after displaying the error message.
+    This makes the error and print_usage functions in C++ work more like
+    the corresponding functions in the scripting language.
+
+ ** The default error handlers in liboctave have been updated to use
+    exceptions.  After displaying an error message they no longer return
+    control to the calling program.  The error handler function can be
+    customized through the global variables
+    "current_liboctave_error_handler" and
+    "current_liboctave_error_with_id_handler".  If a programmer has
+    installed their own custom error handling routines when directly
+    linking with liboctave then these must be updated to throw an
+    exception and not return to the calling program.
+
+ ** The system for common errors and warnings has been renamed from
+    gripe_XXX to either err_XXX if error is called or warn_XXX if
+    warning is called.  The gripe_XXX functions are deprecated and will
+    be removed in version 5.
+
+ ** New configure option, --enable-address-sanitizer-flags, to build
+    Octave with memory allocator checks (similar to those in valgrind)
+    built in.
+
+Summary of important user-visible changes for version 4.0 (2015-05-23):
+----------------------------------------------------------------------
+
+ ** A graphical user interface is now the default when running Octave
+    interactively.  The start-up option --no-gui will run the familiar
+    command line interface, and still allows use of the GUI dialogs and
+    qt plotting toolkit.  The option --no-gui-libs runs a minimalist
+    command line interface that does not link with the Qt libraries and
+    uses the fltk toolkit for plotting.
+
+ ** Octave now uses OpenGL graphics with Qt widgets by default.  If
+    OpenGL libraries are not available when Octave is built, gnuplot is
+    used.  You may choose to use the fltk or gnuplot toolkit for
+    graphics by executing the command
+
+      graphics_toolkit ("fltk")
+        OR
+      graphics_toolkit ("gnuplot")
+
+    Adding such a command to your ~/.octaverc file will set the default
+    for each session.
+
+ ** A new syntax for object oriented programming termed classdef has
+    been introduced.  See the manual for more extensive documentation of
+    the classdef interface.
+
+    New keywords:
+
+      classdef      endclassdef
+      enumeration   endenumeration
+      events        endevents
+      methods       endmethods
+      properties    endproperties
+
+ ** New audio functions and classes:
+
+      audiodevinfo  audioread      sound
+      audioinfo     audiorecorder  soundsc
+      audioplayer   audiowrite
+
+ ** Other new classes in Octave 4.0:
+
+      audioplayer    inputParser
+      audiorecorder
+
+ ** Optional stricter Matlab compatibility for ranges, diagonal
+    matrices, and permutation matrices.
+
+    Octave has internal optimizations which use space-efficient storage
+    for the three data types above.  Three new functions have been added
+    which control whether the optimizations are used (default), or
+    whether the data types are stored as full matrices.
+
+    disable_range   disable_diagonal_matrix   disable_permutation_matrix
+
+    All three optimizations are disabled if Octave is started with the
+    --braindead command line option.
+
+ ** The preference
+
+      do_braindead_shortcircuit_evaluation
+
+    is now enabled by default.
+
+ ** The preference
+
+      allow_noninteger_range_as_index
+
+    is now enabled by default and the warning ID
+
+      Octave:noninteger-range-as-index
+
+    is now set to "on" by default instead of "error" by default and "on"
+    for --traditional.
+
+ ** The "backtrace" warning option is now enabled by default.  This
+    change was made for Matlab compatibility.
+
+ ** For compatibility with Matlab, the "ismatrix (x)" function now only
+    checks the dimension of "x".  The old behavior of "ismatrix" is
+    obtained by "isnumeric (x) || islogical (x) || ischar (x)".
+
+ ** The nextpow2 function behavior has been changed for vector inputs.
+    Instead of computing `nextpow2 (length (x))', it will now compute
+    nextpow2 for each element of the input.  This change is Matlab
+    compatible, and also prevents bugs for "vectors" of length 1.
+
+ ** polyeig now returns a row vector of eigenvalues rather than a matrix
+    with the eigenvalues on the diagonal.  This change was made for
+    Matlab compatibility.
+
+ ** Interpolation function changes for Matlab compatibility
+
+    The interpolation method 'cubic' is now equivalent to 'pchip' for
+    interp1, interp2, and interp3.  Previously, 'cubic' was equivalent
+    to 'spline' for interp2.  This may produce different results as
+    'spline' has continuous 1st and 2nd derivatives while 'pchip' only
+    has a continuous 1st derivative.  The methods 'next' and 'previous'
+    have been added to interp1 for compatibility.
+
+ ** The delaunay function has been extended to accept 3-D inputs for
+    Matlab compatibility.  The delaunay function no longer plots the
+    triangulation if no output argument is requested, instead, the
+    triangulation is always returned.  The delaunay3 function which
+    handles 3-D inputs has been deprecated in favor of delaunay.
+
+ ** The trigonometric functions asin and acos return different phase
+    values from previous versions of Octave when the input is outside
+    the principal branch ([-1, 1]).  If the real portion of the input is
+    greater than 1 then the limit from below is taken.  If the real
+    portion is less than 1 then the limit from above is taken.  This
+    criteria is consistent with several other numerical analysis
+    software packages.
+
+ ** The hyperbolic function acosh now returns values with a phase in the
+    range [-pi/2, +pi/2].  Previously Octave returned values in the
+    range [0, pi].  This is consistent with several other numerical
+    analysis software packages.
+
+ ** strfind changes when using empty pattern ("") for Matlab
+    compatibility
+
+    strfind now returns an empty array when the pattern itself is empty.
+    In previous versions of Octave, strfind matched at every character
+    location when the pattern was empty.
+
+      NEW
+      strfind ("abc", "") => []
+      OLD
+      strfind ("abc", "") => [1, 2, 3, 4]
+
+ ** Integer formats used in the printf family of functions now work for
+    64-bit integers and are more compatible with Matlab when printing
+    non-integer values.  Now instead of truncating, Octave will switch
+    the effective format to '%g' in the following circumstances:
+
+      * the value of an integer type (int8, uint32, etc.) value exceeds
+        the maximum for the format specifier.  For '%d', the limit is
+        intmax ('int64') and for '%u' it is intmax ('uint64').
+
+      * round(x) != x or the value is outside the range allowed by the
+        integer format specifier.
+
+    There is still one difference: Matlab switches to '%e' and Octave
+    switches to '%g'.
+
+ ** The functions intersect, setdiff, setxor, and union now return a
+    column vector as output unless the input was a row vector.  This
+    change was made for Matlab compatibility.
+
+ ** The inpolygon function now returns true for points that are within
+    the polygon OR on it's edge.  This change was made for Matlab
+    compatibility.
+
+ ** The archive family of functions (bzip2, gzip, zip, tar) and their
+    unpacking routines (bunzip2, gunzip, unzip, untar, unpack) have been
+    recoded.  Excepting unpack, the default is now to place files in the
+    same directory as the archive (on unpack) or as the original files
+    (on archiving).
+
+ ** Qt and FLTK graphics toolkits now support offscreen rendering on
+    Linux.  In other words, print will work even when the figure
+    visibility is "off".
+
+ ** Z-order stacking issues with patches, grid lines, and line object
+    plot markers for on screen display and printing have all been
+    resolved.  For 2-D plots the axis grid lines can be placed on top of
+    the plot with set (gca, "layer", "top").
+
+ ** The patch graphic object has been overhauled.  It now produces
+    visual results equivalent to Matlab even for esoteric combinations
+    of faces/vertices/cdata.
+
+ ** The polar() plot function now draws a circular theta axis and radial
+    rho axis rather than using a rectangular x/y axis.
+
+ ** linkprop has been completely re-coded for performance and Matlab
+    compatibility.  It now returns a linkprop object which must be
+    stored in a variable for as long as the graphic objects should
+    remain linked.  To unlink properties use 'clear hlink' where hlink
+    is the variable containing the linkprop object.
+
+ ** isprime has been extended to operate on negative and complex inputs.
+
+ ** xor has been extended to accept more than two arguments in which
+    case it performs cumulative XOR reduction.
+
+ ** The following functions now support N-dimensional arrays:
+
+      fliplr   flipud   rot90   rectint
+
+ ** The new warning ID "Octave:data-file-in-path" replaces the three
+    previous separate warning IDs "Octave:fopen-file-in-path",
+    "Octave:load-file-in-path", and "Octave:md5sum-file-in-path".
+
+ ** The warning ID Octave:singular-matrix-div has been replaced by
+    Octave:nearly-singular-matrix and Octave:singular-matrix.
+
+ ** The warning ID Octave:matlab-incompatible has been replaced by
+    Octave:language-extension to better reflect its meaning.
+
+ ** The warning ID Octave:broadcast has been removed.  Instead automatic
+    broadcasting will throw an Octave:language-extension warning.  This
+    warning ID is used for broadcasting as well as other features not
+    available in Matlab.
+
+ ** Other new functions added in 4.0:
+
+      annotation
+      bandwidth
+      cubehelix
+      dir_in_loadpath
+      flip
+      frame2im
+      get_home_directory
+      hgload
+      hgsave
+      ichol
+      ilu
+      im2frame
+      isbanded
+      isdiag
+      isstudent
+      istril
+      istriu
+      javachk
+      jit_failcnt
+      linkaxes
+      lscov
+      metaclass
+      numfields
+      open
+      ordschur
+      pan
+      qmr
+      rotate
+      rotate3d
+      sylvester
+      unsetenv
+      validateattributes
+      zoom
+
+ ** inline() scheduled for eventual deprecation by Matlab
+
+    Functions created through the use of inline are scheduled for
+    deprecation by Matlab.  When this occurs Octave will continue to
+    support inline functions for an indeterminate amount of time before
+    also removing support.  All new code should use anonymous functions
+    in place of inline functions.
+
+ ** Deprecated functions.
+
+    The following functions have been deprecated in Octave 4.0 and will
+    be removed from Octave 4.4 (or whatever version is the second major
+    release after 4.0):
+
+      Function             | Replacement
+      ---------------------|------------------
+      bicubic              | interp2
+      delaunay3            | delaunay
+      dump_prefs           | individual preference get/set routines
+      find_dir_in_path     | dir_in_loadpath
+      finite               | isfinite
+      fmod                 | rem
+      fnmatch              | glob or regexp
+      gmap40               | ----
+      loadaudio            | audioread
+      luinc                | ilu or ichol
+      mouse_wheel_zoom     | mousewheelzoom axes property
+      nfields              | numfields
+      octave_tmp_file_name | tempname
+      playaudio            | audioplayer
+      saveaudio            | audiowrite
+      syl                  | sylvester
+      usage                | print_usage
+
+      allow_noninteger_range_as_index
+      do_braindead_shortcircuit_evaluation
+      setaudio
+
+ ** The following functions were deprecated in Octave 3.8 and will be
+    removed from Octave 4.2 (or whatever version is the second major
+    release after 3.8):
+
+      default_save_options    java_new
+      gen_doc_cache           java_unsigned_conversion
+      interp1q                javafields
+      isequalwithequalnans    javamethods
+      java_convert_matrix     re_read_readline_init_file
+      java_debug              read_readline_init_file
+      java_invoke             saving_history
+
+ ** The following functions were deprecated in Octave 3.6 and have been
+    removed from Octave 4.0.
+
+      cut                polyderiv
+      cor                shell_cmd
+      corrcoef           studentize
+      __error_text__     sylvester_matrix
+      error_text
+
+ ** The following keywords were deprecated in Octave 3.8 and have been
+    removed from Octave 4.0
+
+      static
+
+ ** The following configuration variables were deprecated in Octave 3.8
+    and have been removed from Octave 4.0
+
+      CC_VERSION  (now GCC_VERSION)
+      CXX_VERSION (now GXX_VERSION)
+
+ ** The internal function atan2 of the sparse matrix class has been
+    deprecated in Octave 4.0 and will be removed from Octave 4.4 (or
+    whatever version is the second major release after 4.0).  Use the
+    Fatan2 function with sparse inputs as a replacement.
+
+ ** The internal class Octave_map was deprecated in Octave 3.8 and has
+    been removed from Octave 4.0.  Replacement classes are octave_map
+    (struct array) or octave_scalar_map for a single structure.
+
+ ** Octave now has OpenMP enabled by default if the system provides a
+    working OpenMP implementation.  This allows oct-file modules to take
+    advantage of OpenMP if desired.  This can be disabled when building
+    Octave with the configure option --disable-openmp.
+
+ ** Octave now automatically truncates intermediate calculations done
+    with floating point values to 64 bits.  Some hardware math
+    co-processors, such as the x87, maintain extra precision, but this
+    leads to disagreements in calculations when compared to reference
+    implementations in software using the IEEE standard for double
+    precision.  There was no measurable performance impact to this
+    change, but it may be disabled with the configure option
+    --disable-float-truncate.  MinGW and Cygwin platforms, as well as
+    GCC compilers >= 5.0 require this feature.  Non-x87 hardware, or
+    hardware using SSE options exclusively, can disable float truncation
+    if desired.
+
+---------------------------------------------------------
+
+See NEWS.3 for old news.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/RELEASE.BUG_FIX_LIST	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,24 @@
+The following bugs must be fixed prior to the next release.  See also the [[5.0.0 Release Checklist]].
+
+<p>Sign up for a bug by filling in the Owner field so people won't duplicate each other's work.</p>
+
+<p>Use <pre><strike> ... </strike></pre> to cross an item off the list when it has been done.</p>
+
+<p>Add <pre>WON'T FIX</pre> and the strike through tag for any bugs that will not be fixed in this round.</p>
+
+<div class="tocinline">__TOC__</div>
+
+----
+
+== Bugs marked as Crash ==
+
+== Bugs marked Configuration and Build System ==
+
+== Bugs with severity >= 4 ==
+
+== Bugs marked as regressions ==
+
+== Other Bugs ==
+
+== Potentially excluded bugs ==
+These bugs have been provisionally decided not to be blockers for 5.0.0.  That doesn't mean they can't be fixed, if someone wants to fix them.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/RELEASE.CHECKLIST	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,107 @@
+<!----------------------------------------------------------------------------->
+<! This file contains a list of steps to accomplish before producing a release.
+   The format of the file is wiki markup and can be directly used as a page
+   on wiki.octave.org. >
+<!----------------------------------------------------------------------------->
+==5.0.0 Release Tasks==
+
+<!----------------------------------------------------------------------------->
+# Update gnulib to latest version
+#: Must occur first as it could resolve existing, or create new, bug reports
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# File bug reports for all outstanding bugs known, but not reported
+#* Put out a general call for reports on Octave-Maintainers and Octave-Help list
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Review patch tracker/bug list for any patches submitted that may be included before release
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Identify Bugs which *must* be fixed prior to release
+#* Review bugs on tracker for possible inclusion in list
+#* Review bugs and update to correct category, such as Patch submitted
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Clear all bugs identified as must-fix
+#* See [[Bug Fix List - 5.0 Release]]
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# GPL License activities
+#* Update Copyright statements for all source controlled files
+#* Update dates in any other locations (launch message, citation, MXE files, etc.)
+#* Add any new contributors to contributors.in
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Style-check code base
+#* This will produce lots of whitespace changes, but no behavior changes
+#* Must occur after patches have been added since whitespace changes can prevent patches from applying
+#* m-file style check. Completion Date:
+#* C++ style check.  Completion Date:
+<!----------------------------------------------------------------------------->
+# Run lint checker on code base
+#* Possibilities include compiling with -fsanitize=undefined and running 'make check', cppcheck, etc.
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Verify 'make check' is passing on all buildbot combinations of OS and compilers
+#* Start discussion on octave-maintainers list about which failing tests must be fixed
+#* Identify and fix any tests determined critical in step above
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Compile and run Octave test suite with --enable-address-sanitizer-flags to check for memory leaks
+#* Results posted to bug report:
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Review documentation
+#* Grammar check documentation so that it conforms to Octave standards
+#* Spell check documentation
+#* Verify no functions missing from manual
+#* Verify deprecated functions removed from "see also" links
+#* Verify all formats (Info, HTML, pdf) build correctly
+#* Review NEWS for any features which should be announced
+#* Update major version number in "@subtitle Edition XXX" in octave.texi
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Localization and Internationalization
+#* Update language translation files (*.ts)
+#* Create issue report on Savannah as a centralized location for uploading files
+#* Submit call for translations for GUI strings
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Verify build process and create release candidates
+#* Update configure.ac with new version information
+#** Update AC_INIT, OCTAVE_MAJOR_VERSION, OCTAVE_MINOR_VERSION, OCTAVE_PATCH_VERSION, OCTAVE_RELEASE_DATE
+#* Verify 'make distcheck' passes
+#* Create release candidate
+#** 'make dist'
+#** hg tag repository with release candidate ID
+#** For Windows, create installer [[Windows Installer]]
+#** Upload release candidate
+#** Add release candidate version to Savannah bug tracker
+#** Announce release candidate to Octave-Maintainers, Octave-Help, on web page
+#** Repeat release candidate cycle until clean
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Final Release
+#* Update version information
+#** Update configure.ac (AC_INIT, OCTAVE_MAJOR_VERSION, OCTAVE_MINOR_VERSION, OCTAVE_PATCH_VERSION, OCTAVE_RELEASE_DATE)
+#** Update libtool versioning (configure.ac:OCTAVE_API_VERSION, liboctave/module.mk:%canon_reldir%_%canon_reldir%_current, libinterp/module.mk:%canon_reldir%_liboctinterp_current, libgui/module.mk:%canon_reldir%_liboctgui_current)
+#** Update NEWS (final release date)
+#** Update CITATION (version, year, URL)
+#** Update org.octave.Octave.appdata.xml (version number and release date)
+#* hg tag repository with release version number
+#* merge default onto stable to become the current stable release
+#* Savannah bug tracker version info
+#** add new release version to bug tracker
+#** remove release candidate versions from bug tracker
+#* Announce final release on Octave mailing lists and web site
+#: Completion Date:
+<!----------------------------------------------------------------------------->
+# Post-Release
+#* Update configure.ac (AC_INIT, OCTAVE_MAJOR_VERSION, OCTAVE_MINOR_VERSION, OCTAVE_PATCH_VERSION) to next release cycle
+#* Remove all deprecated functions (either OCTAVE_DEPRECATED in C++ or scripts/deprecated for m-files) scheduled for deletion in default branch
+#* Move NEWS file to backup in etc/NEWS.X
+#* Create new NEWS file
+#: Completion Date:
+
+[[Category:Releases]]
+[[Category:Development]]
--- a/etc/RELEASE.PROCESS	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-<!----------------------------------------------------------------------------->
-<! This file contains a list of steps to accomplish before producing a release.
-   The format of the file is wiki markup and can be directly used as a page
-   on wiki.octave.org.
-<!----------------------------------------------------------------------------->
-==4.4.0 Release Tasks==
-
-This page shows the tasks to be completed before the GUI release is finalized.
-
-<!----------------------------------------------------------------------------->
-# Update gnulib to latest version
-# Must occur first as it could resolve existing, or create new, bug reports
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# File bug reports for all outstanding bugs known, but not reported
-#* Put out a general call for reports on Octave-Maintainers and Octave-Help list
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Review patch tracker/bug list for any patches submitted that may be included before release
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Identify Bugs which *must* be fixed prior to release
-#* Review bugs on tracker for possible inclusion in list
-#* Review bugs and update to correct category, such as Patch submitted
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Clear all bugs identified as must-fix
-#* See [[Bug Fix List - 4.2 Release]]
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# GPL License activities
-#* Update Copyright statements for all source controlled files
-#* Update dates in any other locations (launch message, citation, etc.)
-#* Add any new contributors to contributors.in
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Style-check code base
-#* This will produce lots of whitespace changes, but no behavior changes
-#* Must occur after patches have been added since whitespace changes will often prevent patches from applying
-#* m-file style check. Completion Date:
-#* C++ style check.  Completion Date:
-<!----------------------------------------------------------------------------->
-# Run lint checker on code base
-#* cppcheck, -fsanitize, etc.
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Verify 'make check' is passing on all buildbot combinations of OS and compilers
-#* Start discussion on octave-maintainers list about which failing tests must be fixed
-#* Identify and fix any tests determined critical in step above
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Compile and run Octave test suite with --enable-address-sanitizer-flags to check for memory leaks
-#* Results posted to bug report:
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Review documentation
-#* Grammar check documentation so that it conforms to Octave standards
-#* Spell check documentation
-#* Verify no functions missing from manual
-#* Verify deprecated functions removed from "see also" links
-#* Verify all formats (Info, HTML, pdf) build correctly
-#* Review NEWS for any features which should be announced
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Localization and Internationalization
-#* Update language translation files (*.ts)
-#* Submit call for translations for GUI strings.
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Verify build process and create release candidates
-#* Update version information in configure.ac/Makefile.am
-#* Verify 'make distcheck' passes
-#* Create release candidate
-#** 'make dist'
-#** hg tag repository with release candidate ID
-#** For Windows, create installer [[Windows Installer]]
-#** Upload release candidate
-#** Announce release candidate to Octave-Maintainers, Octave-Help, on web page
-#** Repeat release candidate cycle until clean
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Final Release
-#* hg tag repository with release
-#* merge default onto stable to become the current stable release
-#* add new release version to Savannah bug tracker
-#* Announce final release on Octave mailing lists and web site
-#: Completion Date:
-<!----------------------------------------------------------------------------->
-# Post-Release
-#* Update configure.ac/Makefile.am versioning to next release cycle
-#* Remove all deprecated functions scheduled for deletion in default branch
-#: Completion Date:
-
-[[Category:Releases]]
-[[Category:Development]]
--- a/etc/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/etc/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -8,6 +8,7 @@
   %reldir%/NEWS.1 \
   %reldir%/NEWS.2 \
   %reldir%/NEWS.3 \
+  %reldir%/NEWS.4 \
   %reldir%/PROJECTS \
   %reldir%/gdbinit
 
@@ -37,9 +38,11 @@
 
 appdatadir = $(datadir)/metainfo
 
-appdata_DATA = \
+APPDATA_XML_FILE := \
   %reldir%/icons/org.octave.Octave.appdata.xml
 
+appdata_DATA = $(APPDATA_XML_FILE)
+
 desktopdir = $(datadir)/applications
 
 desktop_DATA = \
@@ -102,6 +105,23 @@
 	$(ICOTOOL) --create --raw  $(WINDOWS_PNG_ICONS) > $@-t && \
 	mv $@-t $@
 
+## Check that the release date and version number are in
+## $(APPDATA_XML_FILE), but only for actual releases, which means
+## we skip the test if the minor version number is 0 or the patch
+## version number is not 0.
+
+appdata-dist-hook:
+	@test x"$(DIST_IGNORE_APPDATA_VERSION)" != x || \
+	 test $(OCTAVE_MINOR_VERSION) -eq 0 || \
+	 test $(OCTAVE_PATCH_VERSION) -ne 0 || \
+	 grep "<release *date=\"$(OCTAVE_RELEASE_DATE)\" *version=\"$(OCTAVE_VERSION)\"/>" $(srcdir)/$(APPDATA_XML_FILE) > /dev/null || \
+	{ echo; \
+	  echo "Packaging distribution requires the version number in the $(APPDATA_XML_FILE)."; \
+	  echo "Please update first or pass DIST_IGNORE_APPDATA_VERSION=1."; \
+	  echo "Cannot package distribution!"; \
+	  echo; exit 1; }
+.PHONY: appdata-dist-hook
+
 install-data-local: install-icons
 
 uninstall-local: uninstall-icons
--- a/examples/code/mex_demo.c	Tue Dec 04 10:12:41 2018 -0800
+++ b/examples/code/mex_demo.c	Thu Dec 20 17:18:56 2018 -0500
@@ -1,13 +1,5 @@
 // mex_demo.c -- example of a dynamically linked function for Octave.
 
-// To use this file, your version of Octave must support dynamic
-// linking.  To find out if it does, type the command
-//
-//   __octave_config_info__ ("ENABLE_DYNAMIC_LINKING")
-//
-// at the Octave prompt.  Support for dynamic linking is included if
-// this expression is true.
-//
 // To compile this file, type the command
 //
 //   mkoctfile --mex mex_demo.c
--- a/examples/code/oct_demo.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/examples/code/oct_demo.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -1,13 +1,5 @@
 // oct_demo.cc -- example of a dynamically linked function for Octave.
 
-// To use this file, your version of Octave must support dynamic
-// linking.  To find out if it does, type the command
-//
-//   __octave_config_info__ ("ENABLE_DYNAMIC_LINKING")
-//
-// at the Octave prompt.  Support for dynamic linking is included if
-// this expression is true.
-//
 // To compile this file, type the command
 //
 //   mkoctfile oct_demo.cc
--- a/libgui/default-qt-settings.in	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/default-qt-settings.in	Thu Dec 20 17:18:56 2018 -0500
@@ -26,10 +26,11 @@
 cursorType=ibeam
 
 [MainWindow]
-geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\xff\xff\xff\xfa\0\0\0\xf\0\0\x4\x11\0\0\x3\xf\0\0\0\x4\0\0\0\x35\0\0\x4\a\0\0\x3\x5\0\0\0\0\0\0)
-windowState="@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\x4\x4\0\0\x2\x93\xfc\x2\0\0\0\x1\xfc\0\0\0(\0\0\x2\x93\0\0\x1\xb0\0\xff\xff\xff\xfc\x1\0\0\0\x2\xfc\0\0\0\0\0\0\x1W\0\0\0j\0\xff\xff\xff\xfc\x2\0\0\0\x3\xfb\0\0\0\x1e\0\x46\0i\0l\0\x65\0s\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0(\0\0\x1\x2\0\0\0\x90\0\xff\xff\xff\xfb\0\0\0\x1a\0W\0o\0r\0k\0s\0p\0\x61\0\x63\0\x65\0V\0i\0\x65\0w\x1\0\0\x1\x30\0\0\0\xd3\0\0\0\x8a\0\xff\xff\xff\xfb\0\0\0\"\0H\0i\0s\0t\0o\0r\0y\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\x2\t\0\0\0\xb2\0\0\0\x8a\0\xff\xff\xff\xfc\0\0\x1]\0\0\x2\xa7\0\0\x1,\0\xff\xff\xff\xfc\x2\0\0\0\x2\xfb\0\0\0\x1c\0N\0\x65\0w\0s\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0@\0\0\0\xdb\0\0\0\0\0\0\0\0\xfc\0\0\0(\0\0\x2\x93\0\0\0\xfa\x1\0\0\x19\xfa\0\0\0\0\x2\0\0\0\x4\xfb\0\0\0$\0T\0\x65\0r\0m\0i\0n\0\x61\0l\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xe0\0\xff\xff\xff\xfb\0\0\0\x14\0\x46\0i\0l\0\x65\0\x45\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x65\0\xff\xff\xff\xfb\0\0\0.\0\x44\0o\0\x63\0u\0m\0\x65\0n\0t\0\x61\0t\0i\0o\0n\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xab\0\xff\xff\xff\xfb\0\0\0\x1e\0v\0\x61\0r\0i\0\x61\0\x62\0l\0\x65\0_\0\x65\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x44\0\xff\xff\xff\0\0\0\0\0\0\x2\x93\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\x16\0M\0\x61\0i\0n\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)"
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x2\0\0\0\0\0\0\0\0\0\x1b\0\0\x4\x3\0\0\x3\t\0\0\0\0\0\0\0\x39\0\0\x4\x3\0\0\x3\t\0\0\0\0\0\0\0\0\x5\0)
+windowState="@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\x4\x4\0\0\x2|\xfc\x2\0\0\0\x1\xfc\0\0\0?\0\0\x2|\0\0\x1\x98\0\xff\xff\xff\xfc\x1\0\0\0\x2\xfc\0\0\0\0\0\0\x1W\0\0\0\x9b\0\xff\xff\xff\xfc\x2\0\0\0\x3\xfb\0\0\0\x1e\0\x46\0i\0l\0\x65\0s\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0?\0\0\0\xf9\0\0\0\x88\0\xff\xff\xff\xfb\0\0\0\x1a\0W\0o\0r\0k\0s\0p\0\x61\0\x63\0\x65\0V\0i\0\x65\0w\x1\0\0\x1>\0\0\0\xcb\0\0\0\x82\0\xff\xff\xff\xfb\0\0\0\"\0H\0i\0s\0t\0o\0r\0y\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\x2\xf\0\0\0\xac\0\0\0\x82\0\xff\xff\xff\xfc\0\0\x1]\0\0\x2\xa7\0\0\x1O\0\xff\xff\xff\xfc\x2\0\0\0\x2\xfb\0\0\0\x1c\0N\0\x65\0w\0s\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0@\0\0\0\xdb\0\0\0\0\0\0\0\0\xfc\0\0\0?\0\0\x2|\0\0\0\xeb\x1\0\0\x1b\xfa\0\0\0\0\x2\0\0\0\x5\xfb\0\0\0$\0T\0\x65\0r\0m\0i\0n\0\x61\0l\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x46\0\xff\xff\xff\xfb\0\0\0\x14\0\x46\0i\0l\0\x65\0\x45\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\x62\0\xff\xff\xff\xfb\0\0\0\x1c\0V\0\x61\0r\0i\0\x61\0\x62\0l\0\x65\0\x45\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0;\0\xff\xff\xff\xfb\0\0\0.\0\x44\0o\0\x63\0u\0m\0\x65\0n\0t\0\x61\0t\0i\0o\0n\0\x44\0o\0\x63\0k\0W\0i\0\x64\0g\0\x65\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xcf\0\xff\xff\xff\xfb\0\0\0\x1e\0v\0\x61\0r\0i\0\x61\0\x62\0l\0\x65\0_\0\x65\0\x64\0i\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2|\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\x16\0M\0\x61\0i\0n\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)"
 
 [DockWidgets]
+TerminalDockWidget=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\x1j\0\0\0 \0\0\x4\x3\0\0\x2\x9e\0\0\x1j\0\0\0 \0\0\x4\x3\0\0\x2\x9e\0\0\0\0\0\0)
 TerminalDockWidgetFloating=false
 TerminalDockWidgetVisible=true
 WorkspaceView=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\0\0\0\0\x1+\0\0\x1\x63\0\0\x2\0\0\0\0\0\0\0\x1+\0\0\x1\x63\0\0\x2\0\0\0\0\0\0\0)
@@ -50,7 +51,9 @@
 NewsDockWidget=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\x2\"\0\0\0@\0\0\x4\xb3\0\0\x1\x1a\0\0\x2\"\0\0\0@\0\0\x4\xb3\0\0\x1\x1a\0\0\0\0\0\0)
 NewsDockWidgetFloating=false
 NewsDockWidgetVisible=true
-TerminalDockWidget=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\x1j\0\0\0 \0\0\x4\x3\0\0\x2\x9e\0\0\x1j\0\0\0 \0\0\x4\x3\0\0\x2\x9e\0\0\0\0\0\0)
+VariableEditor=@ByteArray(\x1\xd9\xd0\xcb\0\x2\0\0\xff\xff\xfb\x65\xff\xff\xfb\xac\xff\xff\xfe\v\xff\xff\xfe\v\xff\xff\xfb\x65\xff\xff\xfb\xac\xff\xff\xfe\v\xff\xff\xfe\v\xff\xff\xff\xff\0\0\0\0\x5\0)
+VariableEditorFloating=false
+VariableEditorVisible=true
 
 [workspaceview]
 local_collapsed=false
@@ -58,18 +61,6 @@
 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)
 
-[filesdockwidget]
-sort_files_by_column=0
-sort_files_by_order=0
-column_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x4\xe\0\0\0\x3\0\0\0\x3\0\0\0\x64\0\0\0\x2\0\0\0\x64\0\0\0\x1\0\0\0\x64\0\0\x2\v\0\0\0\x4\x1\x1\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\x2\v\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x3\0\0\0\0)
-showFilenames=true
-showFileSize=false
-showFileType=false
-showLastModified=false
-showHiddenFiles=false
-sync_octave_directory=true
-useAlternatingRowColors=true
-
 [Scintilla]
 Octave\style0\color=0
 Octave\style0\eolfill=false
--- a/libgui/graphics/Backend.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Backend.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -58,6 +58,7 @@
              || go.isa ("uibuttongroup")
              || go.isa ("uimenu")
              || go.isa ("uicontextmenu")
+             || go.isa ("uitable")
              || go.isa ("uitoolbar")
              || go.isa ("uipushtool")
              || go.isa ("uitoggletool"))
@@ -90,6 +91,7 @@
         || go.isa ("uibuttongroup")
         || go.isa ("uimenu")
         || go.isa ("uicontextmenu")
+        || go.isa ("uitable")
         || go.isa ("uitoolbar")
         || go.isa ("uipushtool")
         || go.isa ("uitoggletool"))
@@ -121,6 +123,7 @@
         || pId == uibuttongroup::properties::ID___OBJECT__
         || pId == uimenu::properties::ID___OBJECT__
         || pId == uicontextmenu::properties::ID___OBJECT__
+        || pId == uitable::properties::ID___OBJECT__
         || pId == uitoolbar::properties::ID___OBJECT__
         || pId == uipushtool::properties::ID___OBJECT__
         || pId == uitoggletool::properties::ID___OBJECT__
@@ -180,6 +183,18 @@
   }
 
   void
+  Backend::show_figure (const graphics_object& go) const
+  {
+    if (go.get_properties ().is_visible ())
+      {
+        ObjectProxy *proxy = toolkitObjectProxy (go);
+
+        if (proxy)
+          proxy->show ();
+      }
+  }
+
+  void
   Backend::print_figure (const graphics_object& go,
                          const std::string& term,
                          const std::string& file_cmd,
--- a/libgui/graphics/Backend.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Backend.h	Thu Dec 20 17:18:56 2018 -0500
@@ -48,6 +48,8 @@
 
     void redraw_figure (const graphics_object& h) const;
 
+    void show_figure (const graphics_object& h) const;
+
     void update (const graphics_object& obj, int pId);
 
     bool initialize (const graphics_object& obj);
--- a/libgui/graphics/BaseControl.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/BaseControl.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -171,6 +171,13 @@
         m_keyPressHandlerDefined = ! up.get_keypressfcn ().isempty ();
         break;
 
+      case uicontrol::properties::ID___FOCUS__:
+        if (up.is___focus__ ())
+          w->setFocus ();
+        else
+          w->clearFocus ();
+        break;
+
       default:
         break;
       }
@@ -199,30 +206,35 @@
           graphics_object go = object ();
           uicontrol::properties& up = Utils::properties<uicontrol> (go);
           graphics_object fig = go.get_ancestor ("figure");
-
-          if (m->button () != Qt::LeftButton
-              || ! up.enable_is ("on"))
+          if (fig)
             {
-              gh_manager::post_set (fig.get_handle (), "selectiontype",
-                                    Utils::figureSelectionType (m), false);
-              gh_manager::post_set (fig.get_handle (), "currentpoint",
-                                    Utils::figureCurrentPoint (fig, m),
-                                    false);
-              gh_manager::post_callback (fig.get_handle (),
-                                         "windowbuttondownfcn");
-              gh_manager::post_callback (m_handle, "buttondownfcn");
+              gh_manager::post_set (fig.get_handle (), "currentobject",
+                                    m_handle.value (), false);
+
+              if (m->button () != Qt::LeftButton || ! up.enable_is ("on"))
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+                  gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                        Utils::figureCurrentPoint (fig, m),
+                                        false);
+                  gh_manager::post_callback (fig.get_handle (),
+                                             "windowbuttondownfcn");
+                  gh_manager::post_callback (m_handle, "buttondownfcn");
 
-              if (m->button () == Qt::RightButton)
-                ContextMenu::executeAt (up, m->globalPos ());
-            }
-          else
-            {
-              if (up.style_is ("listbox"))
-                gh_manager::post_set (fig.get_handle (), "selectiontype",
-                                      Utils::figureSelectionType (m), false);
+                  if (m->button () == Qt::RightButton)
+                    ContextMenu::executeAt (up, m->globalPos ());
+                }
               else
-                gh_manager::post_set (fig.get_handle (), "selectiontype",
-                                      octave_value ("normal"), false);
+                {
+                  if (up.style_is ("listbox"))
+                    gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                          Utils::figureSelectionType (m),
+                                          false);
+                  else
+                    gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                          octave_value ("normal"), false);
+                }
             }
         }
         break;
@@ -236,9 +248,13 @@
             graphics_object go = object ();
             graphics_object fig = go.get_ancestor ("figure");
 
-            gh_manager::post_set (fig.get_handle (), "currentpoint",
-                                  Utils::figureCurrentPoint (fig, m), false);
-            gh_manager::post_callback (fig.get_handle (), "windowbuttonmotionfcn");
+            if (fig)
+              {
+                gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                      Utils::figureCurrentPoint (fig, m), false);
+                gh_manager::post_callback (fig.get_handle (),
+                                           "windowbuttonmotionfcn");
+              }
           }
         break;
 
@@ -257,6 +273,14 @@
           }
         break;
 
+      case QEvent::FocusIn:
+        gh_manager::post_set (m_handle, "__focus__", "on", false);
+        break;
+
+      case QEvent::FocusOut:
+        gh_manager::post_set (m_handle, "__focus__", "off", false);
+        break;
+
       default:
         break;
       }
--- a/libgui/graphics/Canvas.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Canvas.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -382,7 +382,7 @@
               axesList.append (childObj);
           }
         else if (childObj.isa ("uicontrol") || childObj.isa ("uipanel")
-                 || childObj.isa ("uibuttongroup"))
+                 || childObj.isa ("uibuttongroup") || childObj.isa ("uitable"))
           {
             Matrix bb = childObj.get_properties ().get_boundingbox (false);
             QRectF r (bb(0), bb(1), bb(2), bb(3));
--- a/libgui/graphics/Figure.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Figure.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -41,6 +41,10 @@
 #include <QtDebug>
 #include <QTimer>
 #include <QToolBar>
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+#  include <QWindow>
+#  include <QScreen>
+#endif
 
 #include "Canvas.h"
 #include "Container.h"
@@ -82,25 +86,6 @@
     return false;
   }
 
-  static bool
-  hasUiMenuChildren (const figure::properties& fp)
-  {
-    gh_manager::auto_lock lock;
-
-    Matrix kids = fp.get_all_children ();
-
-    for (int i = 0; i < kids.numel (); i++)
-      {
-        graphics_object go (gh_manager::get_object (kids(i)));
-
-        if (go && go.isa ("uimenu")
-            && go.get ("visible").string_value () == "on")
-          return true;
-      }
-
-    return false;
-  }
-
   static QRect
   boundingBoxToRect (const Matrix& bb)
   {
@@ -126,13 +111,18 @@
   Figure::Figure (const graphics_object& go, FigureWindow *win)
     : Object (go, win), m_blockUpdates (false), m_figureToolBar (nullptr),
       m_menuBar (nullptr), m_innerRect (), m_outerRect (),
-      m_mouseModeGroup (nullptr)
+      m_mouseModeGroup (nullptr), m_previousHeight (0), m_resizable (true)
   {
     m_container = new Container (win);
     win->setCentralWidget (m_container);
 
     figure::properties& fp = properties<figure> ();
 
+    // Register for the signal that indicates when a window has moved
+    // to a different screen
+    connect (win, SIGNAL (figureWindowShown ()),
+             this, SLOT (figureWindowShown ()));
+
     // Status bar
     m_statusBar = win->statusBar ();
     int boffset = 0;
@@ -154,15 +144,10 @@
         m_statusBar->hide ();
       }
 
-    if (fp.menubar_is ("figure") || hasUiMenuChildren (fp))
-      toffset += m_menuBar->sizeHint ().height ();
-    else
-      m_menuBar->hide ();
-
     m_innerRect = boundingBoxToRect (fp.get_boundingbox (true));
     m_outerRect = boundingBoxToRect (fp.get_boundingbox (false));
 
-    win->setGeometry (m_innerRect.adjusted (0, -toffset, 0, boffset));
+    set_geometry (m_innerRect.adjusted (0, -toffset, 0, boffset));
 
     // Enable mouse tracking unconditionally
     enableMouseTracking ();
@@ -181,6 +166,9 @@
     // modal style
     update (figure::properties::ID_WINDOWSTYLE);
 
+    // Handle resizing constraints
+    update (figure::properties::ID_RESIZE);
+
     // Visibility
     update (figure::properties::ID_VISIBLE);
 
@@ -217,9 +205,6 @@
       case TextMode:
         return "text";
 
-      case SelectMode:
-        return "select";
-
       default:
         break;
       }
@@ -242,8 +227,6 @@
       return PanMode;
     else if (mode == "text")
       return TextMode;
-    else if (mode == "select")
-      return SelectMode;
     else
       return NoMode;
   }
@@ -319,27 +302,6 @@
 
     m_menuBar = new MenuBar (win);
     win->setMenuBar (m_menuBar);
-
-    QMenu *fileMenu = m_menuBar->addMenu (tr ("&File"));
-    fileMenu->menuAction ()->setObjectName ("builtinMenu");
-    fileMenu->addAction (tr ("&Save"), this, SLOT (fileSaveFigure (bool)));
-    fileMenu->addAction (tr ("Save &As"), this, SLOT (fileSaveFigureAs (void)));
-    fileMenu->addSeparator ();
-    fileMenu->addAction (tr ("&Close Figure"), this,
-                         SLOT (fileCloseFigure (void)), Qt::CTRL | Qt::Key_W);
-
-    QMenu *editMenu = m_menuBar->addMenu (tr ("&Edit"));
-    editMenu->menuAction ()->setObjectName ("builtinMenu");
-    editMenu->addAction (tr ("Cop&y"), this, SLOT (editCopy (bool)),
-                         Qt::CTRL | Qt::Key_C);
-    editMenu->addSeparator ();
-    editMenu->addActions (m_mouseModeGroup->actions ());
-
-    QMenu *helpMenu = m_menuBar->addMenu (tr ("&Help"));
-    helpMenu->menuAction ()->setObjectName ("builtinMenu");
-    helpMenu->addAction (tr ("About Octave"), this,
-                         SLOT (helpAboutOctave (void)));
-
     m_menuBar->addReceiver (this);
   }
 
@@ -353,6 +315,26 @@
         m_blockUpdates = false;
       }
   }
+  
+  void
+  Figure::set_geometry (QRect r)
+  {
+    QMainWindow *win = qWidget<QMainWindow> ();
+    
+    if (! m_resizable)
+      {
+        win->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred);
+        win->setFixedSize (QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+      }
+
+    win->setGeometry (r);
+    
+    if (! m_resizable)
+      {
+        win->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
+        win->setFixedSize(win->size ());
+      }
+  }
 
   Container*
   Figure::innerContainer (void)
@@ -388,6 +370,15 @@
   }
 
   void
+  Figure::show (void)
+  {
+    QWidget *win = qWidget<QWidget> ();
+
+    win->activateWindow ();
+    win->raise ();
+  }
+
+  void
   Figure::print (const QString& file_cmd, const QString& term)
   {
     Canvas *canvas = m_container->canvas (m_handle);
@@ -462,7 +453,7 @@
           if (! m_statusBar->isHidden ())
             boffset += m_statusBar->sizeHint ().height ();
 
-          win->setGeometry (m_innerRect.adjusted (0, -toffset, 0, boffset));
+          set_geometry (m_innerRect.adjusted (0, -toffset, 0, boffset));
         }
         break;
 
@@ -485,6 +476,21 @@
           win->hide ();
         break;
 
+      case figure::properties::ID_RESIZE:
+        if (fp.is_resize ())
+          {
+            win->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred);
+            win->setFixedSize (QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+            m_resizable = true;
+          }
+        else
+          {
+            win->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
+            win->setFixedSize(win->size ());
+            m_resizable = false;
+          }
+        break;
+
       case figure::properties::ID_TOOLBAR:
         if (fp.toolbar_is ("none"))
           showFigureToolBar (false);
@@ -496,7 +502,6 @@
         break;
 
       case figure::properties::ID_MENUBAR:
-        showMenuBar (fp.menubar_is ("figure"));
         if (fp.toolbar_is ("auto"))
           showFigureToolBar (fp.menubar_is ("figure"));
         break;
@@ -533,6 +538,10 @@
 
         break;
 
+      case figure::properties::ID___MOUSE_MODE__:
+        m_container->canvas (m_handle)->setCursor (mouseMode ());
+        break;
+
       default:
         break;
       }
@@ -555,7 +564,7 @@
           r.adjust (0, -dy1, 0, dy2);
 
         m_blockUpdates = true;
-        qWidget<QWidget> ()->setGeometry (r);
+        set_geometry (r);
         m_figureToolBar->setVisible (visible);
         m_statusBar->setVisible (visible);
         m_blockUpdates = false;
@@ -565,50 +574,23 @@
   }
 
   void
-  Figure::showMenuBar (bool visible, int h1)
-  {
-    // Get the height before and after toggling the visibility of builtin menus
-    if (h1 <= 0)
-      h1 = m_menuBar->sizeHint ().height ();
-
-    foreach (QAction *a, m_menuBar->actions ())
-      if (a->objectName () == "builtinMenu")
-        a->setVisible (visible);
-
-    int h2 = m_menuBar->sizeHint ().height ();
-
-    // Keep the menubar visible if it contains custom menus
-    if (! visible)
-      visible = hasUiMenuChildren (properties<figure> ());
-
-    if ((m_menuBar->isVisible () && ! visible)
-        || (! m_menuBar->isVisible () && visible))
-      {
-        int dy = qMax (h1, h2);
-        QRect r = qWidget<QWidget> ()->geometry ();
-
-        if (! visible)
-          r.adjust (0, dy, 0, 0);
-        else
-          r.adjust (0, -dy, 0, 0);
-
-        m_blockUpdates = true;
-        qWidget<QWidget> ()->setGeometry (r);
-        m_menuBar->setVisible (visible);
-        m_blockUpdates = false;
-      }
-    updateBoundingBox (false);
-  }
-
-  void
-  Figure::updateMenuBar (int height)
+  Figure::updateFigureHeight (int dh)
   {
     gh_manager::auto_lock lock;
     graphics_object go = object ();
 
-    if (go.valid_object ())
-      showMenuBar (Utils::properties<figure> (go).menubar_is ("figure"),
-                   height);
+    if (go.valid_object () && dh != 0)
+      {
+        QRect r = qWidget<QWidget> ()->geometry ();
+
+        r.adjust (0, dh, 0, 0);
+
+        m_blockUpdates = true;
+        set_geometry (r);
+        m_blockUpdates = false;
+
+        updateBoundingBox (false);
+      }
   }
 
   void
@@ -647,6 +629,9 @@
         figure::properties& fp = Utils::properties<figure> (go);
 
         fp.set_boundingbox (d->m_bbox, d->m_internal, false);
+
+        if (d->m_internal)
+          emit d->m_figure->asyncUpdate ();
       }
 
     delete d;
@@ -743,18 +728,10 @@
           {
             switch (xevent->type ())
               {
+              case QEvent::ActionAdded:
               case QEvent::ActionChanged:
-                m_previousHeight = m_menuBar->sizeHint ().height ();
-                break;
               case QEvent::ActionRemoved:
-                {
-                  QAction *a = dynamic_cast<QActionEvent *> (xevent)->action ();
-
-                  if (! a->isSeparator ()
-                      && a->objectName () != "builtinMenu")
-                    updateMenuBar ();
-                }
-                break;
+                m_previousHeight = m_menuBar->sizeHint ().height ();
 
               default:
                 break;
@@ -819,24 +796,16 @@
           {
             switch (xevent->type ())
               {
+              case QEvent::ActionAdded:
               case QEvent::ActionChanged:
+              case QEvent::ActionRemoved:
                 // The menubar may have been resized if no action is visible
                 {
                   QAction *a = dynamic_cast<QActionEvent *> (xevent)->action ();
-                  if (m_menuBar->sizeHint ().height () != m_previousHeight
-                      && a->objectName () != "builtinMenu"
+                  int currentHeight = m_menuBar->sizeHint ().height ();
+                  if (currentHeight != m_previousHeight
                       && ! a->isSeparator ())
-                    updateMenuBar (m_previousHeight);
-                }
-                break;
-              case QEvent::ActionAdded:
-                {
-                  QAction *a = dynamic_cast<QActionEvent *> (xevent)->action ();
-
-                  if (! a->isSeparator ()
-                      && a->objectName () != "builtinMenu"
-                      && a->isVisible ())
-                    updateMenuBar ();
+                    updateFigureHeight (m_previousHeight - currentHeight);
                 }
                 break;
 
@@ -865,16 +834,6 @@
   }
 
   void
-  Figure::helpAboutOctave (void)
-  {
-    std::string message
-      = octave_name_version_copyright_copying_warranty_and_bugs (true);
-
-    QMessageBox::about (qWidget<QMainWindow> (), tr ("About Octave"),
-                        QString::fromStdString (message));
-  }
-
-  void
   Figure::setMouseMode (MouseMode mode)
   {
     if (m_blockUpdates)
@@ -893,109 +852,6 @@
   }
 
   void
-  Figure::fileSaveFigure (bool prompt)
-  {
-    QString file = fileName ();
-
-    if (file.isEmpty ())
-      {
-        prompt = true;
-
-        file = "untitled.ofig";
-      }
-
-    if (prompt || file.isEmpty ())
-      {
-        QFileInfo finfo (file);
-
-        file = QFileDialog::getSaveFileName (qWidget<FigureWindow> (),
-                                             tr ("Save Figure As"),
-                                             finfo.absoluteFilePath (),
-                                             tr ("Octave Figure File (*.ofig);;Vector Image Formats (*.eps *.epsc *.pdf *.svg *.ps *.tikz);;Bitmap Image Formats (*.gif *.jpg *.png *.tiff)"),
-                                             nullptr,
-                                             QFileDialog::DontUseNativeDialog);
-      }
-
-    if (! file.isEmpty ())
-      {
-        QFileInfo finfo (file);
-
-        setFileName (finfo.absoluteFilePath ());
-
-        octave_link::post_event (this, &Figure::save_figure_callback,
-                                 file.toStdString ());
-      }
-  }
-
-  void
-  Figure::save_figure_callback (const std::string& file)
-  {
-    figure::properties& fp = properties<figure> ();
-    octave_value fnum = fp.get___myhandle__ ().as_octave_value ();
-
-    size_t flen = file.length ();
-
-    if (flen > 5 && file.substr (flen-5) == ".ofig")
-      Ffeval (ovl ("hgsave", fnum, file));
-    else
-      Ffeval (ovl ("print", fnum, file));
-  }
-
-  void
-  Figure::copy_figure_callback (const std::string& format)
-  {
-    std::string msg;
-
-    std::string file = octave::sys::tempnam ("", "oct-", msg) + '.' + format;
-
-    if (file.empty ())
-      {
-        // Report error?
-        return;
-      }
-
-    save_figure_callback (file);
-
-    octave_link::copy_image_to_clipboard (file);
-  }
-
-  void
-  Figure::fileSaveFigureAs (void)
-  {
-    fileSaveFigure (true);
-  }
-
-  void
-  Figure::fileCloseFigure (void)
-  {
-    qWidget<QMainWindow> ()->close ();
-  }
-
-  void
-  Figure::editCopy (bool /* choose_format */)
-  {
-    QString format = "png";
-
-#if 0
-
-    // FIXME: allow choice of image formats.
-
-    if (choose_format)
-      {
-        QFileInfo finfo (file);
-
-        format = QFileDialog::getSaveFileName (qWidget<FigureWindow> (),
-                                               tr ("Save Figure As"),
-                                               finfo.absoluteFilePath (), 0, 0,
-                                               QFileDialog::DontUseNativeDialog);
-      }
-#endif
-
-    octave_link::post_event (this, &Figure::copy_figure_callback,
-                             format.toStdString ());
-  }
-
-  void
   Figure::addCustomToolBar (QToolBar *bar, bool visible)
   {
     QMainWindow *win = qWidget<QMainWindow> ();
@@ -1011,7 +867,7 @@
         r.adjust (0, -sz.height (), 0, 0);
 
         m_blockUpdates = true;
-        win->setGeometry (r);
+        set_geometry (r);
         win->addToolBarBreak ();
         win->addToolBar (bar);
         m_blockUpdates = false;
@@ -1037,7 +893,7 @@
           r.adjust (0, sz.height (), 0, 0);
 
         m_blockUpdates = true;
-        win->setGeometry (r);
+        set_geometry (r);
         bar->setVisible (visible);
         m_blockUpdates = false;
 
@@ -1079,6 +935,44 @@
   }
 
   void
+  Figure::figureWindowShown ()
+  {
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    QWindow* window = qWidget<QMainWindow> ()->windowHandle ();
+    QScreen* screen = window->screen ();
+
+    gh_manager::auto_lock lock;
+
+    figure::properties& fp = properties<figure> ();
+    fp.set___device_pixel_ratio__ (screen->devicePixelRatio ());
+
+    connect (window, SIGNAL (screenChanged (QScreen*)),
+             this, SLOT (screenChanged (QScreen*)));
+
+#endif
+  }
+
+  void
+  Figure::screenChanged (QScreen* screen)
+  {
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    gh_manager::auto_lock lock;
+
+    figure::properties& fp = properties<figure> ();
+    double old_dpr = fp.get___device_pixel_ratio__ ();
+    double new_dpr = screen->devicePixelRatio ();
+    if (old_dpr != new_dpr)
+      {
+        fp.set___device_pixel_ratio__ (new_dpr);
+
+        // For some obscure reason, changing the __device_pixel_ratio__ property
+        // from the GUI thread does not necessarily trigger a redraw. Force it.
+        redraw ();
+      }
+#endif
+  }
+
+  void
   Figure::enableMouseTracking (void)
   {
     // Enable mouse tracking on every widgets
--- a/libgui/graphics/Figure.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Figure.h	Thu Dec 20 17:18:56 2018 -0500
@@ -32,6 +32,7 @@
 
 class QMainWindow;
 class QToolBar;
+class QScreen;
 
 namespace QtHandles
 {
@@ -46,8 +47,7 @@
     ZoomInMode  = 2,
     ZoomOutMode = 3,
     PanMode     = 4,
-    TextMode    = 5,
-    SelectMode  = 6
+    TextMode    = 5
   };
 
   class Container;
@@ -94,6 +94,7 @@
 
   protected:
     void redraw (void);
+    void show (void);
     void print (const QString& file_cmd, const QString& term);
     void update (int pId);
     void updateBoundingBox (bool internal = false, int flags = 0);
@@ -102,32 +103,26 @@
   private:
     void createFigureToolBarAndMenuBar (void);
     void showFigureToolBar (bool visible);
-    void showMenuBar (bool visible, int height = -1);
     void addCustomToolBar (QToolBar *bar, bool visible);
     void showCustomToolBar (QToolBar *bar, bool visible);
-
     void updateFigureToolBarAndMenuBar (void);
+    void set_geometry (QRect r);
 
     static void updateBoundingBoxHelper (void*);
 
     void close_figure_callback (void);
-    void copy_figure_callback (const std::string& format);
-    void save_figure_callback (const std::string& file);
 
     void enableMouseTracking (void);
 
   private slots:
     void setMouseMode (MouseMode mode);
-    void fileSaveFigure (bool prompt = false);
-    void fileSaveFigureAs (void);
-    void fileCloseFigure (void);
-    void editCopy (bool choose_format = false);
-    void helpAboutOctave (void);
-    void updateMenuBar (int height = -1);
+    void updateFigureHeight (int delta_h);
     void updateContainer (void);
     void toggleAxes (void);
     void toggleGrid (void);
     void autoAxes (void);
+    void figureWindowShown ();
+    void screenChanged (QScreen*);
 
   public slots:
     uint8NDArray slotGetPixels (void);
@@ -145,6 +140,7 @@
     QRect m_outerRect;
     MouseModeActionGroup *m_mouseModeGroup;
     int m_previousHeight;
+    bool m_resizable;
   };
 
 }
--- a/libgui/graphics/FigureWindow.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/FigureWindow.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -48,4 +48,10 @@
     return nullptr;
   }
 
+  void FigureWindow::showEvent (QShowEvent* ev)
+  {
+    QMainWindow::showEvent (ev);
+    emit figureWindowShown();
+  }
+
 }
--- a/libgui/graphics/FigureWindow.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/FigureWindow.h	Thu Dec 20 17:18:56 2018 -0500
@@ -37,10 +37,17 @@
     Q_OBJECT
 
   public:
-    FigureWindow (QWidget *parent = nullptr);
+    explicit FigureWindow (QWidget *parent = nullptr);
     ~FigureWindow (void);
 
     QMenu * createPopupMenu (void);
+
+  protected:
+    void showEvent(QShowEvent *ev);
+
+  signals:
+    void figureWindowShown();
+
   };
 
 }
--- a/libgui/graphics/GLCanvas.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/GLCanvas.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -49,7 +49,7 @@
 
   GLCanvas::GLCanvas (QWidget *xparent, const graphics_handle& gh)
     : OCTAVE_QT_OPENGL_WIDGET (OCTAVE_QT_OPENGL_WIDGET_FORMAT_ARGS xparent),
-      Canvas (gh)
+      Canvas (gh), m_glfcns (), m_renderer (m_glfcns)
   {
     setFocusPolicy (Qt::ClickFocus);
     setFocus ();
@@ -59,6 +59,12 @@
   { }
 
   void
+  GLCanvas::initializeGL (void)
+  {
+    m_glfcns.init ();
+  }
+
+  void
   GLCanvas::draw (const graphics_handle& gh)
   {
     gh_manager::auto_lock lock;
@@ -66,10 +72,11 @@
 
     if (go)
       {
-        octave::opengl_renderer r;
-
-        r.set_viewport (width (), height ());
-        r.draw (go);
+        graphics_object fig = go.get_ancestor ("figure");
+        double dpr = fig.get ("__device_pixel_ratio__").double_value ();
+        m_renderer.set_viewport (dpr * width (), dpr * height ());
+        m_renderer.set_device_pixel_ratio (dpr);
+        m_renderer.draw (go);
       }
   }
 
@@ -82,6 +89,9 @@
     if (go && go.isa ("figure"))
       {
         Matrix pos = go.get ("position").matrix_value ();
+        double dpr = go.get ("__device_pixel_ratio__").double_value ();
+        pos(2) *= dpr;
+        pos(3) *= dpr;
 
         // Make sure we have a valid current context
         if (! begin_rendering ())
@@ -94,23 +104,24 @@
             || go.get ("__printing__").string_value () == "on")
           {
             OCTAVE_QT_OPENGL_FBO
-            fbo (pos(2), pos(3),OCTAVE_QT_OPENGL_FBO::Attachment::Depth);
+            fbo (pos(2), pos(3),
+                 OCTAVE_QT_OPENGL_FBO::Attachment::Depth);
 
             fbo.bind ();
 
-            octave::opengl_renderer r;
-            r.set_viewport (pos(2), pos(3));
-            r.draw (go);
-            retval = r.get_pixels (pos(2), pos(3));
+            m_renderer.set_viewport (pos(2), pos(3));
+            m_renderer.set_device_pixel_ratio (dpr);
+            m_renderer.draw (go);
+            retval = m_renderer.get_pixels (pos(2), pos(3));
 
             fbo.release ();
           }
         else
           {
-            octave::opengl_renderer r;
-            r.set_viewport (pos(2), pos(3));
-            r.draw (go);
-            retval = r.get_pixels (pos(2), pos(3));
+            m_renderer.set_viewport (pos(2), pos(3));
+            m_renderer.set_device_pixel_ratio (dpr);
+            m_renderer.draw (go);
+            retval = m_renderer.get_pixels (pos(2), pos(3));
           }
 
         end_rendering ();
@@ -135,7 +146,7 @@
             if (! begin_rendering ())
               error ("print: no valid OpenGL offscreen context");
 
-            octave::gl2ps_print (figObj, file_cmd.toStdString (),
+            octave::gl2ps_print (m_glfcns, figObj, file_cmd.toStdString (),
                                  term.toStdString ());
           }
         catch (octave::execution_exception& e)
@@ -171,7 +182,7 @@
 
     if (ax)
       {
-        octave::opengl_selector s;
+        octave::opengl_selector s (m_glfcns);
 
         s.set_viewport (width (), height ());
         return s.select (ax, pt.x (), height () - pt.y (),
@@ -181,49 +192,22 @@
     return graphics_object ();
   }
 
-  inline void
-  glDrawZoomBox (const QPoint& p1, const QPoint& p2)
-  {
-    glVertex2d (p1.x (), p1.y ());
-    glVertex2d (p2.x (), p1.y ());
-    glVertex2d (p2.x (), p2.y ());
-    glVertex2d (p1.x (), p2.y ());
-    glVertex2d (p1.x (), p1.y ());
-  }
-
   void
   GLCanvas::drawZoomBox (const QPoint& p1, const QPoint& p2)
   {
-    glMatrixMode (GL_MODELVIEW);
-    glPushMatrix ();
-    glLoadIdentity ();
-
-    glMatrixMode (GL_PROJECTION);
-    glPushMatrix ();
-    glLoadIdentity ();
-    glOrtho (0, width (), height (), 0, 1, -1);
-
-    glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
-    glDisable (GL_DEPTH_TEST);
+    Matrix overlaycolor (3, 1);
+    overlaycolor(0) = 0.45;
+    overlaycolor(1) = 0.62;
+    overlaycolor(2) = 0.81;
+    double overlayalpha = 0.1;
+    Matrix bordercolor = overlaycolor;
+    double borderalpha = 0.9;
+    double borderwidth = 1.5;
 
-    glBegin (GL_POLYGON);
-    glColor4f (0.45, 0.62, 0.81, 0.1);
-    glDrawZoomBox (p1, p2);
-    glEnd ();
-
-    glLineWidth (1.5);
-    glBegin (GL_LINE_STRIP);
-    glColor4f (0.45, 0.62, 0.81, 0.9);
-    glDrawZoomBox (p1, p2);
-    glEnd ();
-
-    glPopAttrib ();
-
-    glMatrixMode (GL_MODELVIEW);
-    glPopMatrix ();
-
-    glMatrixMode (GL_PROJECTION);
-    glPopMatrix ();
+    m_renderer.draw_zoom_box (width (), height (),
+                              p1.x (), p1.y (), p2.x (), p2.y (),
+                              overlaycolor, overlayalpha,
+                              bordercolor, borderalpha, borderwidth);
   }
 
   void
--- a/libgui/graphics/GLCanvas.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/GLCanvas.h	Thu Dec 20 17:18:56 2018 -0500
@@ -43,6 +43,9 @@
 
 #include "Canvas.h"
 
+#include "gl-render.h"
+#include "qopengl-functions.h"
+
 namespace QtHandles
 {
   class GLCanvas : public OCTAVE_QT_OPENGL_WIDGET, public Canvas
@@ -51,6 +54,8 @@
     GLCanvas (QWidget *parent, const graphics_handle& handle);
     ~GLCanvas (void);
 
+    void initializeGL (void);
+
     void draw (const graphics_handle& handle);
     uint8NDArray  do_getPixels (const graphics_handle& handle);
     void do_print (const QString& file_cmd, const QString& term,
@@ -80,10 +85,13 @@
     bool begin_rendering (void);
     void end_rendering (void);
 
-# if defined (HAVE_QT_OFFSCREEN)
+    octave::qopengl_functions m_glfcns;
+    octave::opengl_renderer m_renderer;
+
+#  if defined (HAVE_QT_OFFSCREEN)
     QOpenGLContext m_os_context;
     QOffscreenSurface m_os_surface;
-# endif
+#  endif
   };
 
 }
--- a/libgui/graphics/MouseModeActionGroup.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/MouseModeActionGroup.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,8 +50,12 @@
                                    tr ("Pan"), this));
     m_actions.append (new QAction (QIcon::fromTheme ("insert-text"),
                                    tr ("Insert Text"), this));
+    /*
+    // FIXME: Re-instate this button when the plotedit function
+    //        has been implemented.
     m_actions.append (new QAction (QIcon (":/images/select.png"),
                                    tr ("Select"), this));
+    */
 
     foreach (QAction *a, m_actions)
       {
@@ -83,10 +87,7 @@
             m_current = m_actions[i];
             for (int j = 0; j < m_actions.size (); j++)
               {
-                // SelectMode cancels all the others but the button
-                // doesn't remain highlighed.
-
-                if (j != i || i+1 == SelectMode)
+                if (j != i)
                   m_actions[j]->setChecked (false);
               }
 
@@ -100,12 +101,6 @@
   {
     for (int i = 0; i < m_actions.size (); i++)
       m_actions[i]->setChecked (i+1 == mode);
-
-    // SelectMode cancels all the others but the button doesn't remain
-    // highlighed.
-
-    if (mode == SelectMode)
-      m_actions[SelectMode-1]->setChecked (false);
   }
 
 };
--- a/libgui/graphics/Object.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Object.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -120,6 +120,15 @@
   }
 
   void
+  Object::slotShow (void)
+  {
+    gh_manager::auto_lock lock;
+
+    if (object ().valid_object ())
+      show ();
+  }
+
+  void
   Object::slotPrint (const QString& file_cmd, const QString& term)
   {
     gh_manager::auto_lock lock;
@@ -148,6 +157,10 @@
   { }
 
   void
+  Object::show (void)
+  { }
+
+  void
   Object::print (const QString& /* file_cmd */, const QString& /* term */)
   { }
 
--- a/libgui/graphics/Object.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/Object.h	Thu Dec 20 17:18:56 2018 -0500
@@ -81,6 +81,7 @@
     void slotUpdate (int pId);
     void slotFinalize (void);
     void slotRedraw (void);
+    void slotShow (void);
     void slotPrint (const QString& file_cmd, const QString& term);
 
     void objectDestroyed (QObject *obj = nullptr);
@@ -92,6 +93,7 @@
     virtual void update (int pId);
     virtual void finalize (void);
     virtual void redraw (void);
+    virtual void show (void);
     virtual void print (const QString& file_cmd, const QString& term);
 
     virtual void beingDeleted (void);
--- a/libgui/graphics/ObjectFactory.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/ObjectFactory.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -46,6 +46,7 @@
 #include "PushTool.h"
 #include "RadioButtonControl.h"
 #include "SliderControl.h"
+#include "Table.h"
 #include "TextControl.h"
 #include "ToggleButtonControl.h"
 #include "ToggleTool.h"
@@ -128,6 +129,8 @@
                   obj = Menu::create (go);
                 else if (go.isa ("uicontextmenu"))
                   obj = ContextMenu::create (go);
+                else if (go.isa ("uitable"))
+                  obj = Table::create (go);
                 else if (go.isa ("uitoolbar"))
                   obj = ToolBar::create (go);
                 else if (go.isa ("uipushtool"))
--- a/libgui/graphics/ObjectProxy.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/ObjectProxy.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -56,6 +56,8 @@
                         m_object, SLOT (slotFinalize (void)));
             disconnect (this, SIGNAL (sendRedraw (void)),
                         m_object, SLOT (slotRedraw (void)));
+            disconnect (this, SIGNAL (sendShow (void)),
+                        m_object, SLOT (slotShow (void)));
             disconnect (this, SIGNAL (sendPrint (const QString&, const QString&)),
                         m_object, SLOT (slotPrint (const QString&, const QString&)));
           }
@@ -70,6 +72,8 @@
                      m_object, SLOT (slotFinalize (void)));
             connect (this, SIGNAL (sendRedraw (void)),
                      m_object, SLOT (slotRedraw (void)));
+            connect (this, SIGNAL (sendShow (void)),
+                     m_object, SLOT (slotShow (void)));
             connect (this, SIGNAL (sendPrint (const QString&, const QString&)),
                      m_object, SLOT (slotPrint (const QString&, const QString&)),
                      Qt::BlockingQueuedConnection);
@@ -107,6 +111,12 @@
   }
 
   void
+  ObjectProxy::show (void)
+  {
+    emit sendShow ();
+  }
+
+  void
   ObjectProxy::print (const QString& file_cmd, const QString& term)
   {
     emit sendPrint (file_cmd, term);
@@ -135,11 +145,11 @@
     if (! QMetaObject::invokeMethod (m_object, "slotGetPixels", t,
                                      Q_RETURN_ARG (uint8NDArray, retval)))
       {
-        octave_sleep (0.1);
+        octave::sleep (0.1);
         if (! QMetaObject::invokeMethod (m_object, "slotGetPixels", t,
                                          Q_RETURN_ARG (uint8NDArray, retval)))
           {
-            octave_sleep (0.2);
+            octave::sleep (0.2);
             if (! QMetaObject::invokeMethod (m_object, "slotGetPixels", t,
                                              Q_RETURN_ARG (uint8NDArray, retval)))
               error ("getframe: unable to retrieve figure pixels");
--- a/libgui/graphics/ObjectProxy.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/ObjectProxy.h	Thu Dec 20 17:18:56 2018 -0500
@@ -44,6 +44,7 @@
     void update (int pId);
     void finalize (void);
     void redraw (void);
+    void show (void);
     void print (const QString& file_cmd, const QString& term);
     uint8NDArray get_pixels (void);
 
@@ -54,6 +55,7 @@
     void sendUpdate (int pId);
     void sendFinalize (void);
     void sendRedraw (void);
+    void sendShow (void);
     void sendPrint (const QString& file_cmd, const QString& term);
 
   private:
--- a/libgui/graphics/PopupMenuControl.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/PopupMenuControl.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -104,7 +104,7 @@
 
           if (value.numel () > 0)
             {
-              if (value(0) != static_cast<int>(value(0)))
+              if (value(0) != static_cast<int> (value(0)))
                 warning ("popupmenu value should be integer");
               else
                 {
--- a/libgui/graphics/PushButtonControl.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/PushButtonControl.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -54,7 +54,13 @@
                                         QPushButton *btn)
     : ButtonControl (go, btn)
   {
+    uicontrol::properties& up = properties<uicontrol> ();
+
     btn->setAutoFillBackground (true);
+    octave_value cdat = up.get_cdata ();
+    QImage img = Utils::makeImageFromCData (cdat,
+                                            cdat.rows (), cdat.columns ());
+    btn->setIcon (QIcon (QPixmap::fromImage (img)));
   }
 
   PushButtonControl::~PushButtonControl (void)
@@ -68,12 +74,18 @@
 
     switch (pId)
       {
-      case uicontrol::properties::ID_STRING:
-        btn->setText (Utils::fromStdString (up.get_string_string ()));
+      case uicontrol::properties::ID_CDATA:
+        {
+          octave_value cdat = up.get_cdata ();
+          QImage img = Utils::makeImageFromCData (cdat,
+                                                  cdat.rows (),
+                                                  cdat.columns ());
+          btn->setIcon (QIcon (QPixmap::fromImage (img)));
+        }
         break;
 
       default:
-        BaseControl::update (pId);
+        ButtonControl::update (pId);
         break;
       }
   }
--- a/libgui/graphics/QtHandlesUtils.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/QtHandlesUtils.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,13 +50,13 @@
     QString
     fromStdString (const std::string& s)
     {
-      return QString::fromLocal8Bit (s.c_str ());
+      return QString::fromUtf8 (s.c_str ());
     }
 
     std::string
     toStdString (const QString& s)
     {
-      return std::string (s.toLocal8Bit ().data ());
+      return std::string (s.toUtf8 ().data ());
     }
 
     QStringList
@@ -140,6 +140,10 @@
     template QFont computeFont<uibuttongroup> (const uibuttongroup::properties&
         props,
         int height);
+
+    template QFont computeFont<uitable> (const uitable::properties& props,
+                                         int height);
+
     QColor
     fromRgb (const Matrix& rgb)
     {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Table.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,1705 @@
+/*
+
+Copyright (C) 2016 Andrew Thornton
+
+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 <QEvent>
+#include <QFrame>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QTimer>
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QHeaderView>
+#include <QLineEdit>
+#include <QModelIndexList>
+#include <QString>
+#include <QStringList>
+#include <QTableWidget>
+#include <QTableWidgetItem>
+#include <QHBoxLayout>
+
+#include "Container.h"
+#include "ContextMenu.h"
+#include "Table.h"
+#include "QtHandlesUtils.h"
+
+#include "oct-stream.h"
+#include "oct-string.h"
+#include "oct-strstrm.h"
+#include "ov-struct.h"
+
+namespace QtHandles
+{
+
+  static const int AUTO_WIDTH = 75;
+
+#define AUTO_HEIGHT tp.get_fontsize () * 2 - 1
+
+  static QSize realQSizeForTable (QTableWidget *t)
+  {
+    int w = t->verticalHeader ()->width () + 4;
+    for (int i = 0; i < t->columnCount (); i++)
+      w += t->columnWidth (i);
+    int h = t->horizontalHeader ()->height () + 4;
+    for (int i = 0; i < t->rowCount (); i++)
+      h += t->rowHeight (i);
+    return QSize (w, h);
+  }
+
+#define FORMATNUMBER(type)                                                    \
+  static QString formatNumber (type d,                                        \
+                               char format = 'f',                             \
+                               int precision = 4)                             \
+  {                                                                           \
+    if (format == 'n')                                                        \
+      {                                                                       \
+        if (d == floor (d))                                                   \
+          return QString::number (d, 'g', precision);                         \
+        else if (d <= pow (10, precision - 1) && d > pow (10, 1 - precision)) \
+          return QString::number (d, 'f', precision);                         \
+        else                                                                  \
+          return QString::number (d, 'e', precision);                         \
+      }                                                                       \
+    else if (format == 'F')                                                   \
+      {                                                                       \
+        int exponent = floor (log10 (d) / 3) * 3;                             \
+        d *= pow (10, -exponent);                                             \
+        return QString::number (d, 'f', precision) + "e" +                    \
+          (exponent < 0 ? "-" : "+") +                                        \
+          QString ("%1").arg (abs (exponent), 3, 10, QChar ('0'));            \
+      }                                                                       \
+    else if (format == 'E')                                                   \
+      {                                                                       \
+        int exponent = floor (log10 (d) / 3) * 3;                             \
+        d *=  pow (10, -exponent);                                            \
+        return QString::number (d,                                            \
+                                'f',                                          \
+                                precision - floor (log10 (d)) - 1) +          \
+               "e" + (exponent < 0 ? "-" : "+") +                             \
+               QString ("%1").arg (abs (exponent), 3, 10, QChar ('0'));       \
+      }                                                                       \
+    else                                                                      \
+      return QString::number (d, format, precision);                          \
+  }
+
+  FORMATNUMBER(double)
+  FORMATNUMBER(float)
+
+#undef FORMATNUMBER
+
+  static QString formatComplex (Complex c, char format = 'f', int precision = 4)
+  {
+    return formatNumber (c.real (), format, precision) + " + "
+           + formatNumber (c.imag (), format, precision) + "i";
+  }
+
+#define FORMAT_VALUE_EXCEPT_RAT(f,l)                      \
+  if (format == "numeric" || format == "short")           \
+    text = formatNumber (value, 'n', f);                  \
+  else if (format == "short f" || format == "shortf")     \
+    text = formatNumber (value, 'f', f);                  \
+  else if (format == "short e" || format == "shorte")     \
+    text = formatNumber (value, 'e', f);                  \
+  else if (format == "short eng" || format == "shorteng") \
+    text = formatNumber (value, 'F', f);                  \
+  else if (format == "short g" || format == "shortg")     \
+    text = formatNumber (value, 'g', f + 1);              \
+  else if (format == "long")                              \
+    text = formatNumber (value, 'n', l);                  \
+  else if (format == "long f" || format == "longf")       \
+    text = formatNumber (value, 'f', l);                  \
+  else if (format == "long e" || format == "longe")       \
+    text = formatNumber (value, 'e', l);                  \
+  else if (format == "long eng" || format == "longeng")   \
+    text = formatNumber (value, 'E', l);                  \
+  else if (format == "long g" || format == "longg")       \
+    text = formatNumber (value, 'g', l + 1);              \
+  else if (format == "bank")                              \
+    text = QString::number (value, 'f', 2);               \
+  else if (format == "+")                                 \
+    if (value > 0)                                        \
+      text = Utils::fromStdString ("+");                  \
+    else if (value < 0)                                   \
+      text = Utils::fromStdString ("-");                  \
+    else                                                  \
+      text = Utils::fromStdString ("");
+
+#define FORMAT_VALUE(f,l)                                               \
+  FORMAT_VALUE_EXCEPT_RAT(f,l)                                          \
+  else if (format == "rat")                                             \
+    text = Utils::fromStdString (rational_approx (double (value), 0));  \
+  else                                                                  \
+    {                                                                   \
+      text = formatNumber (value, 'n', f);                              \
+      flag = Qt::AlignLeft ;                                            \
+    }
+
+#define FORMAT_UINT_VALUE()                    \
+  text = QString::number (value);              \
+  if (format == "char"  || format == "popup")  \
+    flag = Qt::AlignLeft;                      \
+  else if (format == "+")                      \
+    {                                          \
+      if (value > 0)                           \
+        text = Utils::fromStdString ("+");     \
+      else                                     \
+        text = Utils::fromStdString ("");      \
+    }
+
+#define FORMAT_INT_VALUE()                     \
+  text = QString::number (value);              \
+  if (format == "char" || format == "popup")   \
+    flag = Qt::AlignLeft ;                     \
+  else if (format == "+")                      \
+    {                                          \
+      if (value > 0)                           \
+        text = Utils::fromStdString ("+");     \
+      else if (value < 0)                      \
+        text = Utils::fromStdString ("-");     \
+      else                                     \
+        text = Utils::fromStdString ("");      \
+    }
+
+  static std::pair<Qt::AlignmentFlag, QString> qStringValueFor (
+    octave_value val, std::string format = "")
+  {
+    Qt::AlignmentFlag flag = Qt::AlignRight;
+    QString text;
+    if (val.is_string ())
+      {
+        text = QtHandles::Utils::fromStdString (val.string_value ());
+        flag = Qt::AlignLeft ;
+      }
+    else if (val.iscomplex ())
+      {
+        // Matlab has multiple complex types, we only have double.
+        Complex c = val.complex_value ();
+        if (format == "short")
+          text = formatComplex (c, 'f', 4);
+        else if (format == "short e" || format == "shorte")
+          text = formatComplex (c, 'e', 4);
+        else if (format == "short eng" || format == "shorteng")
+          text = formatComplex (c, 'E', 4);
+        else if (format == "short g" || format == "shortg")
+          text = formatComplex (c, 'g', 5);
+        else if (format == "long")
+          text = formatComplex (c, 'f', 15);
+        else if (format == "long e" || format == "longe")
+          text = formatComplex (c, 'e', 15);
+        else if (format == "long eng" || format == "longeng")
+          text = formatComplex (c, 'E', 15);
+        else if (format == "long g" || format == "longg")
+          text = formatComplex (c, 'g', 16);
+        else if (format == "bank")
+          text = QString::number (c.real (), 'f', 2);
+        else if (format == "+")
+          {
+            if (c.real () > 0)
+              text = Utils::fromStdString ("+");
+            else if (c.real () < 0)
+              text = Utils::fromStdString ("-");
+            else
+              text = Utils::fromStdString ("");
+          }
+        else if (format == "rat")
+          text = Utils::fromStdString (rational_approx (c.real (), 0)) + " + "
+                 + Utils::fromStdString (rational_approx (c.imag (), 0)) + "i";
+        else if (format == "numeric")
+          text = QString::number (c.real (), 'g', 5) + " + "
+                 + QString::number (c.imag (), 'g', 5) + "i";
+        else
+          {
+            text = QString::number (c.real (), 'g', 5) + " + "
+                   + QString::number (c.imag (), 'g', 5) + "i";
+            flag = Qt::AlignLeft ;
+          }
+      }
+    else if (val.is_double_type () )
+      {
+        double value = val.double_value ();
+        FORMAT_VALUE(4, 15)
+      }
+    else if (val.is_single_type ())
+      {
+        float value = val.float_value ();
+        FORMAT_VALUE(4, 7)
+      }
+    else if (val.is_int8_type ())
+      {
+        short int value = val.short_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint8_type ())
+      {
+        unsigned short int value = val.ushort_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int16_type ())
+      {
+        int value = val.int_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint16_type ())
+      {
+        unsigned int value = val.uint_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int32_type ())
+      {
+        long int value = val.long_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint32_type ())
+      {
+        unsigned long int value = val.ulong_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int64_type ())
+      {
+        int64_t value = val.int64_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint64_type ())
+      {
+        uint64_t value = val.uint64_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.islogical ())
+      {
+        bool b = val.bool_value ();
+        if (format == "char" || format == "popup" || format == "")
+          {
+            text = Utils::fromStdString (b ? "true" : "false");
+            flag = Qt::AlignLeft ;
+          }
+        else if (format == "+")
+          {
+            text = Utils::fromStdString (b ? "+" : "");
+            flag = Qt::AlignLeft ;
+          }
+        else
+          text = Utils::fromStdString (b ? "1" : "0");
+      }
+    else
+      {
+        std::stringstream warn_string;
+        warn_string << "Unknown conversion for datatype " << val.class_name ()
+                    << " to " << format
+                    << " for value " << val.string_value (true);
+        warning ("%s", warn_string.str ().c_str ());
+
+        text = Utils::fromStdString (val.string_value (true));
+      }
+
+    return std::make_pair (flag, text);
+  }
+
+#undef FORMAT_VALUE
+#undef FORMAT_VALUE_EXCEPT_RAT
+#undef FORMAT_UINT_VALUE
+#undef FORMAT_INT_VALUE
+
+  static QTableWidgetItem * itemFor (octave_value val, std::string format = "",
+                                     bool enabled = false)
+  {
+    QTableWidgetItem *retval = new QTableWidgetItem ();
+    std::pair<Qt::AlignmentFlag, QString> flag_and_text =
+      qStringValueFor (val, format);
+    retval->setTextAlignment (flag_and_text.first);
+    retval->setText (flag_and_text.second);
+
+    if (enabled)
+      retval->setFlags (retval->flags () | Qt::ItemIsEditable);
+    else
+      retval->setFlags (retval->flags () & ~Qt::ItemIsEditable);
+
+    return retval;
+  }
+
+  static octave_value
+  attempt_type_conversion (const octave_value& ov,
+                           const octave_value& old_value)
+  {
+    octave_value retval;
+
+    // Define a macro to help with the conversion of strings to integers
+    // FIXME: these will happily integer overflow in the (u)int64 case
+    // - this probably doesn't matter.
+#define SCANF_AND_CONVERT(name,ctype,format)           \
+  else if (old_value.is_ ## name ## _type ())          \
+    {                                                  \
+      ctype val;                                       \
+      int n;                                           \
+      const char *c_str = ov.string_value ().c_str (); \
+      int error = sscanf (c_str, format, &val, &n);    \
+      if (error != 1 || c_str[n])                      \
+        {                                              \
+          val = 0;                                     \
+        }                                              \
+      retval = octave_value ( octave_ ## name (val));  \
+    }
+
+    if (old_value.is_string ())
+      retval = ov;
+    SCANF_AND_CONVERT(int8, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint8, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int16, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint16, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int32, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint32, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int64, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint64, uint64_t, "%ju %n")
+
+  #undef SCANF_AND_CONVERT
+
+    else if (old_value.isnumeric () && ! old_value.isinteger ())
+      {
+        // Basically need to do str2double
+        Complex complex = octave::string::str2double (ov.string_value ());
+        if (old_value.is_single_type ())
+          retval = octave_value (FloatComplex (complex));
+        else
+          retval = octave_value (complex);
+      }
+    else if (old_value.islogical ())
+      {
+        // Right: Matlab basically needs this to be true or false, we should
+        // accept 1 too.
+        if (ov.string_value ()  == "true" || ov.string_value () == "1")
+          retval = octave_value (true);
+        else
+          retval = octave_value (false);
+      }
+    else
+      retval = octave_value (octave::string::str2double (ov.string_value ()));
+    return retval;
+  }
+
+  QWidget *
+  Table::checkBoxForLogical (octave_value val, bool enabled = false)
+  {
+    QWidget *retval = new QWidget (m_tableWidget);
+    QCheckBox *checkBox = new QCheckBox ();
+    QHBoxLayout *layout = new QHBoxLayout (retval);
+    layout->addWidget (checkBox);
+    layout->setAlignment (Qt::AlignCenter);
+    layout->setContentsMargins (0, 0, 0, 0);
+    retval->setLayout (layout);
+
+    if ((val.islogical () || val.is_bool_scalar ()) && val.bool_value ())
+      checkBox->setCheckState (Qt::Checked);
+    else
+      checkBox->setCheckState (Qt::Unchecked);
+
+    checkBox->setAttribute (Qt::WA_TransparentForMouseEvents, true);
+    checkBox->setFocusPolicy (Qt::NoFocus);
+    checkBox->setProperty ("Enabled", QVariant (enabled));
+
+    return retval;
+  }
+
+  Table*
+  Table::create (const graphics_object& go)
+  {
+    Object *parent = Object::parentObject (go);
+
+    if (parent)
+      {
+        Container *container = parent->innerContainer ();
+
+        if (container)
+          return new Table (go, new QTableWidget (container));
+      }
+
+    return 0;
+  }
+
+  Table::Table (const graphics_object& go, QTableWidget *tableWidget)
+    : Object (go, tableWidget), m_tableWidget (tableWidget), m_curData (),
+      m_blockUpdates (false)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    m_curData = octave_value (tp.get_data ());
+    Matrix bb = tp.get_boundingbox (false);
+    m_tableWidget->setObjectName ("UITable");
+    m_tableWidget->setAutoFillBackground (true);
+    m_tableWidget->setGeometry (octave::math::round (bb(0)),
+                                octave::math::round (bb(1)),
+                                octave::math::round (bb(2)),
+                                octave::math::round (bb(3)));
+    m_tableWidget->setFont (Utils::computeFont<uitable> (tp)) ;
+    m_tableWidget->setSelectionBehavior (QAbstractItemView::SelectItems);
+    updatePalette ();
+    m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
+    m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
+    updateData ();
+    updateRowname ();
+    updateColumnname ();
+    updateColumnwidth ();
+    updateEnable ();  // Also does rearrangeableColumns
+    m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+    m_tableWidget->setVisible (tp.is_visible ());
+    updateExtent ();
+    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)));
+  }
+
+  Table::~Table (void) { }
+
+  void
+  Table::itemSelectionChanged ()
+  {
+    if (! (properties<uitable> ().get_cellselectioncallback ().isempty ()))
+      {
+        QModelIndexList modelIndexList =
+          m_tableWidget->selectionModel ()->selectedIndexes ();
+        int length = modelIndexList.size ();
+        Matrix indices = Matrix (length, 2);
+        for (int i = 0; i < length; i++)
+          {
+            indices(i, 0) = modelIndexList.value (i).row () + 1;
+            indices(i, 1) = modelIndexList.value (i).column () + 1;
+          }
+        octave_scalar_map eventData;
+        eventData.setfield ("Indices", indices);
+        octave_value cellSelectionCallbackEventObject =
+          octave_value (new octave_struct (eventData));
+        gh_manager::post_callback (m_handle,
+                                   "cellselectioncallback",
+                                   cellSelectionCallbackEventObject);
+      }
+  }
+
+  void
+  Table::cellClicked (int row, int col)
+  {
+    QCheckBox *checkBox = nullptr;
+    QWidget *widget = qobject_cast<QWidget *> (
+                        m_tableWidget->cellWidget (row, col));
+    if (widget && ! widget->children ().isEmpty ())
+      {
+        QHBoxLayout *layout = qobject_cast<QHBoxLayout *> (
+                                widget->children ().first ());
+        if (layout && layout->count () > 0)
+          {
+            checkBox = qobject_cast<QCheckBox *> (
+                         layout->itemAt (0)-> widget ());
+          }
+      }
+    if (checkBox && checkBox->property ("Enabled").toBool ())
+      checkBoxClicked (row, col, checkBox);
+  }
+
+  void
+  Table::sendCellEditCallback (int row,
+                               int col,
+                               octave_value old_value,
+                               octave_value new_value,
+                               octave_value edit_data,
+                               octave_value error)
+  {
+
+    if (!(properties<uitable> ().get_celleditcallback ().isempty ()))
+      {
+        Matrix indices = Matrix (1, 2);
+        indices(0, 0) = row + 1;
+        indices(0, 1) = col + 1;
+
+        octave_scalar_map eventData;
+        eventData.setfield ("Indices", indices);
+        eventData.setfield ("PreviousData", old_value);
+        eventData.setfield ("NewData", new_value);
+        eventData.setfield ("EditData", edit_data);
+        eventData.setfield ("Error", error);
+
+        octave_value cellEditCallbackEventObject =
+          octave_value (new octave_struct (eventData));
+
+        gh_manager::post_callback (m_handle,
+                                   "celleditcallback",
+                                   cellEditCallbackEventObject);
+      }
+    else if (error.string_value ().length () > 0)
+      warning ("%s", error.string_value ().c_str ());
+  }
+
+  void
+  Table::comboBoxCurrentIndexChanged (const QString& value)
+  {
+    if (m_blockUpdates)
+      return;
+
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+    octave_value data = octave_value (m_curData);
+    bool ok = false;
+
+    QComboBox *comboBox = qobject_cast<QComboBox *> (sender ());
+    int row = comboBox->property ("row").toInt ();
+    int col = comboBox->property ("col").toInt ();
+
+    octave_value edit_data = octave_value (Utils::toStdString (value));
+
+    if (row < data.rows () && col < data.columns ())
+      {
+        if (data.iscell ())
+          {
+            Cell cell = data.cell_value ();
+            octave_value old_data = cell(row, col);
+            if (cell(row, col).is_string ())
+              {
+                cell(row, col) = edit_data;
+                if (edit_data.string_value () != old_data.string_value ())
+                  {
+                    m_curData = octave_value (cell);
+                    gh_manager::post_set (m_handle,
+                                          "data",
+                                          octave_value (cell),
+                                          false);
+                  }
+
+                octave_value error = octave_value ("");
+                sendCellEditCallback (row, col,
+                                      old_data,
+                                      edit_data,
+                                      edit_data,
+                                      error);
+                ok = true;
+              }
+            else
+              {
+                cell(row, col) = attempt_type_conversion (edit_data, old_data);
+
+                // Inform the QTableWidget of our change
+                updateData (row, col, cell(row, col),
+                            columnformat (col), columneditable (col));
+
+                m_curData = octave_value (cell);
+                gh_manager::post_set (m_handle, "data", octave_value (cell), false);
+
+                octave_value error = octave_value ("");
+                sendCellEditCallback (row,
+                                      col,
+                                      old_data,
+                                      cell(row, col),
+                                      edit_data,
+                                      error);
+                ok = true;
+              }
+          }
+        else
+          {
+            octave_value old_data = data.is_matrix_type ()
+                                    ? data.fast_elem_extract (row + col * data.rows ())
+                                    : octave_value ();
+            data.fast_elem_insert (row + col * data.rows (),
+                                   attempt_type_conversion (edit_data, old_data));
+
+            // Inform the QTableWidget of our change
+            updateData (row,
+                        col,
+                        data.fast_elem_extract (row + col * data.rows ()),
+                        columnformat (col),
+                        columneditable (col));
+
+            m_curData = octave_value (data);
+            gh_manager::post_set (m_handle, "data", data, false);
+
+            octave_value error = octave_value ("");
+            sendCellEditCallback (row,
+                                  col,
+                                  old_data,
+                                  data.fast_elem_extract (row + col * data.rows ()),
+                                  edit_data,
+                                  error);
+            ok = true;
+          }
+      }
+    else
+      {
+        // Reset the QTableWidgetItem
+        updateData (row, col, octave_value (""), columnformat (col),
+                    columneditable (col));
+
+        octave_value error =
+          octave_value ("Table data is not editable at this location.");
+        sendCellEditCallback (row,
+                              col,
+                              octave_value (),
+                              octave_value (),
+                              edit_data,
+                              error);
+      }
+
+    if (! ok)
+      {
+        comboBox->setCurrentIndex (-1);
+        comboBox->setEditable (true);
+        comboBox->setEditText (comboBox->property ("original_value").toString ());
+        comboBox->lineEdit ()->setReadOnly (true);
+      }
+    m_blockUpdates = false;
+  }
+
+  void
+  Table::checkBoxClicked (int row, int col, QCheckBox *checkBox)
+  {
+    if (m_blockUpdates)
+      return;
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+
+    bool new_value = ! checkBox->isChecked ();
+
+    octave_value data = octave_value (m_curData);
+    if (data.islogical ())
+      {
+        // EASY WE JUST CONVERT
+        boolMatrix matrix = data.bool_matrix_value ();
+        if (row < matrix.rows () && col < matrix.columns ())
+          {
+            bool old_value = matrix(row, col);
+            matrix(row, col) = new_value;
+            checkBox->setChecked (new_value);
+            if (new_value != old_value)
+              {
+                m_curData = octave_value (matrix);
+                gh_manager::post_set (m_handle, "data",
+                                      octave_value (matrix), false);
+              }
+
+            sendCellEditCallback (row, col,
+                                  octave_value (old_value),
+                                  octave_value (new_value),
+                                  octave_value (new_value),
+                                  octave_value (""));
+
+          }
+        else
+          {
+            sendCellEditCallback (row,
+                                  col,
+                                  octave_value (),
+                                  octave_value (),
+                                  octave_value (new_value),
+                                  octave_value ("Table data is not editable at this location."));
+          }
+      }
+    else if (data.iscell ())
+      {
+        Cell cell = data.cell_value ();
+        if (row < cell.rows () && col < cell.columns ())
+          {
+            if (cell(row, col).islogical ())
+              {
+                bool old_value = cell(row, col).bool_value ();
+                cell(row, col) = octave_value (new_value);
+                checkBox->setChecked (new_value);
+                if (new_value != old_value)
+                  {
+                    m_curData = octave_value (cell);
+                    gh_manager::post_set (m_handle, "data", octave_value (cell), false);
+                  }
+
+                sendCellEditCallback (row,
+                                      col,
+                                      octave_value (old_value),
+                                      octave_value (new_value),
+                                      octave_value (new_value),
+                                      octave_value (""));
+              }
+            else
+              {
+                sendCellEditCallback (row,
+                                      col,
+                                      cell(row, col),
+                                      octave_value (),
+                                      octave_value (new_value),
+                                      octave_value ("Cannot convert logical edit to other type."));
+              }
+          }
+        else
+          {
+            sendCellEditCallback (row,
+                                  col,
+                                  cell(row, col),
+                                  octave_value (),
+                                  octave_value (new_value),
+                                  octave_value ("Table data is not editable at this location."));
+          }
+      }
+    else if (data.is_matrix_type ())
+      {
+        if (row < data.rows () && col < data.columns ())
+          {
+            sendCellEditCallback (row,
+                                  col,
+                                  data.fast_elem_extract (row + col * data.rows ()),
+                                  octave_value (),
+                                  octave_value (new_value),
+                                  octave_value ("Cannot convert logical edit to other type."));
+          }
+        else
+          {
+            sendCellEditCallback (row,
+                                  col,
+                                  data.fast_elem_extract (row + col * data.rows ()),
+                                  octave_value (),
+                                  octave_value (new_value),
+                                  octave_value ("Table data is not editable at this location."));
+          }
+      }
+    m_blockUpdates = false;
+  }
+
+
+  void
+  Table::itemChanged (QTableWidgetItem *item)
+  {
+    if (m_blockUpdates)
+      return;
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+    octave_value data = octave_value (m_curData);
+
+    int row = item->row ();
+    int col = item->column ();
+    octave_value edit_data = octave_value (Utils::toStdString (item->text ()));
+    octave_value new_value;
+    octave_value old_value;
+    octave_value new_data;
+
+    if (row < data.rows () && col < data.columns ())
+      {
+        if (data.iscell ())
+          {
+            old_value = data.cell_value () (row, col);
+          }
+        else if (data.is_matrix_type ())
+          {
+            old_value = data.fast_elem_extract (row + col * data.rows ());
+          }
+
+        // Now we need to coerce the new_value in to the type of the old_value
+        if (old_value.is_string ())
+          new_value = edit_data;
+        else
+          {
+            new_value = attempt_type_conversion (edit_data, old_value);
+            std::pair<Qt::AlignmentFlag, QString> flag_and_text =
+              qStringValueFor (new_value, columnformat (col));
+            item->setTextAlignment (flag_and_text.first);
+            item->setText (flag_and_text.second);
+          }
+
+        if (data.iscell ())
+          {
+            Cell cell = data.cell_value ();
+            cell(row, col) = new_value;
+            new_data = octave_value (cell);
+          }
+        else
+          {
+            data.fast_elem_insert (row + col * data.rows (), new_value);
+            new_data = data;
+          }
+        m_curData = octave_value (new_data);
+        gh_manager::post_set (m_handle, "data", new_data, false);
+
+        sendCellEditCallback (row,
+                              col,
+                              octave_value (old_value),
+                              octave_value (new_value),
+                              octave_value (new_value),
+                              octave_value (""));
+      }
+    else
+      {
+        item->setText ("");
+
+        octave_value error =
+          octave_value ("Table data is not editable at this location.");
+        sendCellEditCallback (row,
+                              col,
+                              octave_value (),
+                              octave_value (),
+                              edit_data,
+                              error);
+      }
+
+    m_blockUpdates = false;
+  }
+
+  void
+  Table::update (int pId)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    switch (pId)
+      {
+      case uitable::properties::ID_BACKGROUNDCOLOR:
+      case uitable::properties::ID_FOREGROUNDCOLOR:
+        updatePalette ();
+        break;
+
+      case uitable::properties::ID_COLUMNNAME:
+        updateColumnname ();
+        updateColumnwidth ();
+        break;
+
+      case uitable::properties::ID_COLUMNWIDTH:
+        updateColumnwidth ();
+        break;
+
+      case uitable::properties::ID_COLUMNEDITABLE:
+      case uitable::properties::ID_COLUMNFORMAT:
+      case uitable::properties::ID_DATA:
+        m_blockUpdates = true;
+        m_curData = octave_value (tp.get_data ());
+        updateData ();
+        updateRowname ();
+        updateColumnname ();
+        updateColumnwidth ();
+        updateEnable ();
+        m_blockUpdates = false;
+        break;
+
+      case uitable::properties::ID_ENABLE:
+        updateEnable ();
+        break;
+
+      case uitable::properties::ID_KEYPRESSFCN:
+        m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
+        break;
+
+      case uitable::properties::ID_KEYRELEASEFCN:
+        m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
+        break;
+
+      case uitable::properties::ID_FONTNAME:
+      case uitable::properties::ID_FONTSIZE:
+      case uitable::properties::ID_FONTWEIGHT:
+      case uitable::properties::ID_FONTANGLE:
+        if (m_tableWidget)
+          {
+            m_tableWidget->setFont (Utils::computeFont<uitable> (tp));
+            for (int row = 0; row < m_tableWidget->rowCount (); row++)
+              {
+                m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+              }
+          }
+        break;
+
+      case uitable::properties::ID_POSITION:
+        {
+          Matrix bb = tp.get_boundingbox (false);
+          m_tableWidget->setGeometry (octave::math::round (bb(0)),
+                                      octave::math::round (bb(1)),
+                                      octave::math::round (bb(2)),
+                                      octave::math::round (bb(3)));
+          updateExtent ();
+        }
+        break;
+
+      case uitable::properties::ID_REARRANGEABLECOLUMNS:
+        updateRearrangeableColumns ();
+        break;
+
+      case uitable::properties::ID_ROWNAME:
+        updateRowname ();
+        break;
+
+      case uitable::properties::ID_ROWSTRIPING:
+        updatePalette ();
+        break;
+
+      case uitable::properties::ID_TOOLTIPSTRING:
+        m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+        break;
+
+      case base_properties::ID_VISIBLE:
+        m_tableWidget->setVisible (tp.is_visible ());
+        break;
+
+      default:
+        break;
+
+      }
+  }
+
+  void
+  Table::updateColumnname (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    // Reset the Column Count
+    m_tableWidget->setColumnCount (tp.get_data ().columns ());
+
+    octave_value columnname = tp.get_columnname ();
+    QStringList l;
+    bool visible = true;
+
+    if (columnname.is_string () && columnname.string_value (false) == "numbered")
+      for (int i = 0; i < m_tableWidget->columnCount (); i++)
+        l << QString::number (i + 1);
+    else if (columnname.is_string ())
+      {
+        if (m_tableWidget->columnCount () > 0)
+          l << Utils::fromStdString (columnname.string_value ());
+        for (int i = 1; i < m_tableWidget->columnCount (); i++)
+          l << "";
+      }
+    else if (columnname.isempty ())
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+
+        visible = false;
+      }
+    else if (columnname.iscell ())
+      {
+        octave_idx_type n = columnname.numel ();
+        Cell cell_value = columnname.cell_value ();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ())
+              l << Utils::fromStdString (v.string_value (true));
+            else if (v.is_matrix_type ())
+              {
+                Matrix data = v.matrix_value ();
+
+                /* Now Matlab does something very strange here:
+                 * If data is a row or column matrix,
+                 * then each datapoint is added.
+                 * Otherwise, nothing is set.
+                 */
+                if (data.rows () > 1 && data.cols () > 1)
+                  l << "";
+                else
+                  for (octave_idx_type j = 0; j < data.numel (); j++)
+                    l << QString::number (data(j));
+              }
+            else if (v.isnumeric ())
+              l << QString::number (v.double_value ());
+            else
+              l << QString::number (v.double_value ());
+          }
+      }
+    else if (columnname.is_matrix_type ())
+      {
+        octave_idx_type n = columnname.numel ();
+        Matrix matrix_value = columnname.matrix_value ();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          l << QString::number (matrix_value(i));
+      }
+    else
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+        visible = false;
+      }
+
+    l.replaceInStrings ("|", "\n");
+
+    // Now add the columns as required
+    if (m_tableWidget->columnCount () < l.length ())
+      {
+        int oldColumnCount = m_tableWidget->columnCount ();
+        m_tableWidget->setColumnCount (l.length ());
+        for (int col = oldColumnCount; col < l.length (); col++)
+          {
+            std::string format = columnformat (col);
+            bool enabled = columneditable (col);
+
+            for (int row = 0; row < m_tableWidget->rowCount (); row++)
+              updateData (row, col, octave_value (""), format, enabled);
+          }
+      }
+
+    m_tableWidget->setHorizontalHeaderLabels (l);
+    m_tableWidget->horizontalHeader ()->setVisible (visible);
+  }
+
+  void
+  Table::updateColumnwidth (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    octave_value columnwidth = tp.get_columnwidth ();
+    if (columnwidth.isempty () ||
+        (columnwidth.is_string () && columnwidth.string_value (false) == "auto"))
+      for (int i = 0; i < m_tableWidget->columnCount (); i++)
+        m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+    else if (columnwidth.is_string ()
+             && columnwidth.string_value (false) == "preferred")
+      for (int i = 0; i < m_tableWidget->columnCount (); i++)
+        {
+          int column_size =
+            (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
+          int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+          if (column_size > header_size)
+            header_size = column_size;
+          m_tableWidget->setColumnWidth (i, header_size);
+        }
+    else if (columnwidth.iscell ())
+      {
+        Cell cell_value = columnwidth.cell_value ();
+        int i = 0;
+        for (; i < m_tableWidget->columnCount () && i < cell_value.numel (); i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ()  && v.string_value (false) == "auto")
+              m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+            else if (v.is_string () && v.string_value (false) == "preferred")
+              {
+                int column_size =
+                  (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
+                int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+                if (column_size > header_size)
+                  header_size = column_size;
+                m_tableWidget->setColumnWidth (i, header_size);
+              }
+            else
+              {
+                int w = int (v.double_value ());
+                m_tableWidget->setColumnWidth (i, w);
+              }
+          }
+        for (; i < m_tableWidget->columnCount (); i++)
+          {
+            int column_size =
+              (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
+            int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+            if (column_size > header_size)
+              header_size = column_size;
+            m_tableWidget->setColumnWidth (i, header_size);
+          }
+      }
+    else if (columnwidth.is_matrix_type ())
+      {
+        Matrix matrix_value = columnwidth.matrix_value ();
+        int i = 0;
+        for (; i < m_tableWidget->columnCount () && i < matrix_value.numel (); i++)
+          {
+            octave_value v = matrix_value(i);
+            int w = int (v.double_value ());
+            m_tableWidget->setColumnWidth (i, w);
+          }
+        for (; i < m_tableWidget->columnCount (); i++)
+          m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+      }
+  }
+
+  bool inline
+  Table::columneditable (int col)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    boolNDArray columneditable = tp.get_columneditable ().bool_array_value ();
+    bool editable = false;
+
+    if (! columneditable.isempty () && col < columneditable.numel ())
+      editable = columneditable.xelem (col);
+    else if (! columneditable.isempty () && columneditable.numel () == 1)
+      editable = columneditable.xelem (0);
+
+    return editable;
+  }
+
+  std::string inline
+  Table::columnformat (int col)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    std::string format = "";
+    octave_value ov_columnformat = tp.get_columnformat ();
+
+    if (ov_columnformat.iscell ())
+      {
+        Cell columnformat = ov_columnformat.cell_value ();
+        if (! columnformat.isempty () && col < columnformat.numel ())
+          {
+            octave_value format_value = columnformat.xelem (col);
+
+            if (! format_value.isempty () && format_value.is_string ())
+              format = format_value.string_value ();
+            else if (! format_value.isempty () && format_value.iscell ())
+              format = "popup";
+          }
+      }
+    else if (ov_columnformat.is_string ())
+      {
+        format = ov_columnformat.string_value ();
+      }
+    return format;
+  }
+
+  void inline
+  Table::updateDataColumn (int col)
+  {
+    octave_value data = properties<uitable> ().get_data ();
+
+    std::string format = columnformat (col);
+    bool is_editable = columneditable (col);
+
+    for (octave_idx_type row = 0; row < data.rows (); row++)
+      updateData (row,
+                  col,
+                  data.iscell ()
+                  ? data.cell_value () (row, col)
+                  : data.fast_elem_extract (row + col * data.rows ()),
+                  format,
+                  is_editable);
+  }
+
+  void inline
+  Table::updateData (int row, int col)
+  {
+    octave_value data = properties<uitable> ().get_data ();
+    updateData (row,
+                col,
+                data.iscell ()
+                ? data.cell_value () (row, col)
+                : data.fast_elem_extract (row + col * data.rows ()),
+                columnformat (col),
+                columneditable (col));
+  }
+
+  void inline
+  Table::updateData (int row, int col, octave_value value,
+                     std::string format = "", bool enabled = false)
+  {
+    if (format == "logical" || (format == "" && value.islogical ()))
+      {
+        if (m_tableWidget->item (row, col))
+          delete m_tableWidget->item (row, col);
+
+        m_tableWidget->setCellWidget (row, col, checkBoxForLogical (value, enabled));
+        m_tableWidget->cellWidget (row, col)->setProperty ("row", QVariant (row));
+        m_tableWidget->cellWidget (row, col)->setProperty ("col", QVariant (col));
+      }
+    else if (format == "popup" && enabled)
+      {
+        if (m_tableWidget->item (row, col))
+          delete m_tableWidget->item (row, col);
+
+        QString string_value = qStringValueFor (value, format).second;
+        uitable::properties& tp = properties<uitable> ();
+        octave_value format_value = tp.get_columnformat ().cell_value ().xelem (col);
+
+        QComboBox *comboBox = new QComboBox ();
+        comboBox->setProperty ("row", QVariant (row));
+        comboBox->setProperty ("col", QVariant (col));
+
+        int index = -1;
+        for (int k = 0; k < format_value.numel (); k++)
+          {
+            QString popup_item = Utils::fromStdString (
+                                   format_value.fast_elem_extract (k).string_value ());
+
+            comboBox->addItem (popup_item);
+
+            if (popup_item == string_value)
+              index = k;
+          }
+        comboBox->setCurrentIndex (index);
+
+        if (index < 0)
+          {
+            comboBox->setEditable (true);
+            comboBox->setEditText (string_value);
+            comboBox->lineEdit ()->setReadOnly (true);
+          }
+
+        comboBox->setProperty ("original_value", QVariant (string_value));
+
+        comboBox->installEventFilter (this);
+        m_tableWidget->setCellWidget (row, col, comboBox);
+        connect (comboBox, SIGNAL(currentIndexChanged (const QString&)),
+                 this, SLOT(comboBoxCurrentIndexChanged (const QString&)));
+      }
+    else
+      {
+        if (m_tableWidget->cellWidget (row, col))
+          delete m_tableWidget->cellWidget (row, col);
+        m_tableWidget->setItem (row, col, itemFor (value, format, enabled));
+      }
+  }
+
+  void
+  Table::updateData ()
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    octave_value data = tp.get_data ();
+
+    if (data.iscell () || data.is_matrix_type ())
+      {
+        m_tableWidget->setRowCount (data.rows ());
+        m_tableWidget->setColumnCount (data.columns ());
+
+        for (octave_idx_type col = 0; col < data.columns (); col++)
+          updateDataColumn (col);
+      }
+
+    for (octave_idx_type row = 0; row < m_tableWidget->rowCount (); row++)
+      m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+  }
+
+  void
+  Table::updateEnable (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    bool enabled = tp.is_enable ();
+    m_tableWidget->setEnabled (! enabled);
+
+    bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
+
+    // Set selection mode
+    m_tableWidget->setSelectionMode (enabled
+                                     ? QAbstractItemView::ExtendedSelection
+                                     : 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 ()->setDragEnabled (enabled && rearrangeableColumns);
+    m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
+
+    // Turn off column editable
+    for (int col = 0; col < m_tableWidget->columnCount (); col++)
+      {
+        bool editable = columneditable (col);
+
+        for (int row = 0; row < m_tableWidget->rowCount (); row++)
+          if (QTableWidgetItem *item = m_tableWidget->item (row, col))
+            {
+              Qt::ItemFlags flags = item->flags ();
+              if (enabled && editable)
+                item->setFlags (flags | Qt::ItemIsEditable);
+              else
+                item->setFlags (flags & ~Qt::ItemIsEditable);
+            }
+          else if (QWidget *widget = m_tableWidget->cellWidget (row, col))
+            {
+              QCheckBox *checkBox = nullptr;
+              if (widget && ! widget->children ().isEmpty ())
+                {
+                  QHBoxLayout *layout = qobject_cast<QHBoxLayout *> (
+                                          widget->children ().first ());
+                  if (layout && layout->count () > 0)
+                    {
+                      checkBox = qobject_cast<QCheckBox *> (
+                                   layout->itemAt (0)-> widget ());
+                    }
+                }
+              if (checkBox)
+                {
+                  widget->setProperty ("Enabled", QVariant (enabled & editable));
+                }
+              else
+                {
+                  widget->setAttribute (Qt::WA_TransparentForMouseEvents, !(editable & enabled));
+                  widget->setFocusPolicy (Qt::NoFocus);
+                }
+            }
+      }
+  }
+
+  void
+  Table::updateExtent (void)
+  {
+    QSize s = realQSizeForTable (m_tableWidget);
+    Matrix extent = Matrix (1, 4);
+    extent(0, 0) = 0;
+    extent(0, 1) = 0;
+    extent(0, 2) = s.width ();
+    extent(0, 3) = s.height () ;
+    graphics_object go = object ();
+    gh_manager::post_set (go.get_handle (), "extent", extent, false);
+  }
+
+  void
+  Table::updatePalette (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    QPalette p = m_tableWidget->palette ();
+    p.setColor (QPalette::Text,
+                Utils::fromRgb (tp.get_foregroundcolor_rgb ()));
+    p.setColor (QPalette::Base,
+                Utils::fromRgb (tp.get_backgroundcolor_rgb ()));
+    p.setColor (QPalette::AlternateBase,
+                Utils::fromRgb (tp.get_alternatebackgroundcolor_rgb ()));
+    m_tableWidget->setPalette (p);
+    m_tableWidget->setAlternatingRowColors (tp.is_rowstriping ());
+    // FIXME: Handle multiple alternating background colors
+  }
+
+  void
+  Table::updateRowname (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    // Reset the row count
+    m_tableWidget->setRowCount (tp.get_data ().rows ());
+
+    octave_value rowname = tp.get_rowname ();
+    QStringList l;
+    bool visible = true;
+
+    if (rowname.is_string () && rowname.string_value (false) == "numbered")
+      for (int i = 0; i < m_tableWidget->rowCount (); i++)
+        l << QString::number (i + 1);
+    else if (rowname.is_string ())
+      {
+        if (m_tableWidget->rowCount () > 0)
+          l << Utils::fromStdString (rowname.string_value ());
+        for (int i = 1; i < m_tableWidget->rowCount (); i++)
+          l << "";
+      }
+    else if (rowname.isempty ())
+      {
+        for (int i = 0; i < m_tableWidget->rowCount (); i++)
+          l << "";
+        visible = false;
+      }
+    else if (rowname.iscell ())
+      {
+        octave_idx_type n = rowname.numel ();
+        Cell cell_value = rowname.cell_value ();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ())
+              l << Utils::fromStdString (v.string_value (true));
+            else if (v.is_matrix_type ())
+              {
+                Matrix data = v.matrix_value ();
+
+                /* Now Matlab does something very strange here:
+                 * If data is a row or column matrix,
+                 * then each datapoint is added.
+                 * Otherwise, nothing is set.
+                 */
+                if (data.rows () > 1 && data.cols () > 1)
+                  l << "";
+                else
+                  for (octave_idx_type j = 0; j < data.numel (); j++)
+                    l << QString::number (data(j));
+              }
+            else if (v.isnumeric ())
+              l << QString::number (v.double_value (true));
+            else
+              l << QString::number (v.double_value (true));
+          }
+      }
+    else if (rowname.is_matrix_type ())
+      {
+        octave_idx_type n = rowname.numel ();
+        Matrix matrix_value = rowname.matrix_value ();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          l << QString::number (matrix_value(i));
+      }
+    else
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+        visible = false;
+      }
+
+    // Add dummy rows as required
+    if (m_tableWidget->rowCount () < l.length ())
+      {
+        int oldRowCount = m_tableWidget->rowCount ();
+        m_tableWidget->setRowCount (l.length ());
+
+        for (int col = 0; col < m_tableWidget->columnCount (); col++)
+          {
+            std::string format = columnformat (col);
+            bool enabled = columneditable (col);
+
+            for (int row = oldRowCount; row < l.length (); row++)
+              {
+                m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+
+                updateData (row, col, octave_value (""), format, enabled);
+              }
+          }
+      }
+
+    m_tableWidget->setVerticalHeaderLabels (l);
+    m_tableWidget->verticalHeader ()->setVisible (visible);
+  }
+
+  void
+  Table::updateRearrangeableColumns (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    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);
+  }
+
+  bool
+  Table::eventFilter (QObject *watched, QEvent *xevent)
+  {
+    //uitable::properties& tp = properties<uitable> ();
+    if (qobject_cast<QTableWidget *> (watched))
+      {
+        switch (xevent->type ())
+          {
+          case QEvent::Resize:
+            {
+              gh_manager::auto_lock lock;
+              graphics_object go = object ();
+              if (go.valid_object ())
+                {
+                  const uitable::properties& tp =
+                    Utils::properties<uitable> (go);
+                  if (tp.fontunits_is ("normalized"))
+                    m_tableWidget->setFont (Utils::computeFont<uitable> (tp));
+                }
+            }
+            break;
+
+          case QEvent::MouseButtonPress:
+            {
+              gh_manager::auto_lock lock;
+              QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
+              graphics_object go = object ();
+              const uitable::properties& tp =
+                Utils::properties<uitable> (go);
+              graphics_object fig = go.get_ancestor ("figure");
+
+              if (m->button () != Qt::LeftButton || ! tp.is_enable ())
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+                  gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                        Utils::figureCurrentPoint (fig, m),
+                                        false);
+                  gh_manager::post_callback (fig.get_handle (),
+                                             "windowbuttondownfcn");
+                  gh_manager::post_callback (m_handle, "buttondownfcn");
+
+                  if (m->button () == Qt::RightButton)
+                    ContextMenu::executeAt (properties (), m->globalPos ());
+                }
+              else
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        octave_value ("normal"), false);
+                }
+            }
+            break;
+
+          case QEvent::KeyPress:
+            {
+              QKeyEvent *k = dynamic_cast<QKeyEvent *> (xevent);
+              if (m_keyPressHandlerDefined)
+                {
+                  gh_manager::auto_lock lock;
+
+                  octave_scalar_map keyData = Utils::makeKeyEventStruct (k);
+                  graphics_object fig = object ().get_ancestor ("figure");
+
+                  gh_manager::post_set (fig.get_handle (), "currentcharacter",
+                                        keyData.getfield ("Character"), false);
+                  gh_manager::post_callback (m_handle, "keypressfcn", keyData);
+                }
+              int row = m_tableWidget->currentRow ();
+              int col = m_tableWidget->currentColumn ();
+              switch (k->key ())
+                {
+                case Qt::Key_Space:
+                  {
+                    QCheckBox *checkBox = nullptr;
+                    QWidget *widget = qobject_cast<QWidget *> (
+                                        m_tableWidget->cellWidget (row, col));
+                    if (widget && ! widget->children ().isEmpty ())
+                      {
+                        QHBoxLayout *layout = qobject_cast<QHBoxLayout *> (
+                                                widget->children ().first ());
+                        if (layout && layout->count () > 0)
+                          {
+                            checkBox = qobject_cast<QCheckBox *> (
+                                         layout->itemAt (0)-> widget ());
+                          }
+                      }
+                    if (checkBox && checkBox->property ("Enabled").toBool ())
+                      checkBoxClicked (row, col, checkBox);
+
+                    QComboBox *comboBox = qobject_cast<QComboBox *> (
+                                            m_tableWidget->cellWidget (row,
+                                                                       col));
+                    if (comboBox)
+                      comboBox->showPopup ();
+                  }
+                  break;
+
+                case Qt::Key_Return:
+                case Qt::Key_Enter:
+                  {
+                    if (k->modifiers () == Qt::NoModifier)
+                      {
+                        if (row + 1 < m_tableWidget->rowCount ())
+                          m_tableWidget->setCurrentCell (row + 1, col);
+                        else
+                          {
+                            if (col + 1 < m_tableWidget->columnCount ())
+                              m_tableWidget->setCurrentCell (0, col + 1);
+                            else
+                              m_tableWidget->setCurrentCell (0, 0);
+                          }
+                      }
+                    else if (k->modifiers () == Qt::ShiftModifier)
+                      {
+                        if (row - 1 >= 0)
+                          m_tableWidget->setCurrentCell (row - 1, col);
+                        else
+                          {
+                            if (col - 1 >= 0)
+                              m_tableWidget->setCurrentCell
+                              (m_tableWidget->rowCount () - 1,
+                               col - 1);
+                            else
+                              m_tableWidget->setCurrentCell
+                              (m_tableWidget->rowCount () - 1,
+                               m_tableWidget->columnCount () - 1);
+                          }
+                      }
+                  }
+                  break;
+
+                default:
+                  break;
+                }
+            }
+            break;
+
+          case QEvent::KeyRelease:
+            {
+              if (m_keyReleaseHandlerDefined)
+                {
+                  gh_manager::auto_lock lock;
+                  QKeyEvent *k = dynamic_cast<QKeyEvent *> (xevent);
+
+                  octave_scalar_map keyData = Utils::makeKeyEventStruct (k);
+                  graphics_object fig = object ().get_ancestor ("figure");
+
+                  gh_manager::post_set (fig.get_handle (), "currentcharacter",
+                                        keyData.getfield ("Character"), false);
+                  gh_manager::post_callback (m_handle, "keyreleasefcn",
+                                             keyData);
+                }
+            }
+            break;
+
+          default:
+            break;
+          }
+      }
+    else if (qobject_cast<QComboBox *> (watched))
+      {
+        switch (xevent->type ())
+          {
+          case QEvent::MouseButtonPress:
+            {
+              gh_manager::auto_lock lock;
+              QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
+              graphics_object go = object ();
+              const uitable::properties& tp = Utils::properties<uitable> (go);
+              graphics_object fig = go.get_ancestor ("figure");
+
+              if (m->button () != Qt::LeftButton || ! tp.is_enable ())
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+                  gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                        Utils::figureCurrentPoint (fig, m),
+                                        false);
+                  gh_manager::post_callback (fig.get_handle (),
+                                             "windowbuttondownfcn");
+                  gh_manager::post_callback (m_handle, "buttondownfcn");
+
+                  if (m->button () == Qt::RightButton)
+                    ContextMenu::executeAt (tp, m->globalPos ());
+                }
+              else
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+
+                  QComboBox *comboBox_0 = qobject_cast<QComboBox *> (watched);
+                  for (int row = 0; row < m_tableWidget->rowCount (); row++)
+                    {
+                      for (int col = 0; col < m_tableWidget->columnCount (); col++)
+                        {
+                          QComboBox *comboBox_1 = qobject_cast<QComboBox *> (
+                                                    m_tableWidget->cellWidget (row, col));
+                          if (comboBox_0 == comboBox_1)
+                            m_tableWidget->setCurrentCell (row, col);
+                        }
+                    }
+                }
+            }
+            break;
+
+          default:
+            break;
+          }
+      }
+    return false;
+  }
+
+#undef AUTO_HEIGHT
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Table.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,93 @@
+/*
+
+Copyright (C) 2016 Andrew Thornton
+
+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_Table_h)
+#define octave_Table_h 1
+
+#include "Object.h"
+
+class QCheckBox;
+class QTableWidget;
+class QTableWidgetItem;
+
+namespace QtHandles
+{
+
+  class Container;
+
+  class Table : public Object
+  {
+    Q_OBJECT
+
+  public:
+    Table (const graphics_object& go, QTableWidget* tableWidget);
+    ~Table (void);
+
+    Container* innerContainer (void) { return m_container; }
+
+    bool eventFilter (QObject* watched, QEvent* event);
+
+    static Table* create (const graphics_object& go);
+
+  protected:
+    void update (int pId);
+    //void redraw (void);
+    void updateColumnname (void);
+    void updateColumnwidth (void);
+    void updateData (void);
+    void updateEnable (void);
+    void updateExtent (void);
+    void updatePalette (void);
+    void updateRearrangeableColumns (void);
+    void updateRowname (void);
+
+  private slots:
+    void itemChanged (QTableWidgetItem* item);
+    void comboBoxCurrentIndexChanged (const QString& value);
+    void cellClicked (int row, int col);
+    void itemSelectionChanged (void);
+
+  private:
+    Container* m_container;
+    QTableWidget* m_tableWidget;
+    octave_value m_curData;
+    bool m_blockUpdates;
+    bool m_keyPressHandlerDefined;
+    bool m_keyReleaseHandlerDefined;
+    QWidget * checkBoxForLogical(octave_value cal, bool enabled);
+    void updateData (int row, int col, octave_value value, std::string format,
+                     bool enabled);
+    void updateData (int row, int col);
+    void updateDataColumn (int col);
+    std::string columnformat (int column);
+    bool columneditable (int column);
+    void sendCellEditCallback (int row, int col, octave_value old_value,
+                               octave_value new_value, octave_value edit_data, octave_value error);
+    void checkBoxClicked (int row, int col, QCheckBox* checkBox);
+
+
+
+  };
+
+}
+
+#endif
--- a/libgui/graphics/ToggleButtonControl.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/ToggleButtonControl.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -51,7 +51,7 @@
   }
 
   ToggleButtonControl::ToggleButtonControl (const graphics_object& go,
-      QPushButton *btn)
+                                            QPushButton *btn)
     : ButtonControl (go, btn)
   {
     Object *parent = Object::parentObject (go);
@@ -59,11 +59,41 @@
     if (btnGroup)
       btnGroup->addButton (btn);
 
+    uicontrol::properties& up = properties<uicontrol> ();
+
     btn->setCheckable (true);
     btn->setAutoFillBackground (true);
+    octave_value cdat = up.get_cdata ();
+    QImage img = Utils::makeImageFromCData (cdat,
+                                            cdat.rows (), cdat.columns ());
+    btn->setIcon (QIcon (QPixmap::fromImage (img)));
   }
 
   ToggleButtonControl::~ToggleButtonControl (void)
   { }
 
+  void
+  ToggleButtonControl::update (int pId)
+  {
+    uicontrol::properties& up = properties<uicontrol> ();
+    QPushButton *btn = qWidget<QPushButton> ();
+
+    switch (pId)
+      {
+      case uicontrol::properties::ID_CDATA:
+        {
+          octave_value cdat = up.get_cdata ();
+          QImage img = Utils::makeImageFromCData (cdat,
+                                                  cdat.rows (),
+                                                  cdat.columns ());
+          btn->setIcon (QIcon (QPixmap::fromImage (img)));
+        }
+        break;
+
+      default:
+        ButtonControl::update (pId);
+        break;
+      }
+  }
+
 };
--- a/libgui/graphics/ToggleButtonControl.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/ToggleButtonControl.h	Thu Dec 20 17:18:56 2018 -0500
@@ -37,6 +37,9 @@
     ~ToggleButtonControl (void);
 
     static ToggleButtonControl * create (const graphics_object& go);
+
+  protected:
+    void update (int pId);
   };
 
 }
--- a/libgui/graphics/__init_qt__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/__init_qt__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,7 +31,7 @@
 #include <QPalette>
 #include <QRegExp>
 
-#include "defun.h"
+#include "defun-dld.h"
 #include "graphics.h"
 #include "gtk-manager.h"
 #include "interpreter.h"
@@ -41,6 +41,8 @@
 #include "QtHandlesUtils.h"
 #include "__init_qt__.h"
 
+// PKG_ADD: if (__have_feature__ ("QT") && __have_feature__ ("OPENGL") && have_window_system () && __octave_link_enabled__ ()) register_graphics_toolkit ("qt"); endif
+
 namespace QtHandles
 {
 
@@ -95,14 +97,14 @@
   }
 }
 
-DEFMETHOD (__init_qt__, interp, , , "")
+DEFMETHOD_DLD (__init_qt__, interp, , , "")
 {
   QtHandles::__init__ (interp);
 
   return octave_value ();
 }
 
-DEFUN (__shutdown_qt__, , , "")
+DEFUN_DLD (__shutdown_qt__, , , "")
 {
   QtHandles::__shutdown__ ();
 
@@ -164,7 +166,7 @@
   return d;
 }
 
-DEFUN (__uigetfile_qt__, args, , "")
+DEFUN_DLD (__uigetfile_qt__, args, , "")
 {
   using namespace QtHandles::Utils;
 
@@ -246,7 +248,7 @@
   return retval;
 }
 
-DEFUN (__uiputfile_qt__, args, , "")
+DEFUN_DLD (__uiputfile_qt__, args, , "")
 {
   using namespace QtHandles::Utils;
 
@@ -296,7 +298,7 @@
   return retval;
 }
 
-DEFUN (__uigetdir_qt__, args, , "")
+DEFUN_DLD (__uigetdir_qt__, args, , "")
 {
   using namespace QtHandles::Utils;
 
--- a/libgui/graphics/annotation-dialog.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/annotation-dialog.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,7 +50,7 @@
 {
   ui->setupUi (this);
 
-  QSettings *settings = resource_manager::get_settings ();
+  QSettings *settings = octave::resource_manager::get_settings ();
 
   // restore last geometry
   if (settings)
@@ -94,7 +94,7 @@
   QDialogButtonBox::ButtonRole button_role
     = ui->button_box->buttonRole (button);
 
-  QSettings *settings = resource_manager::get_settings ();
+  QSettings *settings = octave::resource_manager::get_settings ();
 
   // save position
   if (settings)
--- a/libgui/graphics/gl-select.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/gl-select.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-
 #include "gl-select.h"
 
 namespace octave
@@ -35,15 +33,28 @@
   opengl_selector::apply_pick_matrix (void)
   {
     GLdouble p_matrix[16];
-    GLint viewport[4];
+
+    m_glfcns.glGetDoublev (GL_PROJECTION_MATRIX, p_matrix);
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glLoadIdentity ();
+
+    // The following block is equivalent to gluPickMatrix, but we avoid
+    // using glu functions so that we can call OpenGL functions through
+    // the QOpenGLFunctions class so that the OpenGL implementation may
+    // be selected dynamically.
 
-    glGetDoublev (GL_PROJECTION_MATRIX, p_matrix);
-    glGetIntegerv (GL_VIEWPORT, viewport);
-    glMatrixMode (GL_PROJECTION);
-    glLoadIdentity ();
-    gluPickMatrix (xp, yp, size, size, viewport);
-    glMultMatrixd (p_matrix);
-    glMatrixMode (GL_MODELVIEW);
+    Matrix viewport = get_viewport_scaled ();
+
+    if (size > 0)
+      {
+        m_glfcns.glTranslatef ((viewport(2) - 2 * (xp - viewport(0))) / size,
+                               (viewport(3) - 2 * (yp - viewport(1))) / size, 0);
+
+        m_glfcns.glScalef (viewport(2) / size, viewport(3) / size, 1.0);
+      }
+
+    m_glfcns.glMultMatrixd (p_matrix);
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
   }
 
   void
@@ -65,23 +76,23 @@
   graphics_object
   opengl_selector::select (const graphics_object& ax, int x, int y, int flags)
   {
-    glEnable (GL_DEPTH_TEST);
-    glDepthFunc (GL_LEQUAL);
+    m_glfcns.glEnable (GL_DEPTH_TEST);
+    m_glfcns.glDepthFunc (GL_LEQUAL);
 
     xp = x;
     yp = y;
 
     GLuint select_buffer[BUFFER_SIZE];
 
-    glSelectBuffer (BUFFER_SIZE, select_buffer);
-    glRenderMode (GL_SELECT);
-    glInitNames ();
+    m_glfcns.glSelectBuffer (BUFFER_SIZE, select_buffer);
+    m_glfcns.glRenderMode (GL_SELECT);
+    m_glfcns.glInitNames ();
 
     object_map.clear ();
 
     draw (ax);
 
-    int hits = glRenderMode (GL_RENDER);
+    int hits = m_glfcns.glRenderMode (GL_RENDER);
     graphics_object obj;
 
     if (hits > 0)
@@ -139,11 +150,11 @@
     GLuint name = object_map.size ();
 
     object_map[name] = go;
-    glPushName (name);
+    m_glfcns.glPushName (name);
     set_selecting (true);
     opengl_renderer::draw (go, toplevel);
     set_selecting (false);
-    glPopName ();
+    m_glfcns.glPopName ();
   }
 
   void
@@ -167,12 +178,12 @@
     p3 = get_transform ().untransform (xp2(0), xp2(1), xp1(2), false);
     p4 = get_transform ().untransform (xp1(0), xp2(1), xp1(2), false);
 
-    glBegin (GL_QUADS);
-    glVertex3dv (p1.data ());
-    glVertex3dv (p2.data ());
-    glVertex3dv (p3.data ());
-    glVertex3dv (p4.data ());
-    glEnd ();
+    m_glfcns.glBegin (GL_QUADS);
+    m_glfcns.glVertex3dv (p1.data ());
+    m_glfcns.glVertex3dv (p2.data ());
+    m_glfcns.glVertex3dv (p3.data ());
+    m_glfcns.glVertex3dv (p4.data ());
+    m_glfcns.glEnd ();
   }
 
   void
@@ -227,12 +238,12 @@
     p4(0) = xd(0) - x_pix_size/2;
     p4(1) = yd(1) + y_pix_size/2;
 
-    glBegin (GL_QUADS);
-    glVertex3dv (p1.data ());
-    glVertex3dv (p2.data ());
-    glVertex3dv (p3.data ());
-    glVertex3dv (p4.data ());
-    glEnd ();
+    m_glfcns.glBegin (GL_QUADS);
+    m_glfcns.glVertex3dv (p1.data ());
+    m_glfcns.glVertex3dv (p2.data ());
+    m_glfcns.glVertex3dv (p3.data ());
+    m_glfcns.glVertex3dv (p4.data ());
+    m_glfcns.glEnd ();
   }
 
 }
--- a/libgui/graphics/gl-select.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/gl-select.h	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,7 @@
 #define octave_gl_select_h 1
 
 #include <map>
+#include <string>
 
 #include "gl-render.h"
 #include "oct-opengl.h"
@@ -40,7 +41,9 @@
   class opengl_selector : public opengl_renderer
   {
   public:
-    opengl_selector (void) : size (5) { }
+    opengl_selector (opengl_functions& glfcns)
+      : opengl_renderer (glfcns), size (5)
+    { }
 
     virtual ~opengl_selector (void) = default;
 
--- a/libgui/graphics/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/graphics/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -1,5 +1,7 @@
 if AMCOND_BUILD_QT_GRAPHICS
 
+LIBOCTGUI_GRAPHICS_LIB = %reldir%/__init_qt__.la
+
 OCTAVE_GUI_GRAPHICS_MOC = \
   %reldir%/moc-annotation-dialog.cc \
   %reldir%/moc-Backend.cc \
@@ -19,6 +21,7 @@
   %reldir%/moc-PushTool.cc \
   %reldir%/moc-SliderControl.cc \
   %reldir%/moc-TextEdit.cc \
+  %reldir%/moc-Table.cc \
   %reldir%/moc-ToggleTool.cc \
   %reldir%/moc-ToolBar.cc
 
@@ -27,21 +30,21 @@
 DIRSTAMP_FILES += \
   %reldir%/$(octave_dirstamp)
 
-octave_gui_MOC += \
+__init_qt___MOC = \
   $(OCTAVE_GUI_GRAPHICS_MOC)
 
-octave_gui_graphics_UI = \
+__init_qt___UI = \
   %reldir%/annotation-dialog.ui
 
-octave_gui_graphics_UI_H = $(patsubst %reldir%/%.ui, %reldir%/ui-%.h, $(octave_gui_graphics_UI))
+__init_qt___UI_H = $(patsubst %reldir%/%.ui, %reldir%/ui-%.h, $(__init_qt___UI))
 
-$(octave_gui_graphics_UI_H): | %reldir%/$(octave_dirstamp)
+$(__init_qt___UI_H): | %reldir%/$(octave_dirstamp)
 
-BUILT_SOURCES += $(octave_gui_graphics_UI_H)
+BUILT_SOURCES += $(__init_qt___UI_H)
 
-octave_gui_graphics_RC = %reldir%/qrc-qthandles.cc
+__init_qt___RC = %reldir%/qrc-qthandles.cc
 
-$(octave_gui_graphics_RC): | %reldir%/$(octave_dirstamp)
+$(__init_qt___RC): | %reldir%/$(octave_dirstamp)
 
 noinst_HEADERS += \
   %reldir%/__init_qt__.h \
@@ -75,6 +78,7 @@
   %reldir%/QtHandlesUtils.h \
   %reldir%/RadioButtonControl.h \
   %reldir%/SliderControl.h \
+  %reldir%/Table.h \
   %reldir%/TextControl.h \
   %reldir%/TextEdit.h \
   %reldir%/ToggleButtonControl.h \
@@ -82,9 +86,10 @@
   %reldir%/ToolBar.h \
   %reldir%/ToolBarButton.h \
   %reldir%/gl-select.h \
+  %reldir%/qopengl-functions.h \
   $(TEMPLATE_SRC)
 
-%canon_reldir%_%canon_reldir%_la_SOURCES = \
+%canon_reldir%___init_qt___la_SOURCES = \
   %reldir%/__init_qt__.cc \
   %reldir%/annotation-dialog.cc \
   %reldir%/Backend.cc \
@@ -114,6 +119,7 @@
   %reldir%/QtHandlesUtils.cc \
   %reldir%/RadioButtonControl.cc \
   %reldir%/SliderControl.cc \
+  %reldir%/Table.cc \
   %reldir%/TextControl.cc \
   %reldir%/TextEdit.cc \
   %reldir%/ToggleButtonControl.cc \
@@ -124,9 +130,9 @@
 TEMPLATE_SRC = \
   %reldir%/ToolBarButton.cc
 
-nodist_%canon_reldir%_%canon_reldir%_la_SOURCES = $(octave_gui_graphics_MOC) $(octave_gui_graphics_RC)
+nodist_%canon_reldir%___init_qt___la_SOURCES = $(__init_qt___MOC) $(__init_qt___RC)
 
-%canon_reldir%_%canon_reldir%_la_CPPFLAGS = \
+%canon_reldir%___init_qt___la_CPPFLAGS = \
   $(AM_CPPFLAGS) \
   $(FT2_CPPFLAGS) \
   $(FONTCONFIG_CPPFLAGS) \
@@ -135,6 +141,7 @@
   @QT_CPPFLAGS@ \
   -Ilibgui/graphics -I$(srcdir)/libgui/graphics \
   -Isrc -I$(srcdir)/libgui/src \
+  -Iliboctave \
   -I$(srcdir)/liboctave/array \
   -Iliboctave/numeric -I$(srcdir)/liboctave/numeric \
   -Iliboctave/operators -I$(srcdir)/liboctave/operators \
@@ -145,11 +152,43 @@
   -Ilibinterp/corefcn -I$(srcdir)/libinterp/corefcn \
   -I$(srcdir)/libinterp/octave-value
 
-%canon_reldir%_%canon_reldir%_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
+%canon_reldir%___init_qt___la_LDFLAGS = \
+  -avoid-version -module $(NO_UNDEFINED_LDFLAG) $(WARN_LDFLAGS)
+
+DLD_LIBOCTGUI_LIBADD = $(OCT_GUI_LINK_DEPS)
+
+%canon_reldir%___init_qt___la_LIBADD = \
+  $(DLD_LIBOCTGUI_LIBADD) \
+  $(QT_OPENGL_LIBS) \
+  $(OPENGL_LIBS)
+
+%canon_reldir%___init_qt___la_DEPENDENCIES = $(OCT_GUI_LINK_DEPS)
+
+octlib_LTLIBRARIES += $(LIBOCTGUI_GRAPHICS_LIB)
+
+GRAPHICS_DEFUN_FILES = %reldir%/__init_qt__.cc
+
+GRAPHICS_OCT_FILES = $(LIBOCTGUI_GRAPHICS_LIB:.la=.oct)
 
-%canon_reldir%_%canon_reldir%_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
+OCTAVE_INTERPRETER_TARGETS += $(GRAPHICS_OCT_FILES)
+
+OCT_FILE_LIBS += $(LIBOCTGUI_GRAPHICS_LIB)
+
+## Use stamp files to avoid problems with checking timestamps
+## of symbolic links
+
+%reldir%/__init_qt__.oct : $(LIBOCTGUI_GRAPHICS_LIB)
+	$(AM_V_GEN)$(INSTALL_PROGRAM) %reldir%/.libs/$(shell $(SED) -n -e "s/dlname='\([^']*\)'/\1/p" < $<) $@
 
-noinst_LTLIBRARIES += %reldir%/libgui-graphics.la
+GRAPHICS_PKG_ADD_FILE = %reldir%/PKG_ADD
+
+%reldir%/PKG_ADD: $(GRAPHICS_DEFUN_FILES) $(srcdir)/build-aux/mk-pkg-add.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)rm -f $@-t && \
+	$(SHELL) $(srcdir)/build-aux/mk-pkg-add.sh "$(srcdir)" $(GRAPHICS_DEFUN_FILES) > $@-t && \
+	mv $@-t $@
+
+OCT_FILE_PKG_ADD_FILES += \
+  $(GRAPHICS_PKG_ADD_FILE)
 
 libgui_EXTRA_DIST += \
   %reldir%/qthandles.qrc \
@@ -159,11 +198,13 @@
   %reldir%/images/select.png \
   %reldir%/images/zoom-in.png \
   %reldir%/images/zoom-out.png \
-  $(octave_gui_graphics_UI)
+  $(__init_qt___UI)
 
 libgui_CLEANFILES += \
-  $(octave_gui_graphics_MOC) \
-  $(octave_gui_graphics_RC) \
-  $(octave_gui_graphics_UI_H)
+  $(GRAPHICS_OCT_FILES) \
+  $(GRAPHICS_PKG_ADD_FILE) \
+  $(__init_qt___MOC) \
+  $(__init_qt___RC) \
+  $(__init_qt___UI_H)
 
 endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/qopengl-functions.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,454 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+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_qopengl_functions_h)
+#define octave_qopengl_functions_h 1
+
+#include "oct-opengl.h"
+
+#if defined (HAVE_QOPENGLFUNCTIONS_1_1)
+#  include <QOpenGLFunctions_1_1>
+#endif
+
+namespace octave
+{
+  // If we don't have QOPENGLFUNCTIONS_1_1, then we will default to
+  // calling OpenGL functions directly through the base
+  // opengl_functions class.
+
+  class qopengl_functions : public opengl_functions
+  {
+  public:
+
+    qopengl_functions (void)
+#if defined (HAVE_QOPENGLFUNCTIONS_1_1)
+      : m_glfcns ()
+#endif
+    { }
+
+    qopengl_functions (const qopengl_functions&) = default;
+
+    qopengl_functions& operator = (const qopengl_functions&) = default;
+
+    ~qopengl_functions (void) = default;
+
+    void init (void)
+    {
+#if defined (HAVE_QOPENGLFUNCTIONS_1_1)
+      m_glfcns.initializeOpenGLFunctions ();
+#endif
+    }
+
+#if defined (HAVE_QOPENGLFUNCTIONS_1_1)
+
+    void glAlphaFunc (GLenum func, GLclampf ref)
+    {
+      m_glfcns.glAlphaFunc (func, ref);
+    }
+
+    void glBegin (GLenum mode)
+    {
+      m_glfcns.glBegin (mode);
+    }
+
+    void glBindTexture (GLenum target, GLuint texture)
+    {
+      m_glfcns.glBindTexture (target, texture);
+    }
+
+    void glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig,
+                   GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
+    {
+      m_glfcns.glBitmap (width, height, xorig, yorig, xmove, ymove, bitmap);
+    }
+
+    void glBlendFunc (GLenum sfactor, GLenum dfactor)
+    {
+      m_glfcns.glBlendFunc (sfactor, dfactor);
+    }
+
+    void glCallList (GLuint list)
+    {
+      m_glfcns.glCallList (list);
+    }
+
+    void glClearColor (GLclampf red, GLclampf green, GLclampf blue,
+                       GLclampf alpha)
+    {
+      m_glfcns.glClearColor (red, green, blue, alpha);
+    }
+
+    void glClear (GLbitfield mask)
+    {
+      m_glfcns.glClear (mask);
+    }
+
+    void glClipPlane (GLenum plane, const GLdouble *equation)
+    {
+      m_glfcns.glClipPlane (plane, equation);
+    }
+
+    void glColor3dv (const GLdouble *v)
+    {
+      m_glfcns.glColor3dv (v);
+    }
+
+    void glColor3f (GLfloat red, GLfloat green, GLfloat blue)
+    {
+      m_glfcns.glColor3f (red, green, blue);
+    }
+
+    void glColor3fv (const GLfloat *v)
+    {
+      m_glfcns.glColor3fv (v);
+    }
+
+    void glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
+    {
+      m_glfcns.glColor4d (red, green, blue, alpha);
+    }
+
+    void glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+    {
+      m_glfcns.glColor4f (red, green, blue, alpha);
+    }
+
+    void glColor4fv (const GLfloat *v)
+    {
+      m_glfcns.glColor4fv (v);
+    }
+
+    void glDeleteLists (GLuint list, GLsizei range)
+    {
+      m_glfcns.glDeleteLists (list, range);
+    }
+
+    void glDeleteTextures (GLsizei n, const GLuint *textures)
+    {
+      m_glfcns.glDeleteTextures (n, textures);
+    }
+
+    void glDepthFunc (GLenum func)
+    {
+      m_glfcns.glDepthFunc (func);
+    }
+
+    void glDisable (GLenum cap)
+    {
+      m_glfcns.glDisable (cap);
+    }
+
+    void glDrawPixels (GLsizei width, GLsizei height, GLenum format,
+                       GLenum type, const GLvoid *pixels)
+    {
+      m_glfcns.glDrawPixels (width, height, format, type, pixels);
+    }
+
+    void glEdgeFlag (GLboolean flag)
+    {
+      m_glfcns.glEdgeFlag (flag);
+    }
+
+    void glEnable (GLenum cap)
+    {
+      m_glfcns.glEnable (cap);
+    }
+
+    void glEndList (void)
+    {
+      m_glfcns.glEndList ();
+    }
+
+    void glEnd (void)
+    {
+      m_glfcns.glEnd ();
+    }
+
+    void glFinish (void)
+    {
+      m_glfcns.glFinish ();
+    }
+
+    GLuint glGenLists (GLsizei range)
+    {
+      return m_glfcns.glGenLists (range);
+    }
+
+    void glGenTextures (GLsizei n, GLuint *textures)
+    {
+      m_glfcns.glGenTextures (n, textures);
+    }
+
+    void glGetBooleanv (GLenum pname, GLboolean *data)
+    {
+      m_glfcns.glGetBooleanv (pname, data);
+    }
+
+    void glGetDoublev (GLenum pname, GLdouble *data)
+    {
+      m_glfcns.glGetDoublev (pname, data);
+    }
+
+    GLenum glGetError (void)
+    {
+      return m_glfcns.glGetError ();
+    }
+
+    void glGetFloatv (GLenum pname, GLfloat *data)
+    {
+      m_glfcns.glGetFloatv (pname, data);
+    }
+
+    void glGetIntegerv (GLenum pname, GLint *data)
+    {
+      m_glfcns.glGetIntegerv (pname, data);
+    }
+
+    const GLubyte * glGetString (GLenum name)
+    {
+      return m_glfcns.glGetString (name);
+    }
+
+    void glHint (GLenum target, GLenum mode)
+    {
+      m_glfcns.glHint (target, mode);
+    }
+
+    void glInitNames (void)
+    {
+      m_glfcns.glInitNames ();
+    }
+
+    GLboolean glIsEnabled (GLenum cap)
+    {
+      return m_glfcns.glIsEnabled (cap);
+    }
+
+    void glLightfv (GLenum light, GLenum pname, const GLfloat *params)
+    {
+      m_glfcns.glLightfv (light, pname, params);
+    }
+
+    void glLineStipple (GLint factor, GLushort pattern)
+    {
+      m_glfcns.glLineStipple (factor, pattern);
+    }
+
+    void glLineWidth (GLfloat width)
+    {
+      m_glfcns.glLineWidth (width);
+    }
+
+    void glLoadIdentity (void)
+    {
+      m_glfcns.glLoadIdentity ();
+    }
+
+    void glMaterialf (GLenum face, GLenum pname, GLfloat param)
+    {
+      m_glfcns.glMaterialf (face, pname, param);
+    }
+
+    void glMaterialfv (GLenum face, GLenum pname, const GLfloat *params)
+    {
+      m_glfcns.glMaterialfv (face, pname, params);
+    }
+
+    void glMatrixMode (GLenum mode)
+    {
+      m_glfcns.glMatrixMode (mode);
+    }
+
+    void glMultMatrixd (const GLdouble *m)
+    {
+      m_glfcns.glMultMatrixd (m);
+    }
+
+    void glNewList (GLuint list, GLenum mode)
+    {
+      m_glfcns.glNewList (list, mode);
+    }
+
+    void glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz)
+    {
+      m_glfcns.glNormal3d (nx, ny, nz);
+    }
+
+    void glNormal3dv (const GLdouble *v)
+    {
+      m_glfcns.glNormal3dv (v);
+    }
+
+    void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,
+                  GLdouble near_val, GLdouble far_val)
+    {
+      m_glfcns.glOrtho (left, right, bottom, top, near_val, far_val);
+    }
+
+    void glPixelStorei (GLenum pname, GLint param)
+    {
+      m_glfcns.glPixelStorei (pname, param);
+    }
+
+    void glPixelZoom (GLfloat xfactor, GLfloat yfactor)
+    {
+      m_glfcns.glPixelZoom (xfactor, yfactor);
+    }
+
+    void glPolygonMode (GLenum face, GLenum mode)
+    {
+      m_glfcns.glPolygonMode (face, mode);
+    }
+
+    void glPolygonOffset (GLfloat factor, GLfloat units)
+    {
+      m_glfcns.glPolygonOffset (factor, units);
+    }
+
+    void glPopAttrib (void)
+    {
+      m_glfcns.glPopAttrib ();
+    }
+
+    void glPopMatrix (void)
+    {
+      m_glfcns.glPopMatrix ();
+    }
+
+    void glPopName (void)
+    {
+      m_glfcns.glPopName ();
+    }
+
+    void glPushAttrib (GLbitfield mask)
+    {
+      m_glfcns.glPushAttrib (mask);
+    }
+
+    void glPushMatrix (void)
+    {
+      m_glfcns.glPushMatrix ();
+    }
+
+    void glPushName (GLuint name)
+    {
+      m_glfcns.glPushName (name);
+    }
+
+    void glRasterPos3d (GLdouble x, GLdouble y, GLdouble z)
+    {
+      m_glfcns.glRasterPos3d (x, y, z);
+    }
+
+    void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height,
+                       GLenum format, GLenum type, GLvoid *pixels)
+    {
+      m_glfcns.glReadPixels (x, y, width, height, format, type, pixels);
+    }
+
+    GLint glRenderMode (GLenum mode)
+    {
+      return m_glfcns.glRenderMode (mode);
+    }
+
+    void glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+    {
+      m_glfcns.glRotated (angle, x, y, z);
+    }
+
+    void glScaled (GLdouble x, GLdouble y, GLdouble z)
+    {
+      m_glfcns.glScaled (x, y, z);
+    }
+
+    void glScalef (GLfloat x, GLfloat y, GLfloat z)
+    {
+      m_glfcns.glScalef (x, y, z);
+    }
+
+    void glSelectBuffer (GLsizei size, GLuint *buffer)
+    {
+      m_glfcns.glSelectBuffer (size, buffer);
+    }
+
+    void glShadeModel (GLenum mode)
+    {
+      m_glfcns.glShadeModel (mode);
+    }
+
+    void glTexCoord2d (GLdouble s, GLdouble t)
+    {
+      m_glfcns.glTexCoord2d (s, t);
+    }
+
+    void glTexImage2D (GLenum target, GLint level, GLint internalFormat,
+                       GLsizei width, GLsizei height, GLint border,
+                       GLenum format, GLenum type, const GLvoid *pixels)
+    {
+      m_glfcns.glTexImage2D (target, level, internalFormat, width, height,
+                             border, format, type, pixels);
+    }
+
+    void glTexParameteri (GLenum target, GLenum pname, GLint param)
+    {
+      m_glfcns.glTexParameteri (target, pname, param);
+    }
+
+    void glTranslated (GLdouble x, GLdouble y, GLdouble z)
+    {
+      m_glfcns.glTranslated (x, y, z);
+    }
+
+    void glTranslatef (GLfloat x, GLfloat y, GLfloat z)
+    {
+      m_glfcns.glTranslatef (x, y, z);
+    }
+
+    void glVertex2d (GLdouble x, GLdouble y)
+    {
+      m_glfcns.glVertex2d (x, y);
+    }
+
+    void glVertex3d (GLdouble x, GLdouble y, GLdouble z)
+    {
+      m_glfcns.glVertex3d (x, y, z);
+    }
+
+    void glVertex3dv (const GLdouble *v)
+    {
+      m_glfcns.glVertex3dv (v);
+    }
+
+    void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
+    {
+      m_glfcns.glViewport (x, y, width, height);
+    }
+
+  private:
+
+    QOpenGLFunctions_1_1 m_glfcns;
+
+#endif
+  };
+}
+
+#endif
--- a/libgui/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -39,7 +39,7 @@
 
 include %reldir%/src/module.mk
 include %reldir%/graphics/module.mk
-include %reldir%/qterminal-module.mk
+include %reldir%/qterminal/module.mk
 
 nodist_%canon_reldir%_liboctgui_la_SOURCES = \
   %reldir%/liboctgui-build-info.cc
@@ -50,19 +50,16 @@
   -Ilibgui \
   -I$(srcdir)/libgui
 
-%canon_reldir%_liboctgui_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
-
-%canon_reldir%_liboctgui_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
-
 %canon_reldir%_liboctgui_la_LIBADD = \
   %reldir%/qterminal/libqterminal.la \
   %reldir%/src/libgui-src.la \
-  %reldir%/graphics/libgui-graphics.la \
   libinterp/liboctinterp.la \
   liboctave/liboctave.la \
-  $(LIBOCTGUI_LINK_DEPS)
+  $(QT_LIBS)
 
-# Increment these as needed and according to the rules in the libtool manual:
+## Increment the following version numbers as needed and according
+## to the rules in the etc/HACKING.md file:
+
 %canon_reldir%_liboctgui_current = 4
 %canon_reldir%_liboctgui_revision = 0
 %canon_reldir%_liboctgui_age = 0
--- a/libgui/qterminal-module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-noinst_HEADERS += \
-  libgui/qterminal/libqterminal/QTerminal.h \
-  libgui/qterminal/libqterminal/win32/QTerminalColors.h \
-  libgui/qterminal/libqterminal/win32/QWinTerminalImpl.h \
-  libgui/qterminal/libqterminal/unix/BlockArray.h \
-  libgui/qterminal/libqterminal/unix/Character.h \
-  libgui/qterminal/libqterminal/unix/CharacterColor.h \
-  libgui/qterminal/libqterminal/unix/Emulation.h \
-  libgui/qterminal/libqterminal/unix/ExtendedDefaultTranslator.h \
-  libgui/qterminal/libqterminal/unix/ExtendedDefaultTranslatorMac.h \
-  libgui/qterminal/libqterminal/unix/Filter.h \
-  libgui/qterminal/libqterminal/unix/History.h \
-  libgui/qterminal/libqterminal/unix/KeyboardTranslator.h \
-  libgui/qterminal/libqterminal/unix/konsole_wcwidth.h \
-  libgui/qterminal/libqterminal/unix/kpty.h \
-  libgui/qterminal/libqterminal/unix/kpty_p.h \
-  libgui/qterminal/libqterminal/unix/LineFont.h \
-  libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h \
-  libgui/qterminal/libqterminal/unix/Screen.h \
-  libgui/qterminal/libqterminal/unix/ScreenWindow.h \
-  libgui/qterminal/libqterminal/unix/TerminalCharacterDecoder.h \
-  libgui/qterminal/libqterminal/unix/Vt102Emulation.h \
-  libgui/qterminal/libqterminal/unix/SelfListener.h \
-  libgui/qterminal/libqterminal/unix/TerminalModel.h \
-  libgui/qterminal/libqterminal/unix/TerminalView.h
-
-libgui_qterminal_libqterminal_la_MOC =
-
-OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC = \
-  libgui/qterminal/libqterminal/moc-QTerminal.cc
-
-$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC): | libgui/qterminal/libqterminal/$(octave_dirstamp)
-
-DIRSTAMP_FILES += \
-  libgui/qterminal/libqterminal/$(octave_dirstamp)
-
-libgui_qterminal_libqterminal_la_MOC += \
-  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC)
-
-nodist_libgui_qterminal_libqterminal_la_SOURCES = $(libgui_qterminal_libqterminal_la_MOC)
-
-libgui_qterminal_libqterminal_la_CPPFLAGS = \
-  $(AM_CPPFLAGS) \
-  @QT_CPPFLAGS@ \
-  -I$(srcdir)/libgui/qterminal/libqterminal \
-  -I$(srcdir)/libgui/src
-
-libgui_qterminal_libqterminal_la_CFLAGS = $(AM_CFLAGS)
-
-libgui_qterminal_libqterminal_la_CXXFLAGS = $(AM_CXXFLAGS)
-
-if WIN32_TERMINAL
-
-libgui_qterminal_libqterminal_la_SOURCES = \
-  libgui/qterminal/libqterminal/win32/QTerminalColors.cpp \
-  libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp \
-  libgui/qterminal/libqterminal/QTerminal.cc
-
-OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC = \
-  libgui/qterminal/libqterminal/win32/moc-QWinTerminalImpl.cc
-
-libgui_qterminal_libqterminal_la_MOC += \
-  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC)
-
-$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC): | libgui/qterminal/libqterminal/win32/$(octave_dirstamp)
-
-DIRSTAMP_FILES += \
-  libgui/qterminal/libqterminal/win32/$(octave_dirstamp)
-
-libgui_qterminal_libqterminal_la_CPPFLAGS += -DUNICODE
-
-# This flag is required to let MOC know about Q_OS_WIN32.
-MOC_CPPFLAGS += -DQ_OS_WIN32
-
-else
-
-libgui_qterminal_libqterminal_la_SOURCES = \
-  libgui/qterminal/libqterminal/unix/BlockArray.cpp \
-  libgui/qterminal/libqterminal/unix/Emulation.cpp \
-  libgui/qterminal/libqterminal/unix/Filter.cpp \
-  libgui/qterminal/libqterminal/unix/History.cpp \
-  libgui/qterminal/libqterminal/unix/KeyboardTranslator.cpp \
-  libgui/qterminal/libqterminal/unix/konsole_wcwidth.cpp \
-  libgui/qterminal/libqterminal/unix/kpty.cpp \
-  libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp \
-  libgui/qterminal/libqterminal/unix/Screen.cpp \
-  libgui/qterminal/libqterminal/unix/ScreenWindow.cpp \
-  libgui/qterminal/libqterminal/unix/TerminalCharacterDecoder.cpp \
-  libgui/qterminal/libqterminal/unix/Vt102Emulation.cpp \
-  libgui/qterminal/libqterminal/unix/SelfListener.cpp \
-  libgui/qterminal/libqterminal/unix/TerminalModel.cpp \
-  libgui/qterminal/libqterminal/unix/TerminalView.cpp \
-  libgui/qterminal/libqterminal/QTerminal.cc
-
-OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC = \
-  libgui/qterminal/libqterminal/unix/moc-Emulation.cc \
-  libgui/qterminal/libqterminal/unix/moc-Filter.cc \
-  libgui/qterminal/libqterminal/unix/moc-QUnixTerminalImpl.cc \
-  libgui/qterminal/libqterminal/unix/moc-ScreenWindow.cc \
-  libgui/qterminal/libqterminal/unix/moc-SelfListener.cc \
-  libgui/qterminal/libqterminal/unix/moc-TerminalModel.cc \
-  libgui/qterminal/libqterminal/unix/moc-TerminalView.cc \
-  libgui/qterminal/libqterminal/unix/moc-Vt102Emulation.cc
-
-libgui_qterminal_libqterminal_la_MOC += \
-  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC)
-
-$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC): | libgui/qterminal/libqterminal/unix/$(octave_dirstamp)
-
-DIRSTAMP_FILES += \
-  libgui/qterminal/libqterminal/unix/$(octave_dirstamp)
-
-endif
-
-noinst_LTLIBRARIES += libgui/qterminal/libqterminal.la
-
-libgui_CLEANFILES += $(libgui_qterminal_libqterminal_la_MOC)
--- a/libgui/qterminal/libqterminal/QTerminal.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/QTerminal.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -22,6 +22,7 @@
 */
 
 #include "QTerminal.h"
+#include "gui-preferences.h"
 
 #if defined (Q_OS_WIN32)
 # include "win32/QWinTerminalImpl.h"
@@ -126,6 +127,7 @@
 
     _paste_action->setEnabled (cb->text().length() > 0);
     _copy_action->setEnabled (has_selected_text);
+    _run_selection_action->setEnabled (has_selected_text);
 
     // Get the actions of any hotspots the filters may have found
     QList<QAction*> actions = get_hotspot_actions (at);
@@ -142,6 +144,17 @@
       _contextMenu->removeAction (actions.at(i));
   }
 
+// slot for running the selected code
+void
+QTerminal::run_selection ()
+{
+  QStringList commands = selectedText ().split (QRegExp ("[\r\n]"),
+                                                QString::SkipEmptyParts);
+  for (int i = 0; i < commands.size (); i++)
+    emit execute_command_in_terminal_signal (commands.at (i));
+
+}
+
 // slot for edit files in error messages
 void
 QTerminal::edit_file ()
@@ -160,11 +173,15 @@
   // Set terminal font:
   QFont term_font = QFont ();
   term_font.setStyleHint (QFont::TypeWriter);
+  QString default_font = settings->value (global_mono_font.key, global_mono_font.def).toString ();
   term_font.setFamily
-    (settings->value ("terminal/fontName", "Courier New").toString ());
+    (settings->value (cs_font.key, default_font).toString ());
   term_font.setPointSize (settings->value ("terminal/fontSize", 10).toInt ());
   setTerminalFont (term_font);
 
+  QFontMetrics metrics (term_font);
+  setMinimumSize (metrics.maxWidth ()*16, metrics.height ()*3);
+
   QString cursorType
     = settings->value ("terminal/cursorType", "ibeam").toString ();
 
--- a/libgui/qterminal/libqterminal/QTerminal.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/QTerminal.h	Thu Dec 20 17:18:56 2018 -0500
@@ -99,6 +99,8 @@
 
   void edit_mfile_request (const QString&, int);
 
+  void execute_command_in_terminal_signal (const QString&);
+
 public slots:
 
   virtual void copyClipboard (void) = 0;
@@ -117,6 +119,8 @@
 
   void set_global_shortcuts (bool focus_out);
 
+  void run_selection (void);
+
   void edit_file (void);
 
   virtual void handle_visibility_changed (bool) { };
@@ -130,19 +134,22 @@
 
     _contextMenu = new QMenu (this);
 
-    _copy_action = _contextMenu->addAction (
-                     resource_manager::icon ("edit-copy"),
-                     tr ("Copy"), this, SLOT (copyClipboard ()));
+    _copy_action = _contextMenu->addAction
+      (octave::resource_manager::icon ("edit-copy"),
+       tr ("Copy"), this, SLOT (copyClipboard ()));
 
-    _paste_action = _contextMenu->addAction (
-                      resource_manager::icon ("edit-paste"),
-                      tr ("Paste"), this, SLOT (pasteClipboard ()));
+    _paste_action = _contextMenu->addAction
+     (octave::resource_manager::icon ("edit-paste"),
+      tr ("Paste"), this, SLOT (pasteClipboard ()));
 
     _contextMenu->addSeparator ();
 
     _selectall_action = _contextMenu->addAction (
                           tr ("Select All"), this, SLOT (selectAll ()));
 
+    _run_selection_action = _contextMenu->addAction (
+                     tr ("Run Selection"), this, SLOT (run_selection ()));
+
     _edit_action = _contextMenu->addAction (
                      tr (""), this, SLOT (edit_file ()));
 
@@ -160,6 +167,9 @@
     connect (this, SIGNAL (edit_mfile_request (const QString&, int)),
              xparent, SLOT (edit_mfile (const QString&, int)));
 
+    connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)),
+             xparent, SLOT (execute_command_in_terminal (const QString&)));
+
     connect (xparent, SIGNAL (settings_changed (const QSettings *)),
              this, SLOT (notice_settings (const QSettings *)));
 
@@ -200,6 +210,7 @@
   QAction * _paste_action;
   QAction * _selectall_action;
   QAction * _edit_action;
+  QAction * _run_selection_action;
 
   QAction *_interrupt_action;
   QAction *_nop_action;
--- a/libgui/qterminal/libqterminal/unix/Filter.cpp	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/unix/Filter.cpp	Thu Dec 20 17:18:56 2018 -0500
@@ -23,9 +23,6 @@
 // Own
 #include "unix/Filter.h"
 
-// System
-#include <iostream>
-
 // Qt
 #include <QDesktopServices>
 #include <QAction>
--- a/libgui/qterminal/libqterminal/unix/History.cpp	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/unix/History.cpp	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,6 @@
 #include "unix/History.h"
 
 // System
-#include <iostream>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,6 @@
     : QTerminal(p),
       _parent (p)
 {
-    setMinimumSize(300, 200);
     initialize();
 }
 
@@ -188,6 +187,11 @@
 
     m_terminalView->setColorTable(cols);
 
+    QString css = QString ("TerminalView {\n"
+                           "  background: %1;\n"
+                           "}\n").arg (color.name ());
+    setStyleSheet (css);
+
   }
 void QUnixTerminalImpl::setForegroundColor (const QColor& color)
 {
--- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Thu Dec 20 17:18:56 2018 -0500
@@ -1570,6 +1570,46 @@
   getCharacterPosition(ev->pos(),charLine,charColumn);
   QPoint pos = QPoint(charColumn,charLine);
 
+  // reposition cursor if mouseclick happens in the currently editable line
+  QVector<LineProperty> lineprop = _screenWindow->getLineProperties ();
+  int lineStart = _screenWindow->cursorPosition ().y ();
+  if (lineStart > 0)
+    {
+      while (lineprop[lineStart-1] & LINE_WRAPPED)
+        lineStart--;
+    }
+
+  if (charLine >= lineStart)
+    {
+      int posInLineCursor = _screenWindow->cursorPosition ().x ()
+                            + qMax (0,(_screenWindow->cursorPosition ().y ()-lineStart))
+                            * _screenWindow->windowColumns ();
+      int posInLineClick = charColumn
+                           + qMax (0, (charLine - lineStart))
+                           * _screenWindow->windowColumns ();
+
+      if (posInLineCursor > posInLineClick)
+        {
+          QKeyEvent *event = new QKeyEvent (QEvent::KeyPress,Qt::Key_Left,
+                                            Qt::NoModifier,QString (""));
+
+          for (int i = 0; i < posInLineCursor - posInLineClick; i++)
+            emit keyPressedSignal (event);
+
+          delete event;
+        }
+      else if (posInLineClick > posInLineCursor)
+        {
+          QKeyEvent *event = new QKeyEvent (QEvent::KeyPress,Qt::Key_Right,
+                                            Qt::NoModifier,QString (""));
+
+          for (int i = 0; i < posInLineClick - posInLineCursor; i++)
+            emit keyPressedSignal (event);
+
+          delete event;
+        }
+    }
+
   if ( ev->button() == Qt::LeftButton)
     {
 
@@ -2418,7 +2458,56 @@
     }
 
   if ( emitKeyPressSignal && !_readonly )
-    emit keyPressedSignal(event);
+    {
+      // Clear selection if the cursor is moved with arrow keys
+      bool emitKey = true;
+      if ((event->modifiers() == Qt::NoModifier)
+          && (event->key() == Qt::Key_Right || event->key() == Qt::Key_Left))
+        _screenWindow->clearSelection();
+
+      // Delete selected text if printable key is pressed
+      if ( !event->text ().isEmpty () )
+        {
+          int lineStart, colStart, lineEnd, colEnd;
+          _screenWindow->getSelectionStart (colStart, lineStart);
+          _screenWindow->getSelectionEnd (colEnd, lineEnd);
+          int cursorLoc = loc (_screenWindow->cursorPosition ().x (),
+                               _screenWindow->cursorPosition ().y ());
+
+          //Check if there is a selection in the current line
+          if ((loc (colStart,lineStart) != loc (colEnd, lineEnd))
+               && (cursorLoc >=loc (colStart,lineStart))
+               && (cursorLoc-1 <= loc (colEnd,lineEnd)))
+            {
+              QKeyEvent *ev = new QKeyEvent (QEvent::KeyPress,Qt::Key_Backspace,
+                                             Qt::NoModifier,QString (""));
+
+              if (cursorLoc < loc (colEnd, lineEnd))
+                {
+                  QKeyEvent *ev_right = new QKeyEvent (QEvent::KeyPress,Qt::Key_Right,
+                                                       Qt::NoModifier,QString (""));
+                  for (int i = 0; i < loc (colEnd,lineEnd) - cursorLoc + 1; i++)
+                    emit keyPressedSignal (ev_right);
+                  delete ev_right;
+                }
+
+              for (int i = 0; i < loc (colEnd, lineEnd) - loc (colStart, lineStart) + 1; i++)
+                emit keyPressedSignal (ev);
+
+              delete ev;
+
+              // Backspace deleted the selected text and has done its duty, no need to call it again
+              if (event->key() == Qt::Key_Backspace)
+                {
+                  _screenWindow->clearSelection ();
+                  emitKey = false;
+                }
+            }
+        }
+
+      if (emitKey)
+        emit keyPressedSignal (event);
+    }
 
   if (_readonly) {
       event->ignore();
@@ -2426,6 +2515,7 @@
   else {
       event->accept();
     }
+
 }
 
 void TerminalView::inputMethodEvent( QInputMethodEvent* event )
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Thu Dec 20 17:18:56 2018 -0500
@@ -52,7 +52,6 @@
 #include <versionhelpers.h>
 #include <cstring>
 #include <csignal>
-#include <limits>
 
 #include "QWinTerminalImpl.h"
 #include "QTerminalColors.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/qterminal/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,117 @@
+noinst_HEADERS += \
+  %reldir%/libqterminal/QTerminal.h \
+  %reldir%/libqterminal/win32/QTerminalColors.h \
+  %reldir%/libqterminal/win32/QWinTerminalImpl.h \
+  %reldir%/libqterminal/unix/BlockArray.h \
+  %reldir%/libqterminal/unix/Character.h \
+  %reldir%/libqterminal/unix/CharacterColor.h \
+  %reldir%/libqterminal/unix/Emulation.h \
+  %reldir%/libqterminal/unix/ExtendedDefaultTranslator.h \
+  %reldir%/libqterminal/unix/ExtendedDefaultTranslatorMac.h \
+  %reldir%/libqterminal/unix/Filter.h \
+  %reldir%/libqterminal/unix/History.h \
+  %reldir%/libqterminal/unix/KeyboardTranslator.h \
+  %reldir%/libqterminal/unix/konsole_wcwidth.h \
+  %reldir%/libqterminal/unix/kpty.h \
+  %reldir%/libqterminal/unix/kpty_p.h \
+  %reldir%/libqterminal/unix/LineFont.h \
+  %reldir%/libqterminal/unix/QUnixTerminalImpl.h \
+  %reldir%/libqterminal/unix/Screen.h \
+  %reldir%/libqterminal/unix/ScreenWindow.h \
+  %reldir%/libqterminal/unix/TerminalCharacterDecoder.h \
+  %reldir%/libqterminal/unix/Vt102Emulation.h \
+  %reldir%/libqterminal/unix/SelfListener.h \
+  %reldir%/libqterminal/unix/TerminalModel.h \
+  %reldir%/libqterminal/unix/TerminalView.h
+
+libgui_qterminal_libqterminal_la_MOC =
+
+OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC = \
+  %reldir%/libqterminal/moc-QTerminal.cc
+
+$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC): | %reldir%/libqterminal/$(octave_dirstamp)
+
+DIRSTAMP_FILES += \
+  %reldir%/libqterminal/$(octave_dirstamp)
+
+%canon_reldir%_libqterminal_la_MOC += \
+  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_MOC)
+
+nodist_%canon_reldir%_libqterminal_la_SOURCES = $(%canon_reldir%_libqterminal_la_MOC)
+
+%canon_reldir%_libqterminal_la_CPPFLAGS = \
+  $(AM_CPPFLAGS) \
+  @QT_CPPFLAGS@ \
+  -I$(srcdir)/libgui/qterminal/libqterminal \
+  -I$(srcdir)/libgui/src
+
+%canon_reldir%_libqterminal_la_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS}
+
+%canon_reldir%_libqterminal_la_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS}
+
+if WIN32_TERMINAL
+
+%canon_reldir%_libqterminal_la_SOURCES = \
+  %reldir%/libqterminal/win32/QTerminalColors.cpp \
+  %reldir%/libqterminal/win32/QWinTerminalImpl.cpp \
+  %reldir%/libqterminal/QTerminal.cc
+
+OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC = \
+  %reldir%/libqterminal/win32/moc-QWinTerminalImpl.cc
+
+%canon_reldir%_libqterminal_la_MOC += \
+  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC)
+
+$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_WIN32_MOC): | %reldir%/libqterminal/win32/$(octave_dirstamp)
+
+DIRSTAMP_FILES += \
+  %reldir%/libqterminal/win32/$(octave_dirstamp)
+
+%canon_reldir%_libqterminal_la_CPPFLAGS += -DUNICODE
+
+# This flag is required to let MOC know about Q_OS_WIN32.
+MOC_CPPFLAGS += -DQ_OS_WIN32
+
+else
+
+%canon_reldir%_libqterminal_la_SOURCES = \
+  %reldir%/libqterminal/unix/BlockArray.cpp \
+  %reldir%/libqterminal/unix/Emulation.cpp \
+  %reldir%/libqterminal/unix/Filter.cpp \
+  %reldir%/libqterminal/unix/History.cpp \
+  %reldir%/libqterminal/unix/KeyboardTranslator.cpp \
+  %reldir%/libqterminal/unix/konsole_wcwidth.cpp \
+  %reldir%/libqterminal/unix/kpty.cpp \
+  %reldir%/libqterminal/unix/QUnixTerminalImpl.cpp \
+  %reldir%/libqterminal/unix/Screen.cpp \
+  %reldir%/libqterminal/unix/ScreenWindow.cpp \
+  %reldir%/libqterminal/unix/TerminalCharacterDecoder.cpp \
+  %reldir%/libqterminal/unix/Vt102Emulation.cpp \
+  %reldir%/libqterminal/unix/SelfListener.cpp \
+  %reldir%/libqterminal/unix/TerminalModel.cpp \
+  %reldir%/libqterminal/unix/TerminalView.cpp \
+  %reldir%/libqterminal/QTerminal.cc
+
+OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC = \
+  %reldir%/libqterminal/unix/moc-Emulation.cc \
+  %reldir%/libqterminal/unix/moc-Filter.cc \
+  %reldir%/libqterminal/unix/moc-QUnixTerminalImpl.cc \
+  %reldir%/libqterminal/unix/moc-ScreenWindow.cc \
+  %reldir%/libqterminal/unix/moc-SelfListener.cc \
+  %reldir%/libqterminal/unix/moc-TerminalModel.cc \
+  %reldir%/libqterminal/unix/moc-TerminalView.cc \
+  %reldir%/libqterminal/unix/moc-Vt102Emulation.cc
+
+%canon_reldir%_libqterminal_la_MOC += \
+  $(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC)
+
+$(OCTAVE_GUI_QTERMINAL_LIBQTERMINAL_UNIX_MOC): | %reldir%/libqterminal/unix/$(octave_dirstamp)
+
+DIRSTAMP_FILES += \
+  %reldir%/libqterminal/unix/$(octave_dirstamp)
+
+endif
+
+noinst_LTLIBRARIES += %reldir%/libqterminal.la
+
+libgui_CLEANFILES += $(%canon_reldir%_libqterminal_la_MOC)
--- a/libgui/src/color-picker.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/color-picker.h	Thu Dec 20 17:18:56 2018 -0500
@@ -56,8 +56,4 @@
   };
 }
 
-// FIXME: This is temporary and should be removed when all classes that
-// use the color_picker class are also inside the octave namespace.
-using octave::color_picker;
-
 #endif
--- a/libgui/src/dialog.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/dialog.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
 #endif
 
 #include "dialog.h"
+#include "resource-manager.h"
 
 #include <QString>
 #include <QStringList>
@@ -70,15 +71,18 @@
     // Wait for link thread to go to sleep state.
     lock ();
 
-    // Check for a matching button text while ignoring accelerators because
-    // the window manager may have added one in the passed button
-    QString text_clean = rm_amp (button->text ());
-    for (int i = 0; i < m_button_list.count (); i++)
+    if (button)   // button is NULL when dialog is closed
       {
-        if (rm_amp (m_button_list.at (i)) == text_clean)
+        // Check for a matching button text while ignoring accelerators because
+        // the window manager may have added one in the passed button
+        QString text_clean = rm_amp (button->text ());
+        for (int i = 0; i < m_button_list.count (); i++)
           {
-            m_dialog_button = m_button_list.at (i); // text w/o extra accelerator
-            break;
+            if (rm_amp (m_button_list.at (i)) == text_clean)
+              {
+                m_dialog_button = m_button_list.at (i); // text w/o extra accelerator
+                break;
+              }
           }
       }
 
@@ -230,8 +234,7 @@
 
     selector = view->selectionModel ();
     int i = 0;
-    for (QList<int>::const_iterator it = initial.begin ();
-         it != initial.end (); it++)
+    for (auto it = initial.begin (); it != initial.end (); it++)
       {
         QModelIndex idx = m_model->index (initial.value (i++) - 1, 0,
                                           QModelIndex ());
@@ -460,6 +463,11 @@
 
     setWindowTitle (title.isEmpty () ? " " : title);
     setDirectory (dirname);
+    
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      setOption(QFileDialog::DontUseNativeDialog);
 
     if (multimode == "on")         // uigetfile multiselect=on
       {
--- a/libgui/src/documentation-dock-widget.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/documentation-dock-widget.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -32,14 +32,13 @@
 namespace octave
 {
   documentation_dock_widget::documentation_dock_widget (QWidget *p)
-    : octave_dock_widget (p)
+    : octave_dock_widget ("DocumentationDockWidget", p)
   {
-    setObjectName ("DocumentationDockWidget");
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
     set_title (tr ("Documentation"));
     setStatusTip (tr ("See the documentation for help."));
 
-    m_docs = new octave::documentation (this);
+    m_docs = new documentation (this);
     setWidget (m_docs);
 
     connect (p, SIGNAL (show_doc_signal (const QString&)),
--- a/libgui/src/documentation-dock-widget.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/documentation-dock-widget.h	Thu Dec 20 17:18:56 2018 -0500
@@ -53,7 +53,7 @@
 
   private:
 
-    octave::documentation *m_docs;
+    documentation *m_docs;
   };
 }
 
--- a/libgui/src/documentation.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/documentation.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,6 +28,7 @@
 #include "file-ops.h"
 #include "oct-env.h"
 
+#include <QAction>
 #include <QApplication>
 #include <QCompleter>
 #include <QDir>
@@ -41,26 +42,35 @@
 #include <QLabel>
 #include <QLineEdit>
 #include <QMessageBox>
-#include <QShortcut>
 #include <QTabWidget>
-#include <QToolButton>
 #include <QVBoxLayout>
 
 #include "documentation.h"
 #include "resource-manager.h"
+#include "shortcut-manager.h"
+#include "gui-preferences.h"
 
 namespace octave
 {
   // The documentation splitter, which is the main widget
   // of the doc dock widget
   documentation::documentation (QWidget *p)
-    : QSplitter (Qt::Horizontal, p)
+    : QSplitter (Qt::Horizontal, p),
+      m_doc_widget (p),
+      m_tool_bar (new QToolBar (p)),
+      m_query_string (QString ()),
+      m_prev_pages_menu (new QMenu (p)),
+      m_next_pages_menu (new QMenu (p)),
+      m_prev_pages_count (0),
+      m_next_pages_count (0),
+      m_findnext_shortcut (new QShortcut (p)),
+      m_findprev_shortcut (new QShortcut (p))
   {
     // Get original collection
     QString collection = getenv ("OCTAVE_QTHELP_COLLECTION");
     if (collection.isEmpty ())
-      collection = QString::fromStdString (octave::config::oct_doc_dir ()
-                                           + octave::sys::file_ops::dir_sep_str ()
+      collection = QString::fromStdString (config::oct_doc_dir ()
+                                           + sys::file_ops::dir_sep_str ()
                                            + "octave_interpreter.qhc");
 
     // Setup the help engine with the original collection, use a writable copy
@@ -69,26 +79,34 @@
 
     QString tmpdir = QDir::tempPath();
     m_collection
-      = QString::fromStdString (octave::sys::tempnam (tmpdir.toStdString (),
-                                                      "oct-qhelp-"));
+      = QString::fromStdString (sys::tempnam (tmpdir.toStdString (),
+                                              "oct-qhelp-"));
 
     if (m_help_engine->copyCollectionFile (m_collection))
       m_help_engine->setCollectionFile (m_collection);
     else
+#ifdef ENABLE_DOCS
+      // FIXME: Perhaps a better way to do this would be to keep a count
+      // in the GUI preferences file.  After issuing this warning 3 times
+      // it would be disabled.  The count would need to be reset when a new
+      // version of Octave is installed.
       QMessageBox::warning (this, tr ("Octave Documentation"),
                             tr ("Could not copy help collection to temporary\n"
                                 "file. Search capabilities may be affected.\n"
                                 "%1").arg (m_help_engine->error ()));
+#endif
 
     connect(m_help_engine, SIGNAL(setupFinished()),
             m_help_engine->searchEngine(), SLOT(indexDocumentation()));
 
     if (! m_help_engine->setupData())
       {
+#ifdef ENABLE_DOCS
         QMessageBox::warning (this, tr ("Octave Documentation"),
                               tr ("Could not setup the data required for the\n"
                                   "documentation viewer. Only help texts in\n"
-                                  "the Console Widget will be available."));
+                                  "the Command Window will be available."));
+#endif
         if (m_help_engine)
           delete m_help_engine;
         m_help_engine = 0;
@@ -101,6 +119,10 @@
     connect (m_doc_browser, SIGNAL (cursorPositionChanged (void)),
              this, SLOT(handle_cursor_position_change (void)));
 
+    // Tool bar
+    construct_tool_bar ();
+
+    // Find bar
     QWidget *find_footer = new QWidget (browser_find);
     QLabel *find_label = new QLabel (tr ("Find:"), find_footer);
     m_find_line_edit = new QLineEdit (find_footer);
@@ -129,32 +151,20 @@
     find_footer->setLayout (h_box_find_footer);
 
     QVBoxLayout *v_box_browser_find = new QVBoxLayout (browser_find);
+    v_box_browser_find->addWidget (m_tool_bar);
     v_box_browser_find->addWidget (m_doc_browser);
     v_box_browser_find->addWidget (find_footer);
     browser_find->setLayout (v_box_browser_find);
 
-    QShortcut *show_shortcut = new QShortcut (QKeySequence (QKeySequence::Find), p);
-    show_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (show_shortcut, SIGNAL (activated (void)),
-             m_find_line_edit->parentWidget (), SLOT (show (void)));
-    connect (show_shortcut, SIGNAL (activated (void)),
-             m_find_line_edit, SLOT (selectAll (void)));
-    connect (show_shortcut, SIGNAL (activated (void)),
-             m_find_line_edit, SLOT (setFocus (void)));
-    QShortcut *hide_shortcut = new QShortcut (Qt::Key_Escape, p);
-    hide_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (hide_shortcut, SIGNAL (activated (void)),
-             m_find_line_edit->parentWidget (), SLOT(hide (void)));
-    connect (hide_shortcut, SIGNAL (activated (void)),
-             m_doc_browser, SLOT (setFocus (void)));
-    QShortcut *findnext_shortcut = new QShortcut (QKeySequence (QKeySequence::FindNext), p);
-    findnext_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (findnext_shortcut, SIGNAL (activated (void)),
+    notice_settings (resource_manager::get_settings ());
+
+    m_findnext_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
+    connect (m_findnext_shortcut, SIGNAL (activated (void)),
              this, SLOT(find_forward (void)));
-    QShortcut *findprev_shortcut = new QShortcut (QKeySequence (QKeySequence::FindPrevious), p);
-    findprev_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (findprev_shortcut, SIGNAL (activated (void)),
+    m_findprev_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
+    connect (m_findprev_shortcut, SIGNAL (activated (void)),
              this, SLOT(find_backward (void)));
+
     find_footer->hide ();
     m_search_anchor_position = 0;
 
@@ -165,6 +175,7 @@
 
     // Contents
     QHelpContentWidget *content = m_help_engine->contentWidget ();
+    content->setObjectName ("documentation_tab_contents");
     navi->addTab (content, tr ("Contents"));
 
     connect(m_help_engine->contentWidget (),
@@ -195,12 +206,13 @@
     filter_all->setLayout (h_box_index);
 
     QWidget *index_all = new QWidget (navi);
+    index_all->setObjectName ("documentation_tab_index");
     QVBoxLayout *v_box_index = new QVBoxLayout (index_all);
     v_box_index->addWidget (filter_all);
     v_box_index->addWidget (index);
     index_all->setLayout (v_box_index);
 
-    navi->addTab (index_all, tr ("Index"));
+    navi->addTab (index_all, tr ("Function Index"));
 
     connect(m_help_engine->indexWidget (),
             SIGNAL (linkActivated (const QUrl&, const QString&)),
@@ -222,6 +234,7 @@
     v_box_search->addWidget (search);
     v_box_search->addWidget (result);
     search_all->setLayout (v_box_search);
+    search_all->setObjectName ("documentation_tab_search");
     navi->addTab (search_all, tr ("Search"));
 
     connect (search, SIGNAL (search (void)),
@@ -234,8 +247,8 @@
 
     connect (search_engine->resultWidget (),
              SIGNAL (requestShowLink (const QUrl&)),
-             m_doc_browser,
-             SLOT(handle_index_clicked (const QUrl&)));
+             this,
+             SLOT(handle_search_result_clicked (const QUrl&)));
 
     // Fill the splitter
     insertWidget (0, navi);
@@ -272,16 +285,123 @@
       }
   }
 
+  QAction * documentation::add_action (const QIcon& icon, const QString& text,
+                                       const char *member, QWidget *receiver,
+                                       QToolBar *tool_bar)
+  {
+    QAction *a;
+    QWidget *r = this;
+    if (receiver != nullptr)
+      r = receiver;
+
+    a = new QAction (icon, text, this);
+    connect (a, SIGNAL (triggered ()), r, member);
+
+    if (tool_bar)
+      tool_bar->addAction (a);
+
+    m_doc_widget->addAction (a);  // important for shortcut context
+    a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
+
+    return a;
+  }
+
+  void documentation::construct_tool_bar (void)
+  {
+    // Home, Previous, Next
+    m_action_go_home = add_action (resource_manager::icon ("go-home"),
+                                   tr ("Go home"), SLOT (home (void)),
+                                   m_doc_browser, m_tool_bar);
+    m_action_go_prev = add_action (resource_manager::icon ("go-previous"),
+                                   tr ("Go back"), SLOT (backward (void)),
+                                   m_doc_browser, m_tool_bar);
+    m_action_go_prev->setEnabled (false);
+
+    // popdown menu with prev pages files
+    QToolButton *popdown_button_prev_pages = new QToolButton ();
+    popdown_button_prev_pages->setToolTip (tr ("Previous Pages"));
+    popdown_button_prev_pages->setMenu (m_prev_pages_menu);
+    popdown_button_prev_pages->setPopupMode (QToolButton::InstantPopup);
+    popdown_button_prev_pages->setToolButtonStyle (Qt::ToolButtonTextOnly);
+    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 (resource_manager::icon ("go-next"),
+                                   tr ("Go forward"), SLOT (forward (void)),
+                                   m_doc_browser, m_tool_bar);
+    m_action_go_next->setEnabled (false);
+
+    // popdown menu with prev pages files
+    QToolButton *popdown_button_next_pages = new QToolButton ();
+    popdown_button_next_pages->setToolTip (tr ("Next Pages"));
+    popdown_button_next_pages->setMenu (m_next_pages_menu);
+    popdown_button_next_pages->setPopupMode (QToolButton::InstantPopup);
+    popdown_button_next_pages->setToolButtonStyle (Qt::ToolButtonTextOnly);
+    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)));
+
+    // Init prev/next menus
+    for (int i = 0; i < max_history_entries; ++i)
+      {
+        m_prev_pages_actions[i] = new QAction (this);
+        m_prev_pages_actions[i]->setVisible (false);
+        m_next_pages_actions[i] = new QAction (this);
+        m_next_pages_actions[i]->setVisible (false);
+        m_prev_pages_menu->addAction (m_prev_pages_actions[i]);
+        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 *)));
+
+    // Find
+    m_tool_bar->addSeparator ();
+    m_action_find = add_action (resource_manager::icon ("edit-find"),
+                                   tr ("Find"), SLOT (activate_find (void)),
+                                   this, m_tool_bar);
+
+    // Zoom
+    m_tool_bar->addSeparator ();
+    m_action_zoom_in = add_action (resource_manager::icon ("zoom-in"),
+                                   tr ("Zoom in"), SLOT (zoom_in (void)),
+                                   m_doc_browser, m_tool_bar);
+    m_action_zoom_out = add_action (resource_manager::icon ("zoom-out"),
+                                    tr ("Zoom out"), SLOT (zoom_out (void)),
+                                    m_doc_browser, m_tool_bar);
+    m_action_zoom_original = add_action (resource_manager::icon ("zoom-original"),
+                                   tr ("Zoom original"), SLOT (zoom_original (void)),
+                                   m_doc_browser, m_tool_bar);
+  }
+
   void documentation::global_search (void)
   {
 #if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
     QString queries
       = m_help_engine->searchEngine ()->queryWidget ()->searchInput ();
+    m_query_string = queries.split (" ").first ();
 #else
     QList<QHelpSearchQuery> queries
       = m_help_engine->searchEngine ()->queryWidget ()->query ();
+    if (queries.count ())
+      m_query_string = queries.first ().wordList.first ();
+    else
+      m_query_string = "";
 #endif
 
+
     m_help_engine->searchEngine ()->search (queries);
   }
 
@@ -292,12 +412,151 @@
 
   void documentation::global_search_finished (int)
   {
+    if (! m_internal_search.isEmpty ())
+      {
+        QHelpSearchEngine *search_engine = m_help_engine->searchEngine ();
+        if (search_engine)
+          {
+#if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
+            QVector<QHelpSearchResult> res
+              = search_engine->searchResults (0, search_engine->searchResultCount ());
+#else
+            QList< QPair<QString, QString> > res
+              = search_engine->hits (0, search_engine->hitCount ());
+#endif
+
+            if (res.count ())
+              {
+                QUrl url;
+
+                if (res.count () == 1)
+#if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
+                  url = res.front ().url ();
+#else
+                  url = res.front ().first;
+#endif
+                else
+                  {
+                    // Remove the quotes we added
+                    QString search_string = m_internal_search;
+
+                    for (auto r = res.begin (); r != res.end (); r++)
+                      {
+#if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
+                        QString title = r->title ().toLower ();
+                        QUrl tmpurl = r->url ();
+#else
+                        QString title = r->second.toLower ();
+                        QUrl tmpurl = r->first;
+#endif
+                        if (title.contains (search_string.toLower ()))
+                          {
+                            if (title.indexOf (search_string.toLower ()) == 0)
+                              {
+                                url = tmpurl;
+                                break;
+                              }
+                            else if (url.isEmpty ())
+                              url = tmpurl;
+                          }
+                      }
+                  }
+
+                if (! url.isEmpty ())
+                  {
+                    connect (this, SIGNAL (show_single_result (const QUrl)),
+                             m_doc_browser,
+                             SLOT (handle_index_clicked (const QUrl)));
+
+                    emit show_single_result (url);
+                  }
+              }
+           }
+
+        m_internal_search = QString ();
+      }
+
     qApp->restoreOverrideCursor();
   }
 
-  void documentation::notice_settings (const QSettings *) { }
+  void documentation::handle_search_result_clicked (const QUrl& url)
+  {
+    // Open url with matching text
+    m_doc_browser->handle_index_clicked (url);
+
+    // Select all occurrences of matching text
+    select_all_occurrences (m_query_string);
+
+    // Open search widget with matching text as search string
+    m_find_line_edit->setText (m_query_string);
+    m_find_line_edit->parentWidget ()->show ();
+
+    // Go to to first occurrence of search text. Going to the end and then
+    // search backwards until the last occurrence ensures the search text
+    // is visible in the first line of the visible part of the text.
+    m_doc_browser->moveCursor (QTextCursor::End);
+    while (m_doc_browser->find (m_find_line_edit->text (),
+                                QTextDocument::FindBackward));
+  }
+
+  void documentation::select_all_occurrences (const QString& text)
+  {
+    // Get highlight background and text color
+    QPalette pal = QApplication::palette ();
+    QTextCharFormat format;
+    QColor col = pal.color (QPalette::Highlight);
+    col.setAlphaF (0.25);
+    format.setBackground (QBrush (col));
+    format.setForeground (QBrush (pal.color (QPalette::Text)));
+
+    // Create list for extra selected items
+    QList<QTextEdit::ExtraSelection> selected;
+    m_doc_browser->moveCursor (QTextCursor::Start);
 
-  void documentation::copyClipboard (void) { }
+    // Find all occurrences and add them to the selection
+    while ( m_doc_browser->find (text) )
+      {
+        QTextEdit::ExtraSelection selected_item;
+        selected_item.cursor = m_doc_browser->textCursor ();
+        selected_item.format = format;
+        selected.append (selected_item);
+      }
+
+      // Apply selection and move back to the beginning
+      m_doc_browser->setExtraSelections (selected);
+      m_doc_browser->moveCursor (QTextCursor::Start);
+  }
+
+  void documentation::notice_settings (const QSettings *settings)
+  {
+    // Icon size in the toolbar.
+    int size_idx = settings->value (global_icon_size.key,
+                                    global_icon_size.def).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));
+
+    // Shortcuts
+    shortcut_manager::set_shortcut (m_action_find, "editor_edit:find_replace");
+    shortcut_manager::shortcut (m_findnext_shortcut, "editor_edit:find_next");
+    shortcut_manager::shortcut (m_findprev_shortcut, "editor_edit:find_previous");
+    shortcut_manager::set_shortcut (m_action_zoom_in, "editor_view:zoom_in");
+    shortcut_manager::set_shortcut (m_action_zoom_out, "editor_view:zoom_out");
+    shortcut_manager::set_shortcut (m_action_zoom_original, "editor_view:zoom_normal");
+    shortcut_manager::set_shortcut (m_action_go_home, "doc_browser:go_home");
+    shortcut_manager::set_shortcut (m_action_go_prev, "doc_browser:go_back");
+    shortcut_manager::set_shortcut (m_action_go_next, "doc_browser:go_next");
+  }
+
+  void documentation::copyClipboard (void)
+  {
+    if (m_doc_browser->hasFocus ())
+      {
+        m_doc_browser->copy();
+      }
+  }
 
   void documentation::pasteClipboard (void) { }
 
@@ -305,12 +564,66 @@
 
   void documentation::load_ref (const QString& ref_name)
   {
-    if (m_help_engine)
+    if (! m_help_engine)
+      return;
+
+    // First search in the function index
+    QMap<QString, QUrl> found_links
+      = m_help_engine->linksForIdentifier (ref_name);
+
+    QTabWidget *navi = static_cast<QTabWidget*> (widget (0));
+
+    if (found_links.count() > 0)
+      {
+        m_doc_browser->setSource (found_links.constBegin().value());
+
+        // Switch to function index tab
+        m_help_engine->indexWidget()->filterIndices (ref_name);
+        QWidget *index_tab
+          = navi->findChild<QWidget*> ("documentation_tab_index");
+        navi->setCurrentWidget (index_tab);
+      }
+    else
       {
-        QMap<QString, QUrl> found_links
-          = m_help_engine->linksForIdentifier (ref_name);
-        if (found_links.count() > 0)
-          m_doc_browser->setSource (found_links.constBegin().value());
+        // Use full text search to provide the best match
+        QHelpSearchEngine *search_engine = m_help_engine->searchEngine ();
+        QHelpSearchQueryWidget *search_query = search_engine->queryWidget ();
+
+#if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
+        QString query = ref_name;
+        query.prepend ("\"").append ("\"");
+#else
+        QList<QHelpSearchQuery> query;
+        query << QHelpSearchQuery (QHelpSearchQuery::DEFAULT,
+                                   QStringList (QString("\"") + ref_name + QString("\"")));
+#endif
+        m_internal_search = ref_name;
+        search_engine->search (query);
+
+        // Switch to search tab
+#if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
+        search_query->setSearchInput (query);
+#else
+        search_query->setQuery (query);
+#endif
+        QWidget *search_tab
+          = navi->findChild<QWidget*> ("documentation_tab_search");
+        navi->setCurrentWidget (search_tab);
+      }
+  }
+
+  void documentation::activate_find (void)
+  {
+    if (m_find_line_edit->parentWidget ()->isVisible ())
+      {
+        m_find_line_edit->parentWidget ()->hide ();
+        m_doc_browser->setFocus ();
+      }
+    else
+      {
+        m_find_line_edit->parentWidget ()->show ();
+        m_find_line_edit->selectAll ();
+        m_find_line_edit->setFocus ();
       }
   }
 
@@ -426,11 +739,103 @@
       }
   }
 
+  void documentation::update_history_menus (void)
+  {
+    if (m_prev_pages_count != m_doc_browser->backwardHistoryCount ())
+      {
+        update_history (m_doc_browser->backwardHistoryCount (),
+                        m_prev_pages_actions);
+        m_prev_pages_count = m_doc_browser->backwardHistoryCount ();
+      }
+
+    if (m_next_pages_count != m_doc_browser->forwardHistoryCount ())
+      {
+        update_history (m_doc_browser->forwardHistoryCount (),
+                        m_next_pages_actions);
+        m_next_pages_count = m_doc_browser->forwardHistoryCount ();
+      }
+  }
+
+  void documentation::update_history (int new_count, QAction **actions)
+  {
+    // Which menu has to be updated?
+    int prev_next = -1;
+    QAction *a = m_action_go_prev;
+    if (actions == m_next_pages_actions)
+      {
+        prev_next = 1;
+        a = m_action_go_next;
+      }
+
+    // Get maximal count limited by array size
+    int count = qMin (new_count, int (max_history_entries));
+
+    // 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 [^\\)]*\\)[: \\)]*"));
+
+        // Sinve 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 there 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;
+          }
+
+        if (i == 0)
+          a->setText (title); // set tool tip for prev/next buttons
+
+        actions[i]->setText (title);
+        actions[i]->setData (m_doc_browser->historyUrl (prev_next*(i+1)));
+        actions[i]->setEnabled (true);
+        actions[i]->setVisible (true);
+      }
+
+    // Hide unused menu entries
+    for (int j = count; j < max_history_entries; j++)
+      {
+        actions[j]->setEnabled (false);
+        actions[j]->setVisible (false);
+      }
+  }
+
+  void documentation::open_hist_url (QAction *a)
+  {
+    m_doc_browser->setSource (a->data ().toUrl ());
+  }
+
 
   // The documentation browser
   documentation_browser::documentation_browser (QHelpEngine *he, QWidget *p)
-    : QTextBrowser (p), m_help_engine (he)
-  { }
+    : QTextBrowser (p), m_help_engine (he), m_zoom_level (0)
+  {
+    setOpenLinks (false);
+    connect (this, SIGNAL (anchorClicked (QUrl)),
+             this, SLOT (handle_index_clicked (QUrl)));
+  }
 
   documentation_browser::~documentation_browser (void)
   { }
@@ -438,7 +843,10 @@
   void documentation_browser::handle_index_clicked (const QUrl& url,
                                                     const QString&)
   {
-    setSource (url);
+    if (url.scheme () == "qthelp")
+      setSource (url);
+    else
+      QDesktopServices::openUrl (url);
   }
 
   void documentation_browser::notice_settings (const QSettings *)
@@ -452,4 +860,43 @@
       return QTextBrowser::loadResource(type, url);
   }
 
+  void documentation_browser::zoom_in (void)
+  {
+    if (m_zoom_level < max_zoom_level)
+      {
+        zoomIn ();
+        m_zoom_level++;
+      }
+  }
+
+  void documentation_browser::zoom_out (void)
+  {
+    if (m_zoom_level > min_zoom_level)
+      {
+        zoomOut ();
+        m_zoom_level--;
+      }
+  }
+
+  void documentation_browser::zoom_original (void)
+  {
+    zoomIn (- m_zoom_level);
+    m_zoom_level = 0;
+  }
+
+  void documentation_browser::wheelEvent (QWheelEvent *we)
+  {
+    if (we->modifiers () == Qt::ControlModifier)
+      {
+        if (we->delta () > 0)
+          zoom_in ();
+        else
+          zoom_out ();
+
+        we->accept ();
+      }
+    else
+      QTextEdit::wheelEvent (we);
+  }
+
 }
--- a/libgui/src/documentation.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/documentation.h	Thu Dec 20 17:18:56 2018 -0500
@@ -24,15 +24,20 @@
 #define octave_documentation_h 1
 
 #include <QComboBox>
-#include <QWidget>
+#include <QMenu>
 #include <QSettings>
+#include <QShortcut>
 #include <QSplitter>
 #include <QTextBrowser>
+#include <QToolBar>
+#include <QToolButton>
+#include <QWidget>
 #include <QtHelp/QHelpEngine>
 
 namespace octave
 {
-  // The documentation browser
+  //! Documentation browser derived from Textbrowser
+
   class documentation_browser : public QTextBrowser
   {
     Q_OBJECT
@@ -50,14 +55,37 @@
                                const QString& keyword = QString ());
     void notice_settings (const QSettings *settings);
 
+    //! Zooming in and out while taking care of the zoom level
+    //!@{
+    void zoom_in (void);
+    void zoom_out (void);
+    void zoom_original (void);
+    //!@}
+
+  protected:
+
+     void wheelEvent (QWheelEvent *we);
+
   private:
 
     QHelpEngine *m_help_engine;
 
+    //! Store the current zoom level
+    int m_zoom_level;
+
+    //! Minimal and maximal zoom level avoiding calling
+    //! zoom_in and zoom_out without actually zooming but
+    //! with changing the stored zoom level
+    enum
+    {
+      min_zoom_level = -5,
+      max_zoom_level = 10
+    };
   };
 
 
-  // The documentaiton main class (splitter)
+  //! The documentaiton main class derived from QSplitter
+
   class documentation : public QSplitter
   {
     Q_OBJECT
@@ -81,6 +109,7 @@
 
   private slots:
 
+    void activate_find (void);
     void global_search (void);
     void global_search_started (void);
     void global_search_finished (int hits);
@@ -91,18 +120,58 @@
     void find_forward_from_anchor (const QString& text);
     void record_anchor_position (void);
     void handle_cursor_position_change (void);
+    void handle_search_result_clicked (const QUrl& url);
+
+    void update_history_menus (void);
+    void open_hist_url (QAction *a);
+
+  signals:
+
+    void show_single_result (const QUrl);
 
   private:
 
+    void construct_tool_bar (void);
+    QAction *add_action (const QIcon& icon, const QString& text,
+                         const char *member, QWidget *receiver = nullptr,
+                         QToolBar *tool_bar = nullptr);
+    void update_history (int new_count, QAction **actions);
+
+    //! Select all occurrences of a string in the doc browser
+    void select_all_occurrences (const QString& text);
+
     QHelpEngine *m_help_engine;
+    QString m_internal_search;
     documentation_browser *m_doc_browser;
     QLineEdit *m_find_line_edit;
     int m_search_anchor_position;
     QComboBox *m_filter;
     QString m_collection;
 
+    QWidget *m_doc_widget;
+    QToolBar *m_tool_bar;
+    QString m_query_string;
+
+    QAction *m_action_go_home;
+    QAction *m_action_go_prev;
+    QAction *m_action_go_next;
+    QMenu *m_prev_pages_menu;
+    QMenu *m_next_pages_menu;
+    int m_prev_pages_count;
+    int m_next_pages_count;
+
+    enum { max_history_entries = 10 };
+    QAction *m_prev_pages_actions[max_history_entries];
+    QAction *m_next_pages_actions[max_history_entries];
+
+    QAction *m_action_find;
+    QShortcut *m_findnext_shortcut;
+    QShortcut *m_findprev_shortcut;
+
+    QAction *m_action_zoom_in;
+    QAction *m_action_zoom_out;
+    QAction *m_action_zoom_original;
   };
-
 }
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/dw-main-window.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,252 @@
+/*
+
+Copyright (C) 2013-2018 Torsten <mttl@mailbox.org>
+
+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/>.
+
+*/
+
+/* This is the main window derived from QMainWindow for being used
+   as the main window in dock widgets like the variable editor or
+   the file editor
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QMenu>
+#include <QDockWidget>
+
+#include "resource-manager.h"
+#include "shortcut-manager.h"
+#include "dw-main-window.h"
+
+namespace octave
+{
+
+  dw_main_window::dw_main_window (QWidget *p)
+    : QMainWindow (p)
+  {
+    // Adding the actions for closing the dock widgets
+    m_close_action
+      = add_action (nullptr,
+                    resource_manager::icon ("window-close",false),
+                    tr ("&Close"),
+                    SLOT (request_close ()), this);
+
+    m_close_all_action
+      = add_action (nullptr,
+                    resource_manager::icon ("window-close",false),
+                    tr ("Close &All"),
+                    SLOT (request_close_all ()), this);
+
+    m_close_others_action
+      = add_action (nullptr,
+                    resource_manager::icon ("window-close",false),
+                    tr ("Close &Other"),
+                    SLOT (request_close_other ()), this);
+
+    m_switch_left_action
+      = add_action (nullptr, QIcon (), tr ("Switch to &Left Widget"),
+                    SLOT (request_switch_left ()), this);
+
+    m_switch_right_action
+      = add_action (nullptr, QIcon (), tr ("Switch to &Right Widget"),
+                    SLOT (request_switch_right ()), this);
+
+    // The list of actions for floating widgets
+    m_actions_list << m_close_action;
+    m_actions_list << m_close_others_action;
+    m_actions_list << m_close_all_action;
+    m_actions_list << m_switch_left_action;
+    m_actions_list << m_switch_right_action;
+
+    notice_settings (resource_manager::get_settings ());
+  }
+
+
+  // Re-implementing the popup menu of the main window
+  QMenu *dw_main_window::createPopupMenu ()
+  {
+    QList<QAction *> new_actions = QList<QAction *> ();
+    new_actions.append (m_close_action);
+    new_actions.append (m_close_others_action);
+    new_actions.append (m_close_all_action);
+
+    QMenu *menu = QMainWindow::createPopupMenu ();
+    QList<QAction *> actions = menu->actions();
+
+    if (actions.length () > 0)
+      {
+        QAction *sep = menu->insertSeparator (actions.at (0));
+        menu->insertActions (sep, new_actions);
+      }
+    else
+      menu->addActions (new_actions);
+
+    return menu;
+  }
+
+
+  // Adding an action to the main window
+  QAction * dw_main_window::add_action (QMenu *menu, const QIcon& icon,
+                                        const QString& text, const char *member,
+                                        QWidget *receiver)
+  {
+    QAction *a;
+    QWidget *r = this;
+
+    if (receiver != nullptr)
+      r = receiver;
+
+    if (menu)
+      a = menu->addAction (icon, text, r, member);
+    else
+      {
+        a = new QAction (icon, text, this);
+        a->setEnabled (true);
+        connect (a, SIGNAL (triggered ()), r, member);
+      }
+
+    addAction (a);  // important for shortcut context
+    a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
+
+    return a;
+  }
+
+  // Update the settings
+  void dw_main_window::notice_settings (const QSettings*)
+  {
+    shortcut_manager::set_shortcut (m_close_action, "editor_file:close");
+    shortcut_manager::set_shortcut (m_close_all_action, "editor_file:close_all");
+    shortcut_manager::set_shortcut (m_close_others_action, "editor_file:close_other");
+
+    shortcut_manager::set_shortcut (m_switch_left_action, "editor_tabs:switch_left_tab");
+    shortcut_manager::set_shortcut (m_switch_right_action, "editor_tabs:switch_right_tab");
+  }
+
+
+  // Slots for handling actions
+
+  // Close current widget
+  void dw_main_window::request_close ()
+  {
+    for (int i = 0; i < m_dw_list.length (); i++)
+      {
+        if (m_dw_list.at (i)->hasFocus ())
+          {
+            m_dw_list.at (i)->close ();
+            if (i > 0)
+              m_dw_list.at (i-1)->setFocus ();
+            break;
+          }
+      }
+  }
+
+  // Close other widgets
+  void dw_main_window::request_close_other ()
+  {
+    for (int i = m_dw_list.length () - 1; i >= 0; i--)
+      {
+        if (! m_dw_list.at (i)->hasFocus ())
+          m_dw_list.at (i)->close ();
+      }
+  }
+
+  // Close all widgets
+  void dw_main_window::request_close_all ()
+  {
+    for (int i = m_dw_list.length () - 1; i >= 0; i--)
+      m_dw_list.at (i)->close ();
+  }
+
+  // Switch to left widget
+  void dw_main_window::request_switch_left ()
+  {
+    request_switch (-1);
+  }
+
+  // Switch to right widget
+  void dw_main_window::request_switch_right ()
+  {
+    request_switch (1);
+  }
+
+  // Switch to left/right widget
+  void dw_main_window::request_switch (int direction)
+  {
+    int active = -1, next;
+
+    for (int i = m_dw_list.length () - 1; i >= 0; i--)
+      {
+        if (m_dw_list.at (i)->hasFocus ())
+          {
+            active = i;
+            break;
+          }
+      }
+
+    if (active == -1)
+      return;
+
+    if (direction == -1 && active == 0)
+      next = m_dw_list.length () - 1;
+    else if (direction == 1 && active == m_dw_list.length () - 1)
+      next = 0;
+    else
+      next = active + direction;
+
+    m_dw_list.at (next)->raise ();
+    m_dw_list.at (next)->activateWindow ();
+    m_dw_list.at (next)->setFocus ();
+  }
+
+
+  // Reimplemented Event
+  bool dw_main_window::event (QEvent *ev)
+  {
+    if (ev->type () == QEvent::ChildAdded ||
+        ev->type () == QEvent::ChildRemoved)
+      {
+        // Adding or Removing a child indicates that a dock widget was
+        // created or removed.
+        // In all cases, the list of dock widgets has to be updated.
+        m_dw_list = findChildren<QDockWidget *>();
+      }
+
+    if (ev->type () == QEvent::StyleChange)
+      {
+        // This might indicate un- or re-docking a widget: Make sure
+        // floating widget get a copy of our actions
+        for (int i = m_dw_list.length () - 1; i >= 0; i--)
+          {
+            // First remove possibly existing actions
+            for (int j = m_actions_list.length () - 1; j >0; j--)
+              m_dw_list.at (i)->removeAction (m_actions_list.at (j));
+
+            // Then add our actions for floating widgets
+            if (m_dw_list.at (i)->isFloating ())
+              m_dw_list.at (i)->addActions (m_actions_list);
+          }
+      }
+
+    return QMainWindow::event (ev);
+  }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/dw-main-window.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,89 @@
+/*
+
+Copyright (C) 2013-2018 Torsten <mttl@mailbox.org>
+
+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 (dw_main_window_h)
+#define dw_main_window_h 1
+
+#include <QMainWindow>
+#include <QSettings>
+
+
+namespace octave
+{
+
+  class dw_main_window : public QMainWindow
+  {
+    Q_OBJECT
+
+  public:
+
+    dw_main_window (QWidget *parent = nullptr);
+
+    ~dw_main_window (void) = default;
+
+    // No copying!
+
+    dw_main_window (const dw_main_window&) = delete;
+
+    dw_main_window& operator = (const dw_main_window&) = delete;
+
+  public slots:
+
+    void notice_settings (const QSettings*);
+
+  protected slots:
+
+    virtual QMenu* createPopupMenu ();
+
+    virtual bool event (QEvent *ev);
+
+  private slots:
+
+    void request_close ();
+    void request_close_all ();
+    void request_close_other ();
+
+    void request_switch_left ();
+    void request_switch_right ();
+
+  private:
+
+    void request_switch (int direction);
+
+    QList<QDockWidget *> m_dw_list;
+
+    QAction *add_action (QMenu *menu, const QIcon& icon, const QString& text,
+                         const char *member, QWidget *receiver);
+
+    QAction *m_close_action;
+    QAction *m_close_all_action;
+    QAction *m_close_others_action;
+
+    QAction *m_switch_left_action;
+    QAction *m_switch_right_action;
+
+    QList<QAction *> m_actions_list;
+  };
+
+}
+
+#endif
--- a/libgui/src/files-dock-widget.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/files-dock-widget.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,6 +25,7 @@
 #  include "config.h"
 #endif
 
+#include "gui-preferences.h"
 #include "resource-manager.h"
 #include "files-dock-widget.h"
 
@@ -66,9 +67,8 @@
   };
 
   files_dock_widget::files_dock_widget (QWidget *p)
-    : octave_dock_widget (p)
+    : octave_dock_widget ("FilesDockWidget", p)
   {
-    setObjectName ("FilesDockWidget");
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
     set_title (tr ("File Browser"));
     setToolTip (tr ("Browse your files"));
@@ -83,11 +83,18 @@
     m_columns_shown.append (tr ("Alternating row colors"));
 
     m_columns_shown_keys = QStringList ();
-    m_columns_shown_keys.append ("filesdockwidget/showFileSize");
-    m_columns_shown_keys.append ("filesdockwidget/showFileType");
-    m_columns_shown_keys.append ("filesdockwidget/showLastModified");
-    m_columns_shown_keys.append ("filesdockwidget/showHiddenFiles");
-    m_columns_shown_keys.append ("filesdockwidget/useAlternatingRowColors");
+    m_columns_shown_keys.append (fb_show_size.key);
+    m_columns_shown_keys.append (fb_show_type.key);
+    m_columns_shown_keys.append (fb_show_date.key);
+    m_columns_shown_keys.append (fb_show_hidden.key);
+    m_columns_shown_keys.append (fb_show_altcol.key);
+
+    m_columns_shown_defs = QList <QVariant> ();
+    m_columns_shown_defs.append (fb_show_size.def);
+    m_columns_shown_defs.append (fb_show_type.def);
+    m_columns_shown_defs.append (fb_show_date.def);
+    m_columns_shown_defs.append (fb_show_hidden.def);
+    m_columns_shown_defs.append (fb_show_altcol.def);
 
     QWidget *container = new QWidget (this);
 
@@ -180,19 +187,21 @@
     // Create the QFileSystemModel starting in the desired directory
     QDir startup_dir;  // take current dir
 
-    if (settings->value ("filesdockwidget/restore_last_dir",false).toBool ())
+    if (settings->value (fb_restore_last_dir.key,
+                         fb_restore_last_dir.def).toBool ())
       {
         // restore last dir from previous session
         QStringList last_dirs
-          = settings->value ("filesdockwidget/mru_dir_list").toStringList ();
+          = settings->value (fb_mru_list.key).toStringList ();
         if (last_dirs.length () > 0)
           startup_dir = QDir (last_dirs.at (0));  // last dir in previous session
       }
-    else if (! settings->value ("filesdockwidget/startup_dir").toString ().isEmpty ())
+    else if (! settings->value (fb_startup_dir.key, fb_startup_dir.def)
+               .toString ().isEmpty ())
       {
         // do not restore but there is a startup dir configured
         startup_dir
-          = QDir (settings->value ("filesdockwidget/startup_dir").toString ());
+          = QDir (settings->value (fb_startup_dir.key).toString ());
       }
 
     if (! startup_dir.exists ())
@@ -213,22 +222,34 @@
     m_file_tree_view->setSortingEnabled (true);
     m_file_tree_view->setAlternatingRowColors (true);
     m_file_tree_view->setAnimated (true);
-    m_file_tree_view->setToolTip (
-                                  tr ("Activate to open in editor, right click for alternatives"));
+    m_file_tree_view->setToolTip (tr ("Double click to open file/folder, right click for alternatives"));
 
     // get sort column and order as well as cloumn state (order and width)
 
     m_file_tree_view->sortByColumn (
-                                    settings->value ("filesdockwidget/sort_files_by_column",0).toInt (),
-                                    static_cast<Qt::SortOrder>
-                                    (settings->value ("filesdockwidget/sort_files_by_order",
-                                                      Qt::AscendingOrder).toUInt ())
-                                    );
-    m_file_tree_view->header ()->restoreState (
-                                               settings->value ("filesdockwidget/column_state").toByteArray ());
+          settings->value (fb_sort_column.key, fb_sort_column.def).toInt (),
+          static_cast<Qt::SortOrder> (
+            settings->value (fb_sort_order.key, fb_sort_order.def).toUInt ()));
+
+    if (settings->contains (fb_column_state.key))
+      m_file_tree_view->header ()->restoreState (
+                          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 =
-      settings->value ("filesdockwidget/mru_dir_list").toStringList ();
+      settings->value (fb_mru_list.key).toStringList ();
     m_current_directory->addItems (mru_dirs);
 
     m_current_directory->setEditText (
@@ -287,17 +308,16 @@
 
     int sort_column = m_file_tree_view->header ()->sortIndicatorSection ();
     Qt::SortOrder sort_order = m_file_tree_view->header ()->sortIndicatorOrder ();
-    settings->setValue ("filesdockwidget/sort_files_by_column", sort_column);
-    settings->setValue ("filesdockwidget/sort_files_by_order", sort_order);
-    settings->setValue ("filesdockwidget/column_state",
-                        m_file_tree_view->header ()->saveState ());
+    settings->setValue (fb_sort_column.key, sort_column);
+    settings->setValue (fb_sort_order.key, sort_order);
+    settings->setValue (fb_column_state.key, m_file_tree_view->header ()->saveState ());
 
     QStringList dirs;
     for (int i=0; i< m_current_directory->count (); i++)
       {
         dirs.append (m_current_directory->itemText (i));
       }
-    settings->setValue ("filesdockwidget/mru_dir_list", dirs);
+    settings->setValue (fb_mru_list.key, dirs);
 
     settings->sync ();
 
@@ -383,19 +403,16 @@
 
             QString suffix = fileInfo.suffix ().toLower ();
             QSettings *settings = resource_manager::get_settings ();
-            QString ext = settings->value ("filesdockwidget/txt_file_extensions",
-                                           "m;c;cc;cpp;h;txt").toString ();
+            QString ext = settings->value (fb_txt_file_ext.key,
+                                           fb_txt_file_ext.def).toString ();
             QStringList extensions = ext.split (";", QString::SkipEmptyParts);
 
             if (QFile::exists (abs_fname))
               {
-                if (is_octave_data_file (abs_fname.toStdString ()))
-                  emit load_file_signal (abs_fname);
-                else if (extensions.contains (suffix))
+                if (extensions.contains (suffix))
                   emit open_file (fileInfo.absoluteFilePath ());
                 else
-                  open_item_in_app (m_file_tree_view->selectionModel ()
-                                    ->currentIndex ());
+                  emit open_any_signal (abs_fname);
               }
           }
       }
@@ -452,8 +469,8 @@
                                           m_sig_mapper, SLOT (map ()));
         m_sig_mapper->setMapping (action, i);
         action->setCheckable (true);
-        action->setChecked (
-                            settings->value (m_columns_shown_keys.at (i),true).toBool ());
+        action->setChecked (settings->value (
+          m_columns_shown_keys.at (i), m_columns_shown_defs.at (i)).toBool ());
       }
 
     connect (m_sig_mapper, SIGNAL (mapped (int)),
@@ -550,7 +567,7 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QFileInfo file = m_file_system_model->fileInfo (*it);
         if (file.exists ())
@@ -564,7 +581,7 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QFileInfo file = m_file_system_model->fileInfo (*it);
         if (file.exists ())
@@ -577,7 +594,7 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       open_item_in_app (*it);
   }
 
@@ -588,7 +605,7 @@
 
     QStringList selection;
 
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QFileInfo info = m_file_system_model->fileInfo (*it);
 
@@ -669,7 +686,7 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QModelIndex index = *it;
 
@@ -783,15 +800,12 @@
   {
     // Qsettings pointer is checked before emitting.
 
-    int icon_size_settings = settings->value ("toolbar_icon_size",0).toInt ();
-    QStyle *st = style ();
-    int icon_size = st->pixelMetric (QStyle::PM_ToolBarIconSize);
+    int size_idx = settings->value (global_icon_size.key,
+                                    global_icon_size.def).toInt ();
+    size_idx = (size_idx > 0) - (size_idx < 0) + 1;  // Make valid index from 0 to 2
 
-    if (icon_size_settings == 1)
-      icon_size = st->pixelMetric (QStyle::PM_LargeIconSize);
-    else if (icon_size_settings == -1)
-      icon_size = st->pixelMetric (QStyle::PM_SmallIconSize);
-
+    QStyle *st = style ();
+    int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
     m_navigation_tool_bar->setIconSize (QSize (icon_size,icon_size));
 
     // filenames are always shown, other columns can be hidden by settings
@@ -812,19 +826,23 @@
     // enable the buttons to sync octave/browser dir
     // only if this is not done by default
     m_sync_octave_dir
-      = settings->value ("filesdockwidget/sync_octave_directory",true).toBool ();
+      = settings->value (fb_sync_octdir.key, fb_sync_octdir.def).toBool ();
     m_sync_octave_directory_action->setEnabled (! m_sync_octave_dir);
     m_sync_browser_directory_action->setEnabled (! m_sync_octave_dir);
 
+    // If m_sync_octave_dir is enabled, then we want the file browser to
+    // update to match the current working directory of the
+    // interpreter.  We don't want to queue any signal to change the
+    // interpreter's current working directory.  In this case, we just
+    // want the GUI to match the state of the interpreter.
+
     if (m_sync_octave_dir)
-      display_directory (m_octave_dir);  // sync browser to octave dir
-
+      do_sync_browser_directory ();
   }
 
   void files_dock_widget::popdownmenu_home (bool)
   {
-    QString dir
-      = QString::fromStdString (octave::sys::env::get_home_directory ());
+    QString dir = QString::fromStdString (sys::env::get_home_directory ());
 
     if (dir.isEmpty ())
       dir = QDir::homePath ();
@@ -834,11 +852,16 @@
 
   void files_dock_widget::popdownmenu_search_dir (bool)
   {
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = QFileDialog::ShowDirsOnly;
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts |= QFileDialog::DontUseNativeDialog;
+
     QString dir = QFileDialog::getExistingDirectory (this,
                      tr ("Set directory of file browser"),
                      m_file_system_model->rootPath (),
-                     QFileDialog::ShowDirsOnly
-                     | QFileDialog::DontUseNativeDialog);
+                     QFileDialog::Option (opts));
     set_current_directory (dir);
   }
 
--- a/libgui/src/files-dock-widget.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/files-dock-widget.h	Thu Dec 20 17:18:56 2018 -0500
@@ -141,10 +141,14 @@
 
     void displayed_directory_changed (const QString& dir);
 
-    //! Emitted, whenever the user requested to load a file.
+    //! Emitted, whenever the user requested to load a file in the text editor.
 
     void load_file_signal (const QString& fileName);
 
+    //! Emitted, whenever the user requested to open an unknown type file.
+
+    void open_any_signal (const QString& fileName);
+
     //! Emitted, whenever the user requested to run a file.
 
     void run_file_signal (const QFileInfo& info);
@@ -202,6 +206,7 @@
 
     QStringList m_columns_shown;
     QStringList m_columns_shown_keys;
+    QList <QVariant> m_columns_shown_defs;
     QSignalMapper *m_sig_mapper;
   };
 }
--- a/libgui/src/find-files-dialog.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/find-files-dialog.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -313,9 +313,16 @@
 
   void find_files_dialog::browse_folders (void)
   {
+    int opts = 0;  // No options by default.
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts = QFileDialog::DontUseNativeDialog;
+
     QString dir =
       QFileDialog::getExistingDirectory (this, tr ("Set search directory"),
-                                         m_start_dir_edit->text ());
+                                         m_start_dir_edit->text (),
+                                         QFileDialog::Option (opts));
 
     if (! dir.isEmpty ())
       m_start_dir_edit->setText (dir);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/gui-preferences.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,133 @@
+/*
+
+Copyright (C) 2017-2018 Torsten <mttl@mailbox.de>
+
+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_editor_settings_h)
+#define octave_editor_settings_h 1
+
+//#if defined (HAVE_CONFIG_H)
+//#  include "config.h"
+//#endif
+
+#include <QStringList>
+#include <QVariant>
+#include <QStyle>
+
+// Structure for the definition of pairs: key and default value
+
+struct gui_pref
+{
+  gui_pref (const QString& key_, QVariant def_): key (key_), def (def_) {}
+  QString   key;  // the key name
+  QVariant  def;  // the default value
+};
+
+
+// Global preferences
+
+// Get the default monospaced font
+#if defined (Q_WS_X11)
+const QString global_font_family = "Monospace";
+#elif defined (Q_WS_WIN) || defined (Q_WS_MAC)
+const QString global_font_family = "Courier";
+#else
+const QString global_font_family = "Courier";
+#endif
+const gui_pref global_mono_font ("monospace_font", global_font_family);
+
+// Icon size (in preferences: values -1, 0, 1)
+const QStyle::PixelMetric global_icon_sizes[3] =
+{
+  QStyle::PM_SmallIconSize,
+  QStyle::PM_ToolBarIconSize,
+  QStyle::PM_LargeIconSize
+};
+const gui_pref global_icon_size ("toolbar_icon_size", QVariant (0));
+const gui_pref global_icon_theme ("use_system_icon_theme", QVariant (true));
+
+// Style
+const gui_pref global_style ("style", QVariant ("default"));
+
+// Console preferences
+
+const gui_pref cs_font ("terminal/fontName", QVariant ());
+
+
+// Variable Editor preferences
+
+const gui_pref ve_font ("variable_editor/font_size", QVariant ());
+
+
+// Editor preferences
+
+// Octave comment strings
+const gui_pref ed_comment_str_old ("editor/octave_comment_string", QVariant (0));
+const gui_pref ed_comment_str ("editor/oct_comment_str", QVariant (0));
+const gui_pref ed_uncomment_str ("editor/oct_uncomment_str", QVariant (1 + 2 + 4 + 8));
+const QString ed_last_comment_str ("editor/oct_last_comment_str");
+const QStringList ed_comment_strings (QStringList () << "##" << "#" << "%"<< "%%" << "%!");
+const int ed_comment_strings_count = 5;
+
+
+// Session data
+const gui_pref ed_session_names ("editor/savedSessionTabs",
+                                  QVariant (QStringList ()));
+const gui_pref ed_session_enc ("editor/saved_session_encodings",
+                                  QVariant (QStringList ()));
+const gui_pref ed_session_ind ("editor/saved_session_tab_index",
+                                  QVariant (QStringList ()));
+const gui_pref ed_session_lines ("editor/saved_session_lines",
+                                  QVariant (QStringList ()));
+
+
+// File handling
+const gui_pref ed_show_dbg_file ("editor/show_dbg_file", QVariant (true));
+#if defined (Q_OS_WIN32)
+const gui_pref ed_default_enc ("editor/default_encoding", QVariant ("SYSTEM"));
+#else
+const gui_pref ed_default_enc ("editor/default_encoding", QVariant ("UTF-8"));
+#endif
+
+
+// Files dock widget
+
+const gui_pref fb_column_state ("filesdockwidget/column_state", QVariant ());
+const gui_pref fb_show_ ("filesdockwidget/column_state", QVariant ());
+const gui_pref fb_mru_list ("filesdockwidget/mru_dir_list", QVariant (QStringList ()));
+const gui_pref fb_show_size ("filesdockwidget/showFileSize", QVariant (false));
+const gui_pref fb_show_type ("filesdockwidget/showFileType", QVariant (false));
+const gui_pref fb_show_date ("filesdockwidget/showLastModified", QVariant (false));
+const gui_pref fb_show_hidden ("filesdockwidget/showHiddenFiles", QVariant (false));
+const gui_pref fb_show_altcol ("filesdockwidget/useAlternatingRowColors", QVariant (true));
+const gui_pref fb_sort_column ("filesdockwidget/sort_files_by_column", QVariant (0));
+const gui_pref fb_sort_order ("filesdockwidget/sort_files_by_order", QVariant (Qt::AscendingOrder));
+const gui_pref fb_sync_octdir ("filesdockwidget/sync_octave_directory", QVariant (true));
+const gui_pref fb_restore_last_dir ("filesdockwidget/restore_last_dir", QVariant (false));
+const gui_pref fb_startup_dir ("filesdockwidget/startup_dir", QVariant (QString ()));
+const gui_pref fb_txt_file_ext ("filesdockwidget/txt_file_extensions",
+                                QVariant ("m;c;cc;cpp;h;txt"));
+
+// Workspace view
+
+const gui_pref ws_enable_colors ("workspaceview/enable_colors", QVariant (false));
+const gui_pref ws_hide_tool_tips ("workspaceview/hide_tools_tips", QVariant (false));
+
+#endif
--- a/libgui/src/history-dock-widget.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/history-dock-widget.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -42,9 +42,8 @@
 namespace octave
 {
   history_dock_widget::history_dock_widget (QWidget *p)
-    : octave_dock_widget (p)
+    : octave_dock_widget ("HistoryDockWidget", p)
   {
-    setObjectName ("HistoryDockWidget");
     setStatusTip (tr ("Browse and search the command history."));
 
     connect (this, SIGNAL (command_create_script (const QString&)),
@@ -166,9 +165,8 @@
     QString text;
     QItemSelectionModel *selectionModel = m_history_list_view->selectionModel ();
     QModelIndexList rows = selectionModel->selectedRows ();
-    QModelIndexList::iterator it;
     bool prev_valid_row = false;
-    for (it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         if ((*it).isValid ())
           {
@@ -185,8 +183,7 @@
   {
     QItemSelectionModel *selectionModel = m_history_list_view->selectionModel ();
     QModelIndexList rows = selectionModel->selectedRows ();
-    QModelIndexList::iterator it;
-    for (it = rows.begin () ; it != rows.end (); it++)
+    for (auto it = rows.begin () ; it != rows.end (); it++)
       {
         if ((*it).isValid ())
           emit command_double_clicked ((*it).data ().toString ());
@@ -200,7 +197,7 @@
     QModelIndexList rows = selectionModel->selectedRows ();
 
     bool prev_valid_row = false;
-    for (QModelIndexList::iterator it = rows.begin (); it != rows.end (); it++)
+    for (auto it = rows.begin (); it != rows.end (); it++)
       {
         if ((*it).isValid ())
           {
@@ -273,7 +270,7 @@
     m_history_list_view->setAlternatingRowColors (true);
     m_history_list_view->setEditTriggers (QAbstractItemView::NoEditTriggers);
     m_history_list_view->setStatusTip (
-      tr ("Double-click a command to transfer it to the terminal."));
+      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,
@@ -336,7 +333,7 @@
     connect (m_filter_checkbox, SIGNAL (toggled (bool)),
              this, SLOT (filter_activate (bool)));
     connect (m_filter->lineEdit (), SIGNAL (editingFinished (void)),
-             this, SLOT (updatem_filter_history (void)));
+             this, SLOT (update_filter_history (void)));
 
     connect (m_history_list_view, SIGNAL (doubleClicked (QModelIndex)),
              this, SLOT (handle_double_click (QModelIndex)));
Binary file libgui/src/icons/dialog-error.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/dialog-error.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,330 @@
+<?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"
+   width="48px"
+   height="48px"
+   id="svg1306"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/garrett/Source/tango-icon-theme/scalable/status"
+   sodipodi:docname="dialog-error.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs1308">
+    <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="perspective40" />
+    <linearGradient
+       id="linearGradient3957">
+      <stop
+         style="stop-color:#fffeff;stop-opacity:0.33333334;"
+         offset="0"
+         id="stop3959" />
+      <stop
+         style="stop-color:#fffeff;stop-opacity:0.21568628;"
+         offset="1"
+         id="stop3961" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2536">
+      <stop
+         style="stop-color:#a40000;stop-opacity:1;"
+         offset="0"
+         id="stop2538" />
+      <stop
+         style="stop-color:#ff1717;stop-opacity:1;"
+         offset="1"
+         id="stop2540" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2479">
+      <stop
+         style="stop-color:#ffe69b;stop-opacity:1;"
+         offset="0"
+         id="stop2481" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop2483" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4126"
+       inkscape:collect="always">
+      <stop
+         id="stop4128"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop4130"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4126"
+       id="radialGradient2169"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.500000,1.899196e-14,20.00000)"
+       cx="23.857143"
+       cy="40.000000"
+       fx="23.857143"
+       fy="40.000000"
+       r="17.142857" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2479"
+       id="linearGradient2485"
+       x1="43.93581"
+       y1="53.835983"
+       x2="20.064686"
+       y2="-8.5626707"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2536"
+       id="linearGradient2542"
+       x1="36.917976"
+       y1="66.288063"
+       x2="19.071495"
+       y2="5.5410109"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2536"
+       id="linearGradient3046"
+       gradientUnits="userSpaceOnUse"
+       x1="36.917976"
+       y1="66.288063"
+       x2="19.071495"
+       y2="5.5410109" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2479"
+       id="linearGradient3048"
+       gradientUnits="userSpaceOnUse"
+       x1="43.93581"
+       y1="53.835983"
+       x2="20.064686"
+       y2="-8.5626707" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2536"
+       id="linearGradient3064"
+       gradientUnits="userSpaceOnUse"
+       x1="36.917976"
+       y1="66.288063"
+       x2="19.071495"
+       y2="5.5410109" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2479"
+       id="linearGradient3066"
+       gradientUnits="userSpaceOnUse"
+       x1="43.93581"
+       y1="53.835983"
+       x2="20.064686"
+       y2="-8.5626707" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3957"
+       id="linearGradient3963"
+       x1="21.993773"
+       y1="33.955299"
+       x2="20.917078"
+       y2="15.814602"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4126"
+       id="radialGradient3976"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.5,1.893048e-14,20)"
+       cx="23.857143"
+       cy="40.000000"
+       fx="23.857143"
+       fy="40.000000"
+       r="17.142857" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2536"
+       id="linearGradient3978"
+       gradientUnits="userSpaceOnUse"
+       x1="36.917976"
+       y1="66.288063"
+       x2="19.071495"
+       y2="5.5410109" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2479"
+       id="linearGradient3980"
+       gradientUnits="userSpaceOnUse"
+       x1="43.93581"
+       y1="53.835983"
+       x2="20.064686"
+       y2="-8.5626707" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3957"
+       id="linearGradient3982"
+       gradientUnits="userSpaceOnUse"
+       x1="21.993773"
+       y1="33.955299"
+       x2="20.917078"
+       y2="15.814602" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="0.21568627"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="-134.9567"
+     inkscape:cy="20.463852"
+     inkscape:current-layer="layer2"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="925"
+     inkscape:window-height="818"
+     inkscape:window-x="234"
+     inkscape:window-y="30"
+     inkscape:showpageshadow="false"
+     fill="#ef2929">
+    <inkscape:grid
+       id="GridFromPre046Settings"
+       type="xygrid"
+       originx="0px"
+       originy="0px"
+       spacingx="1px"
+       spacingy="1px"
+       color="#0000ff"
+       empcolor="#0000ff"
+       opacity="0.2"
+       empopacity="0.4"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata1311">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Rodney Dawes</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Jakub Steiner, Garrett LeSage</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:title>Dialog Error</dc:title>
+      </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="layer2"
+     inkscape:label="Shadow">
+    <path
+       inkscape:r_cy="true"
+       inkscape:r_cx="true"
+       transform="matrix(1.070555,0,0,0.525,-0.892755,22.5)"
+       d="M 41 40 A 17.142857 8.5714283 0 1 1  6.7142868,40 A 17.142857 8.5714283 0 1 1  41 40 z"
+       sodipodi:ry="8.5714283"
+       sodipodi:rx="17.142857"
+       sodipodi:cy="40"
+       sodipodi:cx="23.857143"
+       id="path6548"
+       style="opacity:0.6;color:#000000;fill:url(#radialGradient3976);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       sodipodi:type="arc" />
+  </g>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       id="g4006">
+      <path
+         transform="matrix(0.920488,0,0,0.920488,2.368532,0.97408)"
+         d="M 46.857143 23.928572 A 23.357143 23.357143 0 1 1  0.1428566,23.928572 A 23.357143 23.357143 0 1 1  46.857143 23.928572 z"
+         sodipodi:ry="23.357143"
+         sodipodi:rx="23.357143"
+         sodipodi:cy="23.928572"
+         sodipodi:cx="23.5"
+         id="path1314"
+         style="fill:url(#linearGradient3978);fill-opacity:1;fill-rule:nonzero;stroke:#b20000;stroke-width:1.08638;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         sodipodi:type="arc"
+         inkscape:r_cx="true"
+         inkscape:r_cy="true" />
+      <path
+         transform="matrix(0.856093,0,0,0.856093,1.818275,0.197769)"
+         d="M 49.901535 26.635273 A 23.991123 23.991123 0 1 1  1.9192886,26.635273 A 23.991123 23.991123 0 1 1  49.901535 26.635273 z"
+         sodipodi:ry="23.991123"
+         sodipodi:rx="23.991123"
+         sodipodi:cy="26.635273"
+         sodipodi:cx="25.910412"
+         id="path3560"
+         style="opacity:0.34659089;fill:#cc0000;fill-opacity:0;stroke:url(#linearGradient3980);stroke-width:1.16809607;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         sodipodi:type="arc"
+         inkscape:r_cx="true"
+         inkscape:r_cy="true" />
+    </g>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="Error Box">
+    <rect
+       inkscape:r_cy="true"
+       inkscape:r_cx="true"
+       style="fill:#efefef;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.73876643;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.8627451"
+       id="rect2070"
+       width="27.836435"
+       height="7.1735945"
+       x="10.078821"
+       y="19.164932"
+       transform="matrix(1.005876,0,0,1.115201,-0.138045,-2.372708)" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="Glossy Shine">
+    <path
+       transform="matrix(1.002994,0,0,1.002994,-7.185874e-2,1.968356e-2)"
+       sodipodi:nodetypes="czssc"
+       id="path3955"
+       d="M 43.370686,21.715486 C 43.370686,32.546102 33.016357,15.449178 24.695948,22.101874 C 16.569626,28.599385 4.0989837,34.292422 4.0989837,23.461806 C 4.0989837,12.377753 12.79438,2.0948032 23.625,2.0948032 C 34.455619,2.0948032 43.370686,10.884868 43.370686,21.715486 z "
+       style="fill:url(#linearGradient3982);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+       inkscape:r_cx="true"
+       inkscape:r_cy="true" />
+  </g>
+</svg>
Binary file libgui/src/icons/dialog-information.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/dialog-information.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,1159 @@
+<?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"
+   sodipodi:docname="dialog-information.svg"
+   sodipodi:docbase="/home/garrett/Source/tango-icon-theme/scalable/status"
+   inkscape:version="0.46"
+   sodipodi:version="0.32"
+   id="svg19655"
+   height="48px"
+   width="48px"
+   inkscape:export-filename="/home/jimmac/Desktop/poing.png"
+   inkscape:export-xdpi="392.72742"
+   inkscape:export-ydpi="392.72742"
+   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="perspective155" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3300">
+      <stop
+         style="stop-color:#4c4c28;stop-opacity:1;"
+         offset="0"
+         id="stop3302" />
+      <stop
+         style="stop-color:#4c4c28;stop-opacity:0;"
+         offset="1"
+         id="stop3304" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3311">
+      <stop
+         id="stop3313"
+         offset="0"
+         style="stop-color:#d6d7a5;stop-opacity:1;" />
+      <stop
+         id="stop3315"
+         offset="1.0000000"
+         style="stop-color:#8e8f6d;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3265">
+      <stop
+         id="stop3267"
+         offset="0"
+         style="stop-color:#929470;stop-opacity:1;" />
+      <stop
+         style="stop-color:#60614a;stop-opacity:1.0000000;"
+         offset="0.26470590"
+         id="stop3269" />
+      <stop
+         id="stop3271"
+         offset="0.63235295"
+         style="stop-color:#f3f5ba;stop-opacity:1.0000000;" />
+      <stop
+         id="stop3273"
+         offset="1.0000000"
+         style="stop-color:#929470;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3175"
+       inkscape:collect="always">
+      <stop
+         id="stop3177"
+         offset="0"
+         style="stop-color:#f1f3ff;stop-opacity:1;" />
+      <stop
+         id="stop3179"
+         offset="1"
+         style="stop-color:#f1f3ff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2399">
+      <stop
+         style="stop-color:#929470;stop-opacity:1;"
+         offset="0"
+         id="stop2401" />
+      <stop
+         id="stop2407"
+         offset="0.26470590"
+         style="stop-color:#fcffc1;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#f3f5ba;stop-opacity:1.0000000;"
+         offset="0.63235295"
+         id="stop2409" />
+      <stop
+         style="stop-color:#929470;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2403" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient6339">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop6341" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop6343" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient20428">
+      <stop
+         id="stop20430"
+         offset="0.0000000"
+         style="stop-color:#a3a3a3;stop-opacity:1.0000000;" />
+      <stop
+         id="stop20432"
+         offset="1"
+         style="stop-color:#b5b5b5;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient20393">
+      <stop
+         id="stop20395"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.44117647;"
+         offset="0.41176471"
+         id="stop2427" />
+      <stop
+         id="stop20397"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:0.48039216;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient20210">
+      <stop
+         id="stop20212"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:0.51546389;" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0.14432989;"
+         offset="0.55172414"
+         id="stop20218" />
+      <stop
+         id="stop20214"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       fy="11.4873"
+       fx="17.8335"
+       r="22.7093"
+       cy="11.4873"
+       cx="17.8335"
+       id="aigrd7">
+      <stop
+         id="stop19512"
+         style="stop-color:#ffffff;stop-opacity:0.17525773;"
+         offset="0.0000000" />
+      <stop
+         id="stop19514"
+         style="stop-color:#709ac8;stop-opacity:1.0000000;"
+         offset="0.88200003" />
+      <stop
+         id="stop19516"
+         style="stop-color:#6f96dd;stop-opacity:1.0000000;"
+         offset="1.0000000" />
+    </radialGradient>
+    <linearGradient
+       y2="43.165"
+       x2="26.4785"
+       y1="43.165"
+       x1="23.124"
+       gradientUnits="userSpaceOnUse"
+       id="aigrd1">
+      <stop
+         id="stop19415"
+         style="stop-color:#686868"
+         offset="5.618000e-003" />
+      <stop
+         id="stop19417"
+         style="stop-color:#777777"
+         offset="3.012137e-002" />
+      <stop
+         id="stop19419"
+         style="stop-color:#929292"
+         offset="8.366583e-002" />
+      <stop
+         id="stop19421"
+         style="stop-color:#A7A7A7"
+         offset="0.1422" />
+      <stop
+         id="stop19423"
+         style="stop-color:#B6B6B6"
+         offset="0.2074" />
+      <stop
+         id="stop19425"
+         style="stop-color:#BEBEBE"
+         offset="0.2846" />
+      <stop
+         id="stop19427"
+         style="stop-color:#C1C1C1"
+         offset="0.4045" />
+      <stop
+         id="stop19429"
+         style="stop-color:#BCBCBC"
+         offset="0.4962" />
+      <stop
+         id="stop19431"
+         style="stop-color:#ADADAD"
+         offset="0.6057" />
+      <stop
+         id="stop19433"
+         style="stop-color:#959595"
+         offset="0.7245" />
+      <stop
+         id="stop19435"
+         style="stop-color:#747474"
+         offset="0.8497" />
+      <stop
+         id="stop19437"
+         style="stop-color:#494949"
+         offset="0.9789" />
+      <stop
+         id="stop19439"
+         style="stop-color:#414141"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient19894"
+       gradientUnits="userSpaceOnUse"
+       x1="18.995100"
+       y1="37.226601"
+       x2="30.169901"
+       y2="37.226601">
+      <stop
+         offset="5.618000e-003"
+         style="stop-color:#A3A349"
+         id="stop19896" />
+      <stop
+         offset="2.078677e-002"
+         style="stop-color:#ACAC54"
+         id="stop19898" />
+      <stop
+         offset="6.600059e-002"
+         style="stop-color:#C1C172"
+         id="stop19900" />
+      <stop
+         offset="0.1148"
+         style="stop-color:#D4D68E"
+         id="stop19902" />
+      <stop
+         offset="0.1677"
+         style="stop-color:#E2E4A6"
+         id="stop19904" />
+      <stop
+         offset="0.2265"
+         style="stop-color:#EDF0B8"
+         id="stop19906" />
+      <stop
+         offset="0.2963"
+         style="stop-color:#F3F6C3"
+         id="stop19908" />
+      <stop
+         offset="0.4045"
+         style="stop-color:#F5F8C7"
+         id="stop19910" />
+      <stop
+         offset="0.5239"
+         style="stop-color:#EEF0BE"
+         id="stop19912" />
+      <stop
+         offset="0.6666"
+         style="stop-color:#DBDDA9"
+         id="stop19914" />
+      <stop
+         offset="0.8211"
+         style="stop-color:#BEBD88"
+         id="stop19916" />
+      <stop
+         offset="0.9832"
+         style="stop-color:#989564"
+         id="stop19918" />
+      <stop
+         offset="1"
+         style="stop-color:#949160"
+         id="stop19920" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="matrix(1.639127,0,0,1.639127,-15.97035,-29.79355)"
+       y2="43.165"
+       x2="26.4785"
+       y1="43.165"
+       x1="23.124"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient20109"
+       xlink:href="#aigrd1"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       r="7.8289826"
+       fy="74.209934"
+       fx="14.772334"
+       cy="74.209934"
+       cx="14.772334"
+       gradientTransform="scale(1.764278,0.566804)"
+       id="radialGradient20216"
+       xlink:href="#linearGradient20210"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="36.726292"
+       x2="32.096882"
+       y1="10.061084"
+       x1="16.998856"
+       gradientTransform="matrix(1.140494,0.000000,0.000000,0.926002,0.272330,-3.247170)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7708"
+       xlink:href="#linearGradient6339"
+       inkscape:collect="always" />
+    <radialGradient
+       r="33.934090"
+       fy="29.869318"
+       fx="68.137589"
+       cy="29.869318"
+       cx="68.137589"
+       gradientTransform="matrix(0.551290,1.265592e-16,-1.355720e-16,0.766034,-10.48701,3.514312)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient7720"
+       xlink:href="#aigrd7"
+       inkscape:collect="always" />
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       y2="3.8557322"
+       x2="-5.2517161"
+       y1="16.651863"
+       x1="37.940434"
+       gradientTransform="matrix(0.894129,0.000000,0.000000,0.985230,1.515981,2.449800e-2)"
+       id="linearGradient3181"
+       xlink:href="#linearGradient3175"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient1700"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.6293,0,0,1.589068,50.68808,3.804378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient1702"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.6293,0,0,1.589068,1.411612,3.929378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20428"
+       id="linearGradient1704"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.985083,0,0,0.503757,1.786612,4.554378)"
+       x1="14.637301"
+       y1="31.504122"
+       x2="9.3648205"
+       y2="32.250980" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient1725"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.026450,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient1727"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.026450,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient1729"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.026450,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient1731"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.026450,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3311"
+       id="linearGradient2516"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.603440,0.000000,0.000000,0.549396,0.614167,2.449800e-2)"
+       x1="17.879995"
+       y1="55.362793"
+       x2="11.906206"
+       y2="54.863026" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3265"
+       id="linearGradient2518"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.905728,-4.386156e-2,0.189510,-0.963437,0.614167,2.449800e-2)"
+       x1="-29.007195"
+       y1="-29.799353"
+       x2="-37.641232"
+       y2="-29.598314" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient2522"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.300410)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient2524"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.300410)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient2529"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient2531"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3300"
+       id="linearGradient3306"
+       gradientTransform="scale(1.002656,0.997352)"
+       x1="24.613028"
+       y1="31.146202"
+       x2="24.613028"
+       y2="26.739624"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3311"
+       id="linearGradient3127"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.60344,0,0,0.549396,0.614167,2.4498e-2)"
+       x1="17.879995"
+       y1="55.362793"
+       x2="11.906206"
+       y2="54.863026" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3265"
+       id="linearGradient3129"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.905728,-4.386156e-2,0.18951,-0.963437,0.614167,2.4498e-2)"
+       x1="-29.007195"
+       y1="-29.799353"
+       x2="-37.641232"
+       y2="-29.598314" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd7"
+       id="radialGradient3131"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.55129,1.265592e-16,-1.35572e-16,0.766034,-10.48701,3.514312)"
+       cx="68.137589"
+       cy="29.869318"
+       fx="68.137589"
+       fy="29.869318"
+       r="33.934090" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6339"
+       id="linearGradient3133"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.140494,0,0,0.926002,0.27233,-3.24717)"
+       x1="16.998856"
+       y1="10.061084"
+       x2="32.096882"
+       y2="36.726292" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3175"
+       id="linearGradient3135"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.894129,0,0,0.98523,1.515981,2.4498e-2)"
+       x1="37.940434"
+       y1="16.651863"
+       x2="-5.2517161"
+       y2="3.8557322" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3311"
+       id="linearGradient3157"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.60344,0,0,0.549396,0.614167,2.4498e-2)"
+       x1="17.879995"
+       y1="55.362793"
+       x2="11.906206"
+       y2="54.863026" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3265"
+       id="linearGradient3159"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.905728,-4.386156e-2,0.18951,-0.963437,0.614167,2.4498e-2)"
+       x1="-29.007195"
+       y1="-29.799353"
+       x2="-37.641232"
+       y2="-29.598314" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd7"
+       id="radialGradient3161"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.55129,1.265592e-16,-1.35572e-16,0.766034,-10.48701,3.514312)"
+       cx="68.137589"
+       cy="29.869318"
+       fx="68.137589"
+       fy="29.869318"
+       r="33.934090" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3175"
+       id="linearGradient3163"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.894129,0,0,0.98523,1.515981,2.4498e-2)"
+       x1="37.940434"
+       y1="16.651863"
+       x2="-5.2517161"
+       y2="3.8557322" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient3165"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.6293,0,0,1.589068,50.68808,3.804378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient3167"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.6293,0,0,1.589068,1.411612,3.929378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20428"
+       id="linearGradient3169"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.985083,0,0,0.503757,1.786612,4.554378)"
+       x1="14.637301"
+       y1="31.504122"
+       x2="9.3648205"
+       y2="32.250980" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6339"
+       id="linearGradient3171"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.140494,0,0,0.926002,0.27233,-3.24717)"
+       x1="16.998856"
+       y1="10.061084"
+       x2="32.096882"
+       y2="36.726292" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3300"
+       id="linearGradient3185"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.002656,0.997352)"
+       x1="24.613028"
+       y1="31.146202"
+       x2="24.613028"
+       y2="26.739624" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient3187"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient3189"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient3191"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient3193"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient3195"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient3197"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient3199"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.30041)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient3201"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.30041)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd1"
+       id="linearGradient4100"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.639127,0,0,1.639127,-15.97035,-29.79355)"
+       x1="23.124"
+       y1="43.165"
+       x2="26.4785"
+       y2="43.165" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3300"
+       id="linearGradient4102"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.002656,0.997352)"
+       x1="24.613028"
+       y1="31.146202"
+       x2="24.613028"
+       y2="26.739624" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient4104"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient4106"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.566621,2.988977e-2,-0.118557,0.656541,36.18544,20.08311)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient4108"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient4110"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient4112"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient4114"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.02645,0.974232)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient19894"
+       id="linearGradient4116"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.30041)"
+       x1="-22.874170"
+       y1="38.675991"
+       x2="-4.3908315"
+       y2="38.675991" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2399"
+       id="linearGradient4118"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.618682,-0.132027,6.262726e-2,0.741184,31.12021,8.30041)"
+       x1="-10.480865"
+       y1="39.033951"
+       x2="-23.851389"
+       y2="39.142845" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3311"
+       id="linearGradient4120"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.60344,0,0,0.549396,0.614167,2.4498e-2)"
+       x1="17.879995"
+       y1="55.362793"
+       x2="11.906206"
+       y2="54.863026" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3265"
+       id="linearGradient4122"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.905728,-4.386156e-2,0.18951,-0.963437,0.614167,2.4498e-2)"
+       x1="-29.007195"
+       y1="-29.799353"
+       x2="-37.641232"
+       y2="-29.598314" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd7"
+       id="radialGradient4124"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.55129,1.265592e-16,-1.35572e-16,0.766034,-10.48701,3.514312)"
+       cx="68.137589"
+       cy="29.869318"
+       fx="68.137589"
+       fy="29.869318"
+       r="33.934090" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3175"
+       id="linearGradient4126"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.894129,0,0,0.98523,1.515981,2.4498e-2)"
+       x1="37.940434"
+       y1="16.651863"
+       x2="-5.2517161"
+       y2="3.8557322" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient4128"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.6293,0,0,1.589068,50.68808,3.804378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20393"
+       id="linearGradient4130"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.6293,0,0,1.589068,1.411612,3.929378)"
+       x1="30.620375"
+       y1="10.313651"
+       x2="32.166080"
+       y2="18.162935" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient20428"
+       id="linearGradient4132"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.985083,0,0,0.503757,1.786612,4.554378)"
+       x1="14.637301"
+       y1="31.504122"
+       x2="9.3648205"
+       y2="32.250980" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6339"
+       id="linearGradient4134"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.140494,0,0,0.926002,0.27233,-3.24717)"
+       x1="16.998856"
+       y1="10.061084"
+       x2="32.096882"
+       y2="36.726292" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="30"
+     inkscape:window-x="0"
+     inkscape:window-height="818"
+     inkscape:window-width="1060"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="true"
+     inkscape:current-layer="layer1"
+     inkscape:cy="19.729332"
+     inkscape:cx="-132.96706"
+     inkscape:zoom="1"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.55294118"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:showpageshadow="false">
+    <inkscape:grid
+       id="GridFromPre046Settings"
+       type="xygrid"
+       originx="0px"
+       originy="0px"
+       spacingx="1px"
+       spacingy="1px"
+       color="#0000ff"
+       empcolor="#0000ff"
+       opacity="0.2"
+       empopacity="0.4"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <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>Info</dc:title>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>dialog</rdf:li>
+            <rdf:li>info</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Garrett LeSage</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+      </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"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <path
+       transform="matrix(1.197183,0,0,1.098591,-6.201582,-3.209507)"
+       d="M 39.875 42.0625 A 13.8125 4.4375 0 1 1  12.25,42.0625 A 13.8125 4.4375 0 1 1  39.875 42.0625 z"
+       sodipodi:ry="4.4375"
+       sodipodi:rx="13.8125"
+       sodipodi:cy="42.0625"
+       sodipodi:cx="26.0625"
+       id="path20208"
+       style="color:#000000;fill:url(#radialGradient20216);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;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:inline;overflow:visible;opacity:0.8"
+       sodipodi:type="arc"
+       inkscape:r_cx="true"
+       inkscape:r_cy="true" />
+    <g
+       id="g4076"
+       transform="translate(0,1)"
+       inkscape:r_cx="true"
+       inkscape:r_cy="true">
+      <path
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(1.075823,0,0,0.937493,-2.551335,3.047213)"
+         id="path19509"
+         d="M 21.893504,38.885945 L 21.893504,40.36116 C 21.893504,41.836375 23.204807,43.147679 24.680022,43.147679 C 26.155237,43.147679 27.466539,41.836375 27.466539,40.36116 L 27.466539,38.885945 L 21.893504,38.885945 z "
+         style="fill:url(#linearGradient4100);fill-rule:nonzero;stroke:#565656;stroke-miterlimit:4;stroke-opacity:1" />
+      <g
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="matrix(0.989073,0,0,0.993556,-0.408739,7.920479e-3)"
+         id="g3173">
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="cccccccscccccccs"
+           id="path3209"
+           d="M 24.511725,27.668867 C 21.208844,27.660897 17.463275,28.632054 19.492913,30.467931 C 18.98969,30.670934 18.270371,31.124313 18.355167,32.185222 C 18.401983,32.739286 18.989243,33.079394 19.79236,33.32911 C 18.881908,33.967722 18.302581,34.642557 18.355167,35.264921 C 18.401438,35.812525 18.976334,36.187531 19.76303,36.43814 C 18.875519,37.069403 18.303301,37.760121 18.355167,38.373951 C 18.434436,39.312088 20.457743,40.362928 24.838928,40.2419 C 27.993329,40.155914 30.776913,39.590514 30.996599,38.373951 C 31.082862,37.896248 30.691907,37.450531 30.087355,37.05408 C 30.539926,36.597918 30.85698,36.135242 30.820616,35.704878 C 30.774128,35.154694 30.205993,34.781923 29.412754,34.53166 C 30.300265,33.900397 30.872482,33.209679 30.820616,32.595849 C 30.774128,32.045664 30.205993,31.702225 29.412754,31.45196 C 30.310848,30.817288 30.872816,30.133928 30.820616,29.516149 C 30.762593,28.829446 27.61599,27.676358 24.511725,27.668867 z "
+           style="color:#000000;fill:#aeae57;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4102);stroke-width:2.01752925;stroke-linecap:round;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:inline;overflow:visible" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="csccc"
+           id="path3183"
+           d="M 30.920208,38.329767 C 30.700522,39.546331 27.591422,40.232861 22.615132,39.983673 C 19.463507,39.825856 19.283163,38.944055 19.502848,37.727491 C 19.722534,36.510926 22.458318,35.65848 25.609509,35.824708 C 28.7607,35.990936 31.139893,37.113203 30.920208,38.329767 z "
+           style="color:#000000;fill:url(#linearGradient4104);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4106);stroke-width:0.08906282;stroke-linecap:round;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:inline;overflow:visible" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:type="arc"
+           style="color:#000000;fill:url(#linearGradient4108);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4110);stroke-width:0.13035245;stroke-linecap:round;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:inline;overflow:visible"
+           id="path1603"
+           sodipodi:cx="-13.87697"
+           sodipodi:cy="27.228739"
+           sodipodi:rx="10.341436"
+           sodipodi:ry="3.2703688"
+           d="M -3.5355339 27.228739 A 10.341436 3.2703688 0 1 1  -24.218407,27.228739 A 10.341436 3.2703688 0 1 1  -3.5355339 27.228739 z"
+           transform="matrix(0.60274,-0.128625,6.428372e-2,0.760788,31.12021,14.49141)" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           transform="matrix(0.60274,-0.128625,6.428372e-2,0.760788,31.12021,11.39591)"
+           d="M -3.5355339 27.228739 A 10.341436 3.2703688 0 1 1  -24.218407,27.228739 A 10.341436 3.2703688 0 1 1  -3.5355339 27.228739 z"
+           sodipodi:ry="3.2703688"
+           sodipodi:rx="10.341436"
+           sodipodi:cy="27.228739"
+           sodipodi:cx="-13.87697"
+           id="path2364"
+           style="color:#000000;fill:url(#linearGradient4112);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4114);stroke-width:0.13035245;stroke-linecap:round;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:inline;overflow:visible"
+           sodipodi:type="arc" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="cccss"
+           id="path2366"
+           d="M 30.698087,29.636386 C 30.698087,31.014688 28.157326,32.55444 24.716601,33.288693 C 21.275876,34.022945 18.38922,33.50421 18.273172,32.130802 C 18.157124,30.757395 20.509679,29.155466 23.952388,28.968827 C 27.422379,28.780711 30.698087,28.924901 30.698087,29.636386 z "
+           style="color:#000000;fill:url(#linearGradient4116);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4118);stroke-width:0.08906286;stroke-linecap:round;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:inline;overflow:visible" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           transform="matrix(0.335464,0,0,0.335464,11.74678,27.2261)"
+           d="M 31 22.375 A 3.25 3.25 0 1 1  24.5,22.375 A 3.25 3.25 0 1 1  31 22.375 z"
+           sodipodi:ry="3.25"
+           sodipodi:rx="3.25"
+           sodipodi:cy="22.375"
+           sodipodi:cx="27.75"
+           id="path20372"
+           style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;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:inline;overflow:visible"
+           sodipodi:type="arc" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="cscc"
+           id="path3241"
+           d="M 19.342183,33.378865 C 22.736592,33.883533 26.320992,33.346192 29.214315,31.470807 C 30.025582,30.944962 30.147604,30.343945 30.520921,29.873844 C 29.09679,31.000705 25.494982,34.035625 19.342183,33.378865 z "
+           style="fill:#000000;fill-opacity:0.23391807;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:type="arc"
+           style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;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:inline;overflow:visible"
+           id="path2435"
+           sodipodi:cx="27.75"
+           sodipodi:cy="22.375"
+           sodipodi:rx="3.25"
+           sodipodi:ry="3.25"
+           d="M 31 22.375 A 3.25 3.25 0 1 1  24.5,22.375 A 3.25 3.25 0 1 1  31 22.375 z"
+           transform="matrix(0.335464,0,0,0.335464,11.74678,30.23376)" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           sodipodi:nodetypes="cscc"
+           id="path3237"
+           d="M 19.466621,39.517838 C 22.86103,40.022506 26.44543,39.485165 29.338753,37.60978 C 30.15002,37.083935 30.272043,36.482919 30.645359,36.012817 C 29.221228,37.139678 25.61942,40.174598 19.466621,39.517838 z "
+           style="fill:#000000;fill-opacity:0.23391807;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           style="fill:#000000;fill-opacity:0.23391807;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="M 19.487361,36.406872 C 22.88177,36.91154 26.46617,36.374199 29.359492,34.498814 C 30.17076,33.972969 30.292782,33.371953 30.666099,32.901851 C 29.241968,34.028712 25.64016,37.063632 19.487361,36.406872 z "
+           id="path3239"
+           sodipodi:nodetypes="cscc" />
+      </g>
+      <g
+         inkscape:r_cy="true"
+         inkscape:r_cx="true"
+         transform="translate(-0.988797,0)"
+         id="g3146">
+        <g
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           id="g3141">
+          <path
+             transform="matrix(0.954439,0,0,0.989869,1.433222,0.639881)"
+             sodipodi:nodetypes="csscs"
+             id="path3243"
+             d="M 18.87103,29.628128 C 18.87103,28.836695 20.445135,27.889988 24.419234,27.942972 C 28.101154,27.992059 30.526608,28.83866 30.526608,30.105404 C 30.526608,31.345281 27.307242,32.174416 23.874677,32.008188 C 20.442113,31.84196 18.87103,30.868005 18.87103,29.628128 z "
+             style="color:#000000;fill:url(#linearGradient4120);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4122);stroke-width:0.09083303;stroke-linecap:round;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:inline;overflow:visible"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+          <path
+             transform="matrix(0.954439,0,0,0.989869,1.433222,0.639881)"
+             sodipodi:nodetypes="csssssc"
+             id="path6305"
+             d="M 24.680021,0.8622936 C 16.858005,0.8622936 10.506261,6.8372628 10.506261,14.195288 C 10.506261,21.737851 16.247826,22.573217 16.247826,25.352995 C 16.247826,28.619061 19.614103,32.322687 25.149309,32.188995 C 31.035159,32.046835 33.464182,28.825655 33.464182,25.352995 C 33.464182,22.384064 38.853781,22.304889 38.853781,14.195288 C 38.853781,6.8372628 32.502038,0.8622936 24.680021,0.8622936 z "
+             style="color:#000000;fill:url(#radialGradient4124);fill-opacity:1;fill-rule:nonzero;stroke:#616471;stroke-width:1.01595449;stroke-linecap:round;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:inline;overflow:visible"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+          <path
+             transform="matrix(0.954439,0,0,0.989869,1.433222,0.639881)"
+             style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4126);stroke-width:0.94685698;stroke-linecap:round;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:inline;overflow:visible"
+             d="M 24.680021,1.9277146 C 17.389999,1.9277146 11.470252,7.4963123 11.470252,14.353901 C 11.470252,21.383476 16.82132,22.162027 16.82132,24.752746 C 16.82132,27.79668 19.958648,31.248413 25.117392,31.123813 C 30.602931,30.991321 32.866751,27.989222 32.866751,24.752746 C 32.866751,21.98574 37.889791,21.911948 37.889791,14.353901 C 37.889791,7.4963123 31.970044,1.9277146 24.680021,1.9277146 z "
+             id="path2429"
+             sodipodi:nodetypes="csssssc"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+        </g>
+        <g
+           id="g1695"
+           transform="matrix(0.9375,0,0,0.926938,0.569221,0.25176)"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true">
+          <path
+             style="fill:url(#linearGradient4128);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-miterlimit:4"
+             d="M 31.947292,19.22274 C 32.260034,19.326988 32.468529,19.63973 32.364281,19.952471 L 28.507134,31.523913 C 28.402887,31.836655 28.090145,32.045149 27.777403,31.940902 C 27.464662,31.836655 27.256168,31.523913 27.360415,31.211172 L 31.217562,19.63973 C 31.321809,19.326988 31.634551,19.118493 31.947292,19.22274 z "
+             id="path1691"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+          <path
+             id="path19612"
+             d="M 20.152404,19.34774 C 19.839662,19.451988 19.631167,19.76473 19.735415,20.077471 L 23.592562,31.648913 C 23.696809,31.961655 24.009551,32.170149 24.322293,32.065902 C 24.635034,31.961655 24.843528,31.648913 24.739281,31.336172 L 20.882134,19.76473 C 20.777887,19.451988 20.465145,19.243493 20.152404,19.34774 z "
+             style="fill:url(#linearGradient4130);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-miterlimit:4"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+          <path
+             style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4132);stroke-width:0.21454535;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+             d="M 20.255362,19.273128 C 20.009452,19.315194 19.816806,19.507772 19.774653,19.753667 C 19.732499,19.999562 19.850004,20.245309 20.067862,20.366878 C 20.067862,20.366878 21.910084,21.447747 24.317862,21.991878 C 26.72564,22.536009 29.806763,22.571305 32.130362,20.304378 C 32.305608,20.165345 32.386854,19.938963 32.340007,19.720224 C 32.29316,19.501485 32.126325,19.328233 31.909509,19.273168 C 31.692693,19.218103 31.463406,19.290751 31.317862,19.460628 C 29.367326,21.36359 26.773024,21.36522 24.567862,20.866878 C 22.3627,20.368536 20.661612,19.366878 20.661612,19.366878 C 20.542178,19.287089 20.397682,19.253744 20.255362,19.273128 z "
+             id="path19614"
+             inkscape:r_cx="true"
+             inkscape:r_cy="true" />
+        </g>
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           style="opacity:0.5977654;color:#000000;fill:url(#linearGradient4134);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98750001;stroke-linecap:round;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:inline;overflow:visible"
+           d="M 25.001158,3.5644322 C 18.737608,3.5644322 13.655359,7.5900329 13.655359,12.547843 C 13.655359,14.527956 14.632918,16.261758 16.006008,17.747035 C 17.558672,18.378895 19.249827,18.832941 21.114752,18.832941 C 27.378302,18.832941 32.460549,14.807341 32.460551,9.849528 C 32.460551,7.857476 31.466744,6.1074629 30.07856,4.6174331 C 28.533139,3.9930601 26.854241,3.5644321 25.001158,3.5644322 z "
+           id="path6334"
+           transform="matrix(0.954439,0,0,0.989869,1.433222,0.639881)" />
+      </g>
+    </g>
+  </g>
+</svg>
Binary file libgui/src/icons/dialog-warning.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/dialog-warning.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,373 @@
+<?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"
+   width="48px"
+   height="48px"
+   id="svg1377"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/status"
+   sodipodi:docname="dialog-warning.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs1379">
+    <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="perspective48" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient6719"
+       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="radialGradient6717"
+       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="linearGradient6715"
+       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
+       y2="56.0523"
+       x2="47.3197"
+       y1="11.1133"
+       x1="4.1914"
+       gradientUnits="userSpaceOnUse"
+       id="aigrd1">
+      <stop
+         id="stop6490"
+         style="stop-color:#D4D4D4"
+         offset="0" />
+      <stop
+         id="stop6492"
+         style="stop-color:#E2E2E2"
+         offset="0.3982" />
+      <stop
+         id="stop6494"
+         style="stop-color:#FFFFFF"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       y2="56.0523"
+       x2="47.3197"
+       y1="11.1133"
+       x1="4.1914"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7451"
+       xlink:href="#aigrd1"
+       inkscape:collect="always" />
+    <linearGradient
+       id="linearGradient4126"
+       inkscape:collect="always">
+      <stop
+         id="stop4128"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop4130"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       r="17.142857"
+       fy="40.000000"
+       fx="23.857143"
+       cy="40.000000"
+       cx="23.857143"
+       gradientTransform="matrix(1,0,0,0.5,2.139286e-14,20)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient7449"
+       xlink:href="#linearGradient4126"
+       inkscape:collect="always" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6525"
+       id="linearGradient5250"
+       x1="8.5469341"
+       y1="30.281681"
+       x2="30.85088"
+       y2="48.301884"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.899009,0,0,0.934235,1.875108,1.193645)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd1"
+       id="linearGradient3922"
+       gradientUnits="userSpaceOnUse"
+       x1="4.1914"
+       y1="11.1133"
+       x2="47.3197"
+       y2="56.0523" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6525"
+       id="linearGradient3924"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.899009,0,0,0.934235,1.875108,1.193645)"
+       x1="8.5469341"
+       y1="30.281681"
+       x2="30.85088"
+       y2="48.301884" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6525"
+       id="linearGradient3933"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.899009,0,0,0.934235,1.875108,1.193645)"
+       x1="8.5469341"
+       y1="30.281681"
+       x2="30.85088"
+       y2="48.301884" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd1"
+       id="linearGradient3935"
+       gradientUnits="userSpaceOnUse"
+       x1="4.1914"
+       y1="11.1133"
+       x2="47.3197"
+       y2="56.0523" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#aigrd1"
+       id="linearGradient3946"
+       gradientUnits="userSpaceOnUse"
+       x1="4.1914"
+       y1="11.1133"
+       x2="47.3197"
+       y2="56.0523" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient6525"
+       id="linearGradient3948"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.899009,0,0,0.934235,1.875108,1.193645)"
+       x1="8.5469341"
+       y1="30.281681"
+       x2="30.85088"
+       y2="48.301884" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="14.757891"
+     inkscape:cx="13.022822"
+     inkscape:cy="24"
+     inkscape:current-layer="g7435"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1105"
+     inkscape:window-height="818"
+     inkscape:window-x="0"
+     inkscape:window-y="30">
+    <inkscape:grid
+       id="GridFromPre046Settings"
+       type="xygrid"
+       originx="0px"
+       originy="0px"
+       spacingx="1px"
+       spacingy="1px"
+       color="#0000ff"
+       empcolor="#0000ff"
+       opacity="0.2"
+       empopacity="0.4"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata1382">
+    <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>Dialog Warning</dc:title>
+        <dc:date>2005-10-14</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Andreas Nilsson</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Jakub Steiner, Garrett LeSage</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>dialog</rdf:li>
+            <rdf:li>warning</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+      </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
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       transform="matrix(1.566667,0.000000,0.000000,1.566667,-8.925566,-23.94764)"
+       id="g7435">
+      <g
+         style="display:inline"
+         transform="matrix(1.444074e-2,0,0,1.331973e-2,33.38871,40.40337)"
+         id="g6707">
+        <rect
+           style="opacity:0.40206185;color:black;fill:url(#linearGradient6715);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"
+           id="rect6709"
+           width="1339.6335"
+           height="478.35718"
+           x="-1559.2523"
+           y="-150.69685" />
+        <path
+           style="opacity:0.40206185;color:black;fill:url(#radialGradient6717);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 -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 "
+           id="path6711"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           id="path6713"
+           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 "
+           style="opacity:0.40206185;color:black;fill:url(#radialGradient6719);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" />
+      </g>
+      <g
+         id="g3937"
+         transform="matrix(1,0,4.537846e-3,1,-0.138907,-1.394718e-15)"
+         inkscape:r_cx="true"
+         inkscape:r_cy="true">
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           transform="matrix(1,0,-8.726683e-3,1,0.328074,1.276596)"
+           id="path6485"
+           d="M 33.282781,38.644744 L 22.407791,18.394765 C 22.095292,17.832266 21.532792,17.519767 20.907793,17.519767 C 20.282793,17.519767 19.720294,17.894765 19.407795,18.457265 L 8.7828048,38.707245 C 8.5328048,39.207244 8.5328048,39.894744 8.8453048,40.394743 C 9.1578038,40.894743 9.6578038,41.144742 10.282804,41.144742 L 31.782782,41.144742 C 32.407781,41.144742 32.97028,40.832243 33.220281,40.332243 C 33.53278,39.832243 33.53278,39.207244 33.282781,38.644744 z "
+           style="fill:#cc0000;fill-rule:nonzero;stroke:#9f0000;stroke-width:0.6382978;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+        <g
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           id="g6487"
+           transform="matrix(0.625,0,-5.534934e-3,0.634254,6.164053,15.76055)"
+           style="fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4">
+          <linearGradient
+             y2="56.052299"
+             x2="47.319698"
+             y1="11.1133"
+             x1="4.1914001"
+             gradientUnits="userSpaceOnUse"
+             id="linearGradient6525">
+            <stop
+               id="stop6529"
+               style="stop-color:#ffffff;stop-opacity:1;"
+               offset="0" />
+            <stop
+               id="stop6531"
+               style="stop-color:#ffffff;stop-opacity:0.34020618;"
+               offset="1" />
+          </linearGradient>
+          <path
+             inkscape:r_cy="true"
+             inkscape:r_cx="true"
+             id="path6496"
+             d="M 9.5,37.6 C 9.2,38.1 9.5,38.5 10,38.5 L 38.2,38.5 C 38.7,38.5 39,38.1 38.7,37.6 L 24.4,11 C 24.1,10.5 23.7,10.5 23.5,11 L 9.5,37.6 z "
+             style="fill:url(#linearGradient3946);stroke:none" />
+        </g>
+        <path
+           inkscape:r_cy="true"
+           inkscape:r_cx="true"
+           transform="matrix(1,0,-8.726683e-3,1,0.318277,1.276596)"
+           sodipodi:nodetypes="ccsccscccc"
+           id="path1325"
+           d="M 32.323106,38.183905 L 22.150271,19.265666 C 21.71698,18.45069 21.561698,18.189213 20.908406,18.189213 C 20.346525,18.189213 20.054127,18.57002 19.651305,19.339291 L 9.7489285,38.242296 C 9.1737649,39.303588 9.1128238,39.580228 9.3937644,40.047345 C 9.6747034,40.514462 10.032797,40.48902 11.356441,40.519491 L 30.974593,40.519491 C 32.206825,40.534726 32.483988,40.440837 32.70874,39.97372 C 32.989681,39.506602 32.867799,39.136 32.323106,38.183905 z "
+           style="opacity:0.5;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3948);stroke-width:0.63829792;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+      </g>
+      <g
+         style="fill-rule:nonzero;stroke:#000000;stroke-miterlimit:4"
+         transform="matrix(0.555088,0,0,0.555052,7.749711,17.80196)"
+         id="g6498"
+         inkscape:r_cx="true"
+         inkscape:r_cy="true">
+        <path
+           style="stroke:none"
+           d="M 23.9,36.5 C 22.6,36.5 21.6,35.5 21.6,34.2 C 21.6,32.8 22.5,31.9 23.9,31.9 C 25.3,31.9 26.1,32.8 26.2,34.2 C 26.2,35.5 25.3,36.5 23.9,36.5 L 23.9,36.5 z M 22.5,30.6 L 21.9,19.1 L 25.9,19.1 L 25.3,30.6 L 22.4,30.6 L 22.5,30.6 z "
+           id="path6500"
+           inkscape:r_cx="true"
+           inkscape:r_cy="true" />
+      </g>
+    </g>
+  </g>
+</svg>
Binary file libgui/src/icons/go-home.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/go-home.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,445 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<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"
+   width="48"
+   height="48"
+   overflow="visible"
+   enable-background="new 0 0 128 129.396"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="go-home.svg"
+   sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
+   version="1.0"
+   inkscape:export-filename="/home/tigert/My Downloads/go-home.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+   id="metadata367"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
+         rdf:resource="http://creativecommons.org/licenses/publicdomain/" /><dc:title>Go Home</dc:title><dc:creator><cc:Agent><dc:title>Jakub Steiner</dc:title></cc:Agent></dc:creator><dc:source>http://jimmac.musichall.cz</dc:source><dc:subject><rdf:Bag><rdf:li>home</rdf:li><rdf:li>return</rdf:li><rdf:li>go</rdf:li><rdf:li>default</rdf:li><rdf:li>user</rdf:li><rdf:li>directory</rdf:li></rdf:Bag></dc:subject><dc:contributor><cc:Agent><dc:title>Tuomas Kuosmanen</dc:title></cc:Agent></dc:contributor></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><defs
+   id="defs365"><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="perspective92" /><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
+     id="linearGradient2406"><stop
+       style="stop-color:#7c7e79;stop-opacity:1;"
+       offset="0"
+       id="stop2408" /><stop
+       id="stop2414"
+       offset="0.1724138"
+       style="stop-color:#848681;stop-opacity:1;" /><stop
+       style="stop-color:#898c86;stop-opacity:1;"
+       offset="1"
+       id="stop2410" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2390"><stop
+       style="stop-color:#919191;stop-opacity:1;"
+       offset="0"
+       id="stop2392" /><stop
+       style="stop-color:#919191;stop-opacity:0;"
+       offset="1"
+       id="stop2394" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2378"><stop
+       style="stop-color:#575757;stop-opacity:1;"
+       offset="0"
+       id="stop2380" /><stop
+       style="stop-color:#575757;stop-opacity:0;"
+       offset="1"
+       id="stop2382" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2368"><stop
+       style="stop-color:#ffffff;stop-opacity:1;"
+       offset="0"
+       id="stop2370" /><stop
+       style="stop-color:#ffffff;stop-opacity:0;"
+       offset="1"
+       id="stop2372" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2349"><stop
+       style="stop-color:#000000;stop-opacity:1;"
+       offset="0"
+       id="stop2351" /><stop
+       style="stop-color:#000000;stop-opacity:0;"
+       offset="1"
+       id="stop2353" /></linearGradient><linearGradient
+     id="linearGradient2341"><stop
+       id="stop2343"
+       offset="0"
+       style="stop-color:#000000;stop-opacity:1;" /><stop
+       id="stop2345"
+       offset="1"
+       style="stop-color:#000000;stop-opacity:0;" /></linearGradient><linearGradient
+     id="linearGradient2329"><stop
+       style="stop-color:#000000;stop-opacity:0.18556701;"
+       offset="0"
+       id="stop2331" /><stop
+       style="stop-color:#ffffff;stop-opacity:1;"
+       offset="1"
+       id="stop2333" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2319"><stop
+       style="stop-color:#000000;stop-opacity:1;"
+       offset="0"
+       id="stop2321" /><stop
+       style="stop-color:#000000;stop-opacity:0;"
+       offset="1"
+       id="stop2323" /></linearGradient><linearGradient
+     id="linearGradient2307"><stop
+       style="stop-color:#edd400;stop-opacity:1;"
+       offset="0"
+       id="stop2309" /><stop
+       style="stop-color:#998800;stop-opacity:1;"
+       offset="1"
+       id="stop2311" /></linearGradient><linearGradient
+     inkscape:collect="always"
+     id="linearGradient2299"><stop
+       style="stop-color:#ffffff;stop-opacity:1;"
+       offset="0"
+       id="stop2301" /><stop
+       style="stop-color:#ffffff;stop-opacity:0;"
+       offset="1"
+       id="stop2303" /></linearGradient><linearGradient
+     id="XMLID_2_"
+     gradientUnits="userSpaceOnUse"
+     x1="80.223602"
+     y1="117.5205"
+     x2="48.046001"
+     y2="59.7995"
+     gradientTransform="matrix(0.314683,0.000000,0.000000,0.314683,4.128264,3.742874)">
+				<stop
+   offset="0"
+   style="stop-color:#CCCCCC"
+   id="stop17" />
+				<stop
+   offset="0.9831"
+   style="stop-color:#FFFFFF"
+   id="stop19" />
+				<midPointStop
+   offset="0"
+   style="stop-color:#CCCCCC"
+   id="midPointStop48" />
+				<midPointStop
+   offset="0.5"
+   style="stop-color:#CCCCCC"
+   id="midPointStop50" />
+				<midPointStop
+   offset="0.9831"
+   style="stop-color:#FFFFFF"
+   id="midPointStop52" />
+			</linearGradient><linearGradient
+     inkscape:collect="always"
+     xlink:href="#XMLID_2_"
+     id="linearGradient1514"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(0.336922,0.000000,0.000000,0.166888,17.98288,15.46151)"
+     x1="52.006104"
+     y1="166.1331"
+     x2="14.049017"
+     y2="-42.218513" /><linearGradient
+     id="XMLID_39_"
+     gradientUnits="userSpaceOnUse"
+     x1="64.387703"
+     y1="65.124001"
+     x2="64.387703"
+     y2="35.569"
+     gradientTransform="matrix(0.354101,0.000000,0.000000,0.354101,1.638679,-8.364921e-2)">
+						<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop336" />
+						<stop
+   offset="0.8539"
+   style="stop-color:#FF6200"
+   id="stop338" />
+						<stop
+   offset="1"
+   style="stop-color:#F25D00"
+   id="stop340" />
+						<midPointStop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="midPointStop335" />
+						<midPointStop
+   offset="0.5"
+   style="stop-color:#FFFFFF"
+   id="midPointStop337" />
+						<midPointStop
+   offset="0.8539"
+   style="stop-color:#FF6200"
+   id="midPointStop339" />
+						<midPointStop
+   offset="0.5"
+   style="stop-color:#FF6200"
+   id="midPointStop341" />
+						<midPointStop
+   offset="1"
+   style="stop-color:#F25D00"
+   id="midPointStop343" />
+					</linearGradient><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2299"
+     id="radialGradient2305"
+     cx="7.5326638"
+     cy="24.202574"
+     fx="7.5326638"
+     fy="24.202574"
+     r="8.2452128"
+     gradientTransform="matrix(4.100086,-1.627292e-17,2.125447e-14,4.201322,-25.41506,-78.53967)"
+     gradientUnits="userSpaceOnUse" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2307"
+     id="radialGradient2313"
+     cx="19.985598"
+     cy="36.77816"
+     fx="19.985598"
+     fy="36.77816"
+     r="1.0821035"
+     gradientTransform="matrix(1.125263,0.000000,0.000000,0.982744,-3.428678,0.565787)"
+     gradientUnits="userSpaceOnUse" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2319"
+     id="radialGradient2325"
+     cx="20.443665"
+     cy="37.425829"
+     fx="20.443665"
+     fy="37.425829"
+     r="1.0821035"
+     gradientTransform="matrix(1.125263,0.000000,0.000000,0.982744,-3.428678,0.731106)"
+     gradientUnits="userSpaceOnUse" /><linearGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2329"
+     id="linearGradient2335"
+     x1="17.602522"
+     y1="26.057423"
+     x2="17.682528"
+     y2="32.654099"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(0.898789,0,0,1.071914,0.478025,-2.080838)" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2341"
+     id="radialGradient2339"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(4.100086,1.627292e-17,2.125447e-14,-4.201322,-5.198109,105.3535)"
+     cx="11.68129"
+     cy="19.554111"
+     fx="11.68129"
+     fy="19.554111"
+     r="8.2452126" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2349"
+     id="radialGradient2355"
+     cx="24.023088"
+     cy="40.56913"
+     fx="24.023088"
+     fy="40.56913"
+     r="16.28684"
+     gradientTransform="matrix(1.000000,0.000000,0.000000,0.431250,1.157278e-15,23.07369)"
+     gradientUnits="userSpaceOnUse" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2368"
+     id="radialGradient2374"
+     cx="29.913452"
+     cy="30.442923"
+     fx="29.913452"
+     fy="30.442923"
+     r="4.0018832"
+     gradientTransform="matrix(3.751495,-2.191984e-22,1.723265e-22,3.147818,-82.00907,-65.70704)"
+     gradientUnits="userSpaceOnUse" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2378"
+     id="radialGradient2384"
+     cx="24.195112"
+     cy="10.577631"
+     fx="24.195112"
+     fy="10.577631"
+     r="15.242914"
+     gradientTransform="matrix(1.125263,-3.585417e-8,4.269819e-8,1.340059,-3.006704,1.355395)"
+     gradientUnits="userSpaceOnUse" /><linearGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2390"
+     id="linearGradient2396"
+     x1="30.603519"
+     y1="37.337803"
+     x2="30.603519"
+     y2="36.112415"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(1.263867,0,0,0.859794,-6.499556,8.390924)" /><linearGradient
+     inkscape:collect="always"
+     xlink:href="#linearGradient2406"
+     id="linearGradient2412"
+     x1="17.850183"
+     y1="28.939463"
+     x2="19.040216"
+     y2="41.03223"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(0.888785,0,0,1.08932,2.41099,-1.524336)" /></defs><sodipodi:namedview
+   inkscape:cy="-2.3755359"
+   inkscape:cx="25.234802"
+   inkscape:zoom="1"
+   inkscape:window-height="691"
+   inkscape:window-width="872"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   borderopacity="0.21568627"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   inkscape:showpageshadow="false"
+   inkscape:window-x="466"
+   inkscape:window-y="157"
+   inkscape:current-layer="svg2"
+   fill="#555753"
+   showgrid="false"
+   stroke="#a40000"
+   showguides="true"
+   inkscape:guide-bbox="true" />
+	<g
+   style="display:inline"
+   id="g5022"
+   transform="matrix(2.158196e-2,0,0,1.859457e-2,43.12251,41.63767)"><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><path
+   style="color:#000000;fill:url(#linearGradient1514);fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:1.0000006;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+   d="M 21.619576,8.1833733 L 27.577035,8.1833733 C 28.416767,8.1833733 41.46351,23.618701 41.46351,24.524032 L 41.019989,43.020777 C 41.019989,43.92611 40.343959,44.654954 39.504227,44.654954 L 8.0469496,44.654954 C 7.2072167,44.654954 6.5311871,43.92611 6.5311871,43.020777 L 6.5876651,24.524032 C 6.5876651,23.618701 20.779844,8.1833733 21.619576,8.1833733 z "
+   id="rect1512"
+   sodipodi:nodetypes="ccccccccc" /><path
+   style="fill:none"
+   id="path5"
+   d="M 46.963575,45.735573 L 1.6386762,45.735573 L 1.6386762,0.41067554 L 46.963575,0.41067554 L 46.963575,45.735573 z " /><path
+   style="fill:url(#linearGradient2335);fill-opacity:1;fill-rule:evenodd"
+   id="path2327"
+   d="M 23,29 L 22.954256,44.090942 L 11.111465,44.090942 L 11,29 L 23,29 z "
+   clip-rule="evenodd"
+   sodipodi:nodetypes="ccccc" /><path
+   sodipodi:nodetypes="ccccccccc"
+   id="path2357"
+   d="M 21.780459,9.405584 L 27.339556,9.405584 C 28.123138,9.405584 40.340425,23.805172 40.340425,24.649756 L 39.993267,42.862067 C 39.993267,43.321326 39.84953,43.515532 39.480892,43.515532 L 8.0936894,43.529812 C 7.7250517,43.529812 7.5097258,43.449894 7.5097258,43.076262 L 7.7250676,24.649756 C 7.7250676,23.805172 20.99688,9.405584 21.780459,9.405584 z "
+   style="opacity:0.3125;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /><path
+   clip-rule="evenodd"
+   d="M 7.2075295,27.943053 L 7.1532728,30.538247 L 25.521437,17.358993 L 40.807832,28.513421 L 40.879142,28.201707 L 24.508686,12.297576 L 7.2075295,27.943053 z "
+   id="path23"
+   style="opacity:0.2;fill:url(#radialGradient2384);fill-opacity:1;fill-rule:evenodd"
+   sodipodi:nodetypes="ccccccc" /><path
+   clip-rule="evenodd"
+   d="M 22,30 L 22,44.090942 L 12.188971,44.090942 L 12,30 L 22,30 z "
+   id="path188"
+   style="fill:url(#linearGradient2412);fill-opacity:1;fill-rule:evenodd"
+   sodipodi:nodetypes="ccccc" /><path
+   style="opacity:0.40909089;fill:url(#radialGradient2325);fill-opacity:1;fill-rule:evenodd"
+   id="path2315"
+   d="M 19.576856,36.44767 C 20.249646,36.44767 20.793472,36.922275 20.793472,37.506177 C 20.793472,38.095988 20.249646,38.574532 19.576856,38.574532 C 18.904584,38.574532 18.35817,38.095988 18.35817,37.506177 C 18.358685,36.922275 18.904584,36.44767 19.576856,36.44767 z "
+   clip-rule="evenodd" /><path
+   clip-rule="evenodd"
+   d="M 19.462314,35.932229 C 20.135103,35.932229 20.678929,36.406834 20.678929,36.990736 C 20.678929,37.580545 20.135103,38.059089 19.462314,38.059089 C 18.790041,38.059089 18.243627,37.580545 18.243627,36.990736 C 18.244142,36.406834 18.790041,35.932229 19.462314,35.932229 z "
+   id="path217"
+   style="fill:url(#radialGradient2313);fill-opacity:1;fill-rule:evenodd" /><path
+   d="M 24.447748,11.559337 L 43.374808,28.729205 L 43.869487,29.121196 L 44.273163,28.949811 L 43.900293,28.188138 L 43.622679,27.964702 L 24.447748,12.392396 L 5.0582327,28.135731 L 4.8206309,28.279851 L 4.603921,28.986637 L 5.0373408,29.115885 L 5.4218948,28.807462 L 24.447748,11.559337 z "
+   id="path342"
+   style="fill:url(#XMLID_39_)"
+   sodipodi:nodetypes="ccccccccccccc" /><path
+   style="fill:#ef2929;stroke:#a40000"
+   id="path362"
+   d="M 24.330168,2.2713382 L 2.4484294,20.372675 L 1.8237005,27.538603 L 3.8236367,29.602926 C 3.8236367,29.602926 24.231018,12.445641 24.44773,12.274963 L 44.08027,29.818223 L 45.978694,27.494226 L 44.362903,20.382852 L 24.44773,2.1668788 L 24.330168,2.2713382 z "
+   sodipodi:nodetypes="cccccccccc" />
+<path
+   style="opacity:0.40909089;color:#000000;fill:url(#radialGradient2305);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;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 2.8413446,20.613129 L 2.5497894,27.236494 L 24.369219,8.980075 L 24.298891,3.0867443 L 2.8413446,20.613129 z "
+   id="path1536"
+   sodipodi:nodetypes="ccccc" /><path
+   sodipodi:nodetypes="ccccc"
+   id="path2337"
+   d="M 24.483763,8.7509884 L 24.583223,2.9098867 L 43.912186,20.56184 L 45.403998,27.062652 L 24.483763,8.7509884 z "
+   style="opacity:0.13636367;color:#000000;fill:url(#radialGradient2339);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;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" /><path
+   style="opacity:0.31818183;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999934;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+   d="M 27.102228,27.719824 L 36.142223,27.719824 C 36.912818,27.719824 37.53319,28.340194 37.53319,29.110791 L 37.525229,38.190012 C 37.525229,38.960608 36.928907,39.455981 36.158311,39.455981 L 27.102228,39.455981 C 26.331631,39.455981 25.711261,38.835608 25.711261,38.065012 L 25.711261,29.110791 C 25.711261,28.340194 26.331631,27.719824 27.102228,27.719824 z "
+   id="rect2361"
+   sodipodi:nodetypes="ccccccccc" /><rect
+   style="opacity:1;color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:#757575;stroke-width:0.9999994;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"
+   id="rect3263"
+   width="10.001333"
+   height="9.9624557"
+   x="26.507767"
+   y="28.514256"
+   rx="0.38128215"
+   ry="0.38128215" /><path
+   style="opacity:0.39772728;color:#000000;fill:url(#radialGradient2374);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999958;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 27.107118,34.408261 C 30.725101,34.739438 32.634842,32.962557 35.97527,32.855521 L 36,29.00603 L 27.088388,29 L 27.107118,34.408261 z "
+   id="rect2363"
+   sodipodi:nodetypes="ccccc" /></svg>
\ No newline at end of file
Binary file libgui/src/icons/go-next.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/go-next.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,192 @@
+<?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"
+   sodipodi:docname="go-next.svg"
+   sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions"
+   inkscape:version="0.46"
+   sodipodi:version="0.32"
+   id="svg11300"
+   height="48"
+   width="48"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000"
+   version="1.0"
+   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="perspective23" />
+    <linearGradient
+       id="linearGradient2591">
+      <stop
+         style="stop-color:#73d216"
+         offset="0"
+         id="stop2593" />
+      <stop
+         style="stop-color:#4e9a06"
+         offset="1.0000000"
+         id="stop2595" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8662"
+       inkscape:collect="always">
+      <stop
+         id="stop8664"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop8666"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8650"
+       inkscape:collect="always">
+      <stop
+         id="stop8652"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop8654"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.046729,-3.749427e-16,2.853404e-16,1.557610,-19.51799,3.452086)"
+       r="17.171415"
+       fy="2.8969381"
+       fx="19.701141"
+       cy="2.8969381"
+       cx="19.701141"
+       id="radialGradient8656"
+       xlink:href="#linearGradient8650"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,2.511012e-15,16.87306)"
+       r="15.644737"
+       fy="36.421127"
+       fx="24.837126"
+       cy="36.421127"
+       cx="24.837126"
+       id="radialGradient8668"
+       xlink:href="#linearGradient8662"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2591"
+       id="radialGradient2597"
+       cx="22.291636"
+       cy="32.797512"
+       fx="22.291636"
+       fy="32.797512"
+       r="16.9562"
+       gradientTransform="matrix(0.843022,1.871885e-16,-2.265228e-16,1.020168,4.499298,1.381992)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="30"
+     inkscape:window-x="0"
+     inkscape:window-height="818"
+     inkscape:window-width="1280"
+     inkscape:showpageshadow="false"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:cy="27.398876"
+     inkscape:cx="20.508639"
+     inkscape:zoom="11.313708"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.25490196"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     fill="#4e9a06"
+     stroke="#4e9a06" />
+  <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:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:title>Go Next</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>go</rdf:li>
+            <rdf:li>next</rdf:li>
+            <rdf:li>right</rdf:li>
+            <rdf:li>arrow</rdf:li>
+            <rdf:li>pointer</rdf:li>
+            <rdf:li>&gt;</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </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"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <path
+       transform="matrix(1.271186,0.000000,0.000000,1.271186,-8.119376,-15.10179)"
+       d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1  9.1923885,36.421127 A 15.644737 8.3968935 0 1 1  40.481863 36.421127 z"
+       sodipodi:ry="8.3968935"
+       sodipodi:rx="15.644737"
+       sodipodi:cy="36.421127"
+       sodipodi:cx="24.837126"
+       id="path8660"
+       style="opacity:0.29946522;color:#000000;fill:url(#radialGradient8668);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:nodetypes="cccccccc"
+       id="path8643"
+       d="M 8.5541875,15.517348 L 8.5541875,32.511768 L 21.538,32.511768 L 21.538,41.056806 L 41.497835,24.150365 L 21.41919,7.1251168 L 21.41919,15.522652 L 8.5541875,15.517348 z "
+       style="opacity:1;color:#000000;fill:url(#radialGradient2597);fill-opacity:1;fill-rule:evenodd;stroke:#3a7304;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       sodipodi:nodetypes="cccccc"
+       id="path8645"
+       d="M 21.962385,8.2485033 L 21.962385,16.054978 L 9.1452151,16.054978 L 9.1452151,25.095691 C 26.895215,27.095691 25.778752,17.640403 40.528752,24.140403 L 21.962385,8.2485033 z "
+       style="opacity:0.5080214;color:#000000;fill:url(#radialGradient8656);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       style="opacity:0.48128339;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 9.537702,16.561892 L 9.537702,31.546332 L 22.523069,31.546332 L 22.523069,38.941498 L 40.001083,24.145807 L 22.507108,9.3654066 L 22.507108,16.566789 L 9.537702,16.561892 z "
+       id="path8658"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
Binary file libgui/src/icons/go-previous.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/go-previous.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,854 @@
+<?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"
+   sodipodi:docname="go-previous.svg"
+   sodipodi:docbase="/home/andreas/projekt/tango/scalable"
+   inkscape:version="0.46"
+   sodipodi:version="0.32"
+   id="svg11300"
+   height="48px"
+   width="48px"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-ydpi="90.000000"
+   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="perspective128" />
+    <linearGradient
+       id="linearGradient2591">
+      <stop
+         style="stop-color:#73d216"
+         offset="0"
+         id="stop2593" />
+      <stop
+         style="stop-color:#4e9a06"
+         offset="1.0000000"
+         id="stop2595" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10314">
+      <stop
+         style="stop-color:#7ea5d6;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop10316" />
+      <stop
+         style="stop-color:#467ec5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop10318" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8938">
+      <stop
+         id="stop8940"
+         offset="0.0000000"
+         style="stop-color:#fdc674;stop-opacity:1.0000000;" />
+      <stop
+         id="stop8942"
+         offset="1.0000000"
+         style="stop-color:#d88103;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8662"
+       inkscape:collect="always">
+      <stop
+         id="stop8664"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop8666"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8650"
+       inkscape:collect="always">
+      <stop
+         id="stop8652"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop8654"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7636"
+       inkscape:collect="always">
+      <stop
+         id="stop7638"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop7640"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7614">
+      <stop
+         id="stop7616"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.21590909"
+         id="stop7649" />
+      <stop
+         style="stop-color:#838383;stop-opacity:1.0000000;"
+         offset="0.50000000"
+         id="stop7632" />
+      <stop
+         id="stop7618"
+         offset="1"
+         style="stop-color:#838383;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7608">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop7610" />
+      <stop
+         id="stop7622"
+         offset="0.46022728"
+         style="stop-color:#e3e3e3;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#dadada;stop-opacity:0.67058824;"
+         offset="0.61970556"
+         id="stop7624" />
+      <stop
+         style="stop-color:#d1d1d1;stop-opacity:0.34285715;"
+         offset="1.0000000"
+         id="stop7612" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7602">
+      <stop
+         id="stop7604"
+         offset="0.0000000"
+         style="stop-color:#f6f6f6;stop-opacity:1.0000000;" />
+      <stop
+         id="stop7606"
+         offset="1.0000000"
+         style="stop-color:#e0e0e0;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7586">
+      <stop
+         id="stop7588"
+         offset="0.0000000"
+         style="stop-color:#525252;stop-opacity:1.0000000;" />
+      <stop
+         id="stop7590"
+         offset="1.0000000"
+         style="stop-color:#000000;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient12836">
+      <stop
+         style="stop-color:#515152;stop-opacity:1;"
+         offset="0"
+         id="stop12838" />
+      <stop
+         style="stop-color:#515152;stop-opacity:0;"
+         offset="1"
+         id="stop12840" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12828">
+      <stop
+         style="stop-color:#cccccd;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop12830" />
+      <stop
+         id="stop12862"
+         offset="0.0000000"
+         style="stop-color:#adadae;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#8f8f90;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop12832" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12810">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop12812" />
+      <stop
+         style="stop-color:#e5e5e5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop12814" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11625">
+      <stop
+         style="stop-color:#fce94f;stop-opacity:1;"
+         offset="0"
+         id="stop11627" />
+      <stop
+         style="stop-color:#fce94f;stop-opacity:0;"
+         offset="1"
+         id="stop11629" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11615">
+      <stop
+         style="stop-color:#636363;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11617" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11619" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11602">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11604" />
+      <stop
+         style="stop-color:#c5c5c5;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11606" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11594">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop11596" />
+      <stop
+         style="stop-color:#d1d1d1;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11598" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11520">
+      <stop
+         style="stop-color:#fbfbfb;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop11522" />
+      <stop
+         style="stop-color:#dcdcdc;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop11524" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11508">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11510" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11512" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11494">
+      <stop
+         style="stop-color:#ef2929;stop-opacity:1;"
+         offset="0"
+         id="stop11496" />
+      <stop
+         style="stop-color:#ef2929;stop-opacity:0;"
+         offset="1"
+         id="stop11498" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient11415">
+      <stop
+         style="stop-color:#204a87;stop-opacity:0.0000000;"
+         offset="0.0000000"
+         id="stop11417" />
+      <stop
+         id="stop11423"
+         offset="0.50000000"
+         style="stop-color:#204a87;stop-opacity:1.0000000;" />
+      <stop
+         style="stop-color:#204a87;stop-opacity:0;"
+         offset="1"
+         id="stop11419" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient11399">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11401" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11403" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11425"
+       gradientUnits="userSpaceOnUse"
+       x1="15.828360"
+       y1="3.7744560"
+       x2="43.615788"
+       y2="34.462429"
+       gradientTransform="translate(-60.28571,-0.285714)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11427"
+       gradientUnits="userSpaceOnUse"
+       x1="9.6957054"
+       y1="9.3458843"
+       x2="35.679932"
+       y2="39.033859"
+       gradientTransform="translate(-60.57143,0.000000)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11415"
+       id="linearGradient11439"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-60.85714,0.428571)"
+       x1="13.267134"
+       y1="19.774456"
+       x2="26.758644"
+       y2="33.462429" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11399"
+       id="radialGradient11441"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.487395,0.000000,20.06483)"
+       cx="12.071428"
+       cy="39.142857"
+       fx="12.071428"
+       fy="39.142857"
+       r="8.5000000" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11494"
+       id="radialGradient11500"
+       cx="27.577173"
+       cy="15.048258"
+       fx="27.577173"
+       fy="15.048258"
+       r="3.8335034"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11494"
+       id="radialGradient11504"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)"
+       cx="27.577173"
+       cy="16.049133"
+       fx="27.577173"
+       fy="16.049133"
+       r="3.8335034" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11508"
+       id="radialGradient11514"
+       cx="30.203562"
+       cy="44.565483"
+       fx="30.203562"
+       fy="44.565483"
+       r="6.5659914"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.166583e-14,29.48178)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11520"
+       id="radialGradient11526"
+       cx="24.445690"
+       cy="35.878170"
+       fx="24.445690"
+       fy="35.878170"
+       r="20.530962"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.995058,-1.535926e-32,0.000000,1.855412,24.94925,-30.20430)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11508"
+       id="radialGradient11532"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,-5.348412e-14,29.48178)"
+       cx="30.203562"
+       cy="44.565483"
+       fx="30.203562"
+       fy="44.565483"
+       r="6.5659914" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11594"
+       id="linearGradient11600"
+       x1="20.092352"
+       y1="8.9471626"
+       x2="31.799011"
+       y2="38.947163"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.045319,0.000000,0.000000,0.957884,48.16627,1.415543)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11520"
+       id="linearGradient11608"
+       x1="24.445671"
+       y1="0.49847093"
+       x2="24.445671"
+       y2="39.447163"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.984324,0.000000,0.000000,0.957884,49.65734,1.415543)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11615"
+       id="radialGradient11621"
+       cx="25.000000"
+       cy="27.749998"
+       fx="25.000000"
+       fy="27.749998"
+       r="4.7500000"
+       gradientTransform="matrix(3.570338,3.171097e-15,-4.005596e-15,4.509900,-64.25843,-94.25499)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11631"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11635"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientTransform="translate(2.000000,0.000000)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11639"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11643"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11647"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(8.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11655"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11657"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11659"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient11661"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12816"
+       x1="65.623963"
+       y1="21.459777"
+       x2="87.528968"
+       y2="21.459777"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12818"
+       gradientUnits="userSpaceOnUse"
+       x1="84.998962"
+       y1="25.209778"
+       x2="62.591469"
+       y2="12.022278" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12828"
+       id="radialGradient12834"
+       cx="88.593018"
+       cy="33.398670"
+       fx="88.593018"
+       fy="33.398670"
+       r="7.0056136"
+       gradientTransform="matrix(0.969219,0.227988,-0.194668,0.827570,9.443870,-15.99848)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12836"
+       id="linearGradient12842"
+       x1="88.750000"
+       y1="31.656250"
+       x2="92.062500"
+       y2="36.656250"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12878"
+       gradientUnits="userSpaceOnUse"
+       x1="65.623963"
+       y1="21.459777"
+       x2="87.528968"
+       y2="21.459777" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12836"
+       id="linearGradient12880"
+       gradientUnits="userSpaceOnUse"
+       x1="88.750000"
+       y1="31.656250"
+       x2="92.062500"
+       y2="36.656250" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12828"
+       id="radialGradient12882"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.969219,0.227988,-0.194668,0.827570,9.443870,-15.99848)"
+       cx="88.593018"
+       cy="33.398670"
+       fx="88.593018"
+       fy="33.398670"
+       r="7.0056136" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient12810"
+       id="linearGradient12884"
+       gradientUnits="userSpaceOnUse"
+       x1="84.998962"
+       y1="25.209778"
+       x2="62.591469"
+       y2="12.022278" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11615"
+       id="radialGradient12894"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.570338,3.171097e-15,-4.005596e-15,4.509900,-64.25843,-94.25499)"
+       cx="25.000000"
+       cy="27.749998"
+       fx="25.000000"
+       fy="27.749998"
+       r="4.7500000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12896"
+       gradientUnits="userSpaceOnUse"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000"
+       gradientTransform="translate(7.267442e-2,-0.181686)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12898"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12900"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12902"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(6.000000,0.000000)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12911"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(7.267442e-2,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12913"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient11625"
+       id="linearGradient12915"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(4.072674,-0.181686)"
+       x1="21.500000"
+       y1="30.000000"
+       x2="21.500000"
+       y2="27.375000" />
+    <linearGradient
+       y2="21.067410"
+       x2="24.445690"
+       y1="33.447811"
+       x1="31.597168"
+       gradientTransform="matrix(0.476329,0.000000,0.000000,0.627721,62.07560,9.156933)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7584"
+       xlink:href="#linearGradient11594"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.407878,2.776254e-16,-5.900875e-16,1.861050,14.96976,-20.55775)"
+       r="6.0270013"
+       fy="29.099535"
+       fx="24.399090"
+       cy="29.099535"
+       cx="24.399090"
+       id="radialGradient7592"
+       xlink:href="#linearGradient7586"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="11.042997"
+       x2="22.585604"
+       y1="34.149513"
+       x1="22.585604"
+       gradientTransform="matrix(1.059222,0.000000,0.000000,0.808101,48.08657,4.001391)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7596"
+       xlink:href="#linearGradient7608"
+       inkscape:collect="always" />
+    <linearGradient
+       gradientTransform="translate(49.32070,0.000000)"
+       gradientUnits="userSpaceOnUse"
+       y2="38.454056"
+       x2="28.284273"
+       y1="28.554562"
+       x1="25.279068"
+       id="linearGradient7642"
+       xlink:href="#linearGradient7636"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.777122,-8.126449e-2,6.891211e-2,2.223012,4.035118,-33.24798)"
+       r="4.4774761"
+       fy="29.609560"
+       fx="24.483574"
+       cy="29.609560"
+       cx="24.483574"
+       id="radialGradient7647"
+       xlink:href="#linearGradient7614"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.046729,-3.749427e-16,-2.853404e-16,1.557610,67.59375,3.275309)"
+       r="17.171415"
+       fy="5.7859797"
+       fx="25.075571"
+       cy="5.7859797"
+       cx="25.075571"
+       id="radialGradient8656"
+       xlink:href="#linearGradient8650"
+       inkscape:collect="always" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,6.772795e-15,16.87306)"
+       r="15.644737"
+       fy="36.421127"
+       fx="24.837126"
+       cy="36.421127"
+       cx="24.837126"
+       id="radialGradient8668"
+       xlink:href="#linearGradient8662"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2591"
+       id="radialGradient2597"
+       cx="22.291636"
+       cy="32.797512"
+       fx="22.291636"
+       fy="32.797512"
+       r="16.956199"
+       gradientTransform="matrix(-0.843022,1.871885e-16,2.265228e-16,1.020168,43.57646,1.205215)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="30"
+     inkscape:window-x="0"
+     inkscape:window-height="818"
+     inkscape:window-width="1280"
+     inkscape:showpageshadow="false"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:cy="25.461494"
+     inkscape:cx="15.433072"
+     inkscape:zoom="16"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.25490196"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     fill="#4e9a06"
+     stroke="#4e9a06" />
+  <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:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:title>Go Previous</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>go</rdf:li>
+            <rdf:li>previous</rdf:li>
+            <rdf:li>left</rdf:li>
+            <rdf:li>arrow</rdf:li>
+            <rdf:li>pointer</rdf:li>
+            <rdf:li>&lt;</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </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"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <path
+       transform="matrix(-1.271186,0.000000,0.000000,1.271186,56.19514,-15.27857)"
+       d="M 40.481863 36.421127 A 15.644737 8.3968935 0 1 1  9.1923885,36.421127 A 15.644737 8.3968935 0 1 1  40.481863 36.421127 z"
+       sodipodi:ry="8.3968935"
+       sodipodi:rx="15.644737"
+       sodipodi:cy="36.421127"
+       sodipodi:cx="24.837126"
+       id="path8660"
+       style="opacity:0.29946521;color:#000000;fill:url(#radialGradient8668);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:nodetypes="cccccccc"
+       id="path8643"
+       d="M 39.490316,15.496821 L 39.490316,32.491241 L 26.537753,32.491241 L 26.537753,40.973779 L 6.577917,23.973588 L 26.531563,6.7295901 L 26.531563,15.502125 L 39.490316,15.496821 z "
+       style="opacity:1.0000000;color:#000000;fill:url(#radialGradient2597);fill-opacity:1.0000000;fill-rule:evenodd;stroke:#3a7304;stroke-width:1.0000004;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       sodipodi:nodetypes="cccccc"
+       id="path8645"
+       d="M 25.988368,7.9779766 L 25.988368,16.034451 L 38.930538,16.034451 L 38.930538,24.918914 C 22.180538,18.668914 22.797001,30.213626 7.547,23.963626 L 25.988368,7.9779766 z "
+       style="opacity:0.50802141;color:#000000;fill:url(#radialGradient8656);fill-opacity:1.0000000;fill-rule:evenodd;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:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible" />
+    <path
+       style="opacity:0.48128340;color:#000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000004;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10.000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:inline;overflow:visible"
+       d="M 38.475551,16.541365 L 38.475551,31.463305 L 25.490184,31.463305 L 25.490184,38.764721 L 8.168419,23.96903 L 25.506145,9.0636299 L 25.506145,16.546262 L 38.475551,16.541365 z "
+       id="path8658"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
--- a/libgui/src/icons/icons_license	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/icons/icons_license	Thu Dec 20 17:18:56 2018 -0500
@@ -17,6 +17,9 @@
 ===========================================
 
 applications-system.svg
+dialog-error.svg
+dialog-information.svg
+dialog-warning.svg
 document-new.svg
 document-open.svg
 document-print.svg
@@ -34,7 +37,10 @@
 folder-new.svg
 go-down.svg
 go-first.svg
+go-home.svg
 go-last.svg
+go-next.svg
+go-previous.svg
 go-up.svg
 preferences-system.svg
 user-home.svg
Binary file libgui/src/icons/zoom-original.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/zoom-original.svg	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<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"
+   version="1.1"
+   id="svg6431"
+   height="48px"
+   width="48px">
+  <defs
+     id="defs6433">
+    <linearGradient
+       id="linearGradient2091">
+      <stop
+         id="stop2093"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop2095"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7916">
+      <stop
+         id="stop7918"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop7920"
+         offset="1.0000000"
+         style="stop-color:#ffffff;stop-opacity:0.34020618;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient8662">
+      <stop
+         id="stop8664"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop8666"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <radialGradient
+       r="15.644737"
+       fy="36.421127"
+       fx="24.837126"
+       cy="36.421127"
+       cx="24.837126"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.536723,-1.018989e-13,16.87306)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient1503"
+       xlink:href="#linearGradient8662" />
+    <linearGradient
+       id="linearGradient2847">
+      <stop
+         id="stop2849"
+         offset="0"
+         style="stop-color:#3465a4;stop-opacity:1;" />
+      <stop
+         id="stop2851"
+         offset="1"
+         style="stop-color:#3465a4;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       y2="26.194071"
+       x2="37.065414"
+       y1="29.729605"
+       x1="37.128052"
+       gradientTransform="matrix(-1.000000,0.000000,0.000000,-1.000000,-1.242480,40.08170)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient1488"
+       xlink:href="#linearGradient2847" />
+    <linearGradient
+       id="linearGradient2831">
+      <stop
+         id="stop2833"
+         offset="0"
+         style="stop-color:#3465a4;stop-opacity:1;" />
+      <stop
+         style="stop-color:#5b86be;stop-opacity:1;"
+         offset="0.33333334"
+         id="stop2855" />
+      <stop
+         id="stop2835"
+         offset="1"
+         style="stop-color:#83a8d8;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       y2="19.115122"
+       x2="15.419417"
+       y1="10.612206"
+       x1="13.478554"
+       gradientTransform="translate(-48.30498,-6.043298)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient1486"
+       xlink:href="#linearGradient2831" />
+    <linearGradient
+       id="linearGradient2380">
+      <stop
+         id="stop2382"
+         offset="0"
+         style="stop-color:#b9cfe7;stop-opacity:1" />
+      <stop
+         id="stop2384"
+         offset="1"
+         style="stop-color:#729fcf;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2682">
+      <stop
+         id="stop2684"
+         offset="0"
+         style="stop-color:#3977c3;stop-opacity:1;" />
+      <stop
+         id="stop2686"
+         offset="1"
+         style="stop-color:#89aedc;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(-48.77039,-5.765705)"
+       gradientUnits="userSpaceOnUse"
+       y2="24.842253"
+       x2="37.124462"
+       y1="31.455952"
+       x1="36.713837"
+       id="linearGradient2688"
+       xlink:href="#linearGradient2682" />
+    <linearGradient
+       id="linearGradient2690">
+      <stop
+         id="stop2692"
+         offset="0"
+         style="stop-color:#c4d7eb;stop-opacity:1;" />
+      <stop
+         id="stop2694"
+         offset="1"
+         style="stop-color:#c4d7eb;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(-48.77039,-5.765705)"
+       gradientUnits="userSpaceOnUse"
+       y2="24.842253"
+       x2="37.124462"
+       y1="30.748846"
+       x1="32.647972"
+       id="linearGradient2696"
+       xlink:href="#linearGradient2690" />
+    <linearGradient
+       id="linearGradient2871">
+      <stop
+         id="stop2873"
+         offset="0"
+         style="stop-color:#3465a4;stop-opacity:1;" />
+      <stop
+         id="stop2875"
+         offset="1"
+         style="stop-color:#3465a4;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2402">
+      <stop
+         id="stop2404"
+         offset="0"
+         style="stop-color:#729fcf;stop-opacity:1;" />
+      <stop
+         id="stop2406"
+         offset="1"
+         style="stop-color:#528ac5;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       y2="26.048164"
+       x2="52.854097"
+       y1="26.048164"
+       x1="5.9649176"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient1493"
+       xlink:href="#linearGradient2797" />
+    <linearGradient
+       id="linearGradient2797">
+      <stop
+         id="stop2799"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop2801"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       y2="26.048164"
+       x2="52.854097"
+       y1="26.048164"
+       x1="5.9649176"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient1491"
+       xlink:href="#linearGradient2797" />
+    <linearGradient
+       id="linearGradient7179">
+      <stop
+         id="stop7181"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop7183"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2316">
+      <stop
+         id="stop2318"
+         offset="0"
+         style="stop-color:#000000;stop-opacity:1;" />
+      <stop
+         id="stop2320"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0.65979379;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1322">
+      <stop
+         style="stop-color:#729fcf"
+         offset="0.0000000"
+         id="stop1324" />
+      <stop
+         style="stop-color:#5187d6;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop1326" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="translate(-16.158044,-13.57119)"
+       gradientUnits="userSpaceOnUse"
+       y2="48.547989"
+       x2="45.918697"
+       y1="36.422989"
+       x1="34.892849"
+       id="linearGradient4975"
+       xlink:href="#linearGradient1322" />
+    <linearGradient
+       gradientUnits="userSpaceOnUse"
+       y2="23.554308"
+       x2="22.374878"
+       y1="13.604306"
+       x1="13.435029"
+       id="linearGradient7185"
+       xlink:href="#linearGradient7179" />
+    <linearGradient
+       gradientTransform="matrix(-1.000000,0.000000,0.000000,-1.000000,47.93934,50.02474)"
+       y2="23.554308"
+       x2="22.374878"
+       y1="13.604306"
+       x1="13.435029"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7189"
+       xlink:href="#linearGradient7179" />
+    <linearGradient
+       y2="20.60858"
+       x2="15.984863"
+       y1="36.061237"
+       x1="62.513836"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7180"
+       xlink:href="#linearGradient2380" />
+    <linearGradient
+       y2="50.939667"
+       x2="45.380436"
+       y1="45.264122"
+       x1="46.834816"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7182"
+       xlink:href="#linearGradient2871" />
+    <linearGradient
+       y2="26.649362"
+       x2="53.588622"
+       y1="23.667896"
+       x1="18.935766"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7184"
+       xlink:href="#linearGradient2402" />
+    <linearGradient
+       y2="50.939667"
+       x2="45.380436"
+       y1="45.264122"
+       x1="46.834816"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient7186"
+       xlink:href="#linearGradient2871" />
+    <linearGradient
+       gradientTransform="translate(1.8597996)"
+       gradientUnits="userSpaceOnUse"
+       y2="34.976799"
+       x2="27.900846"
+       y1="22.851799"
+       x1="16.874998"
+       id="linearGradient7922"
+       xlink:href="#linearGradient7916" />
+    <radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.4184041,0.02503119,-0.01273728,0.42257812,-7.1268356,21.308007)"
+       r="10.319340"
+       fy="35.127438"
+       fx="23.070683"
+       cy="35.127438"
+       cx="23.070683"
+       id="radialGradient2097"
+       xlink:href="#linearGradient2091" />
+  </defs>
+  <metadata
+     id="metadata6436">
+    <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>
+        <dc:date>2006-01-04</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Andreas Nilsson</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://tango-project.org</dc:source>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>add</rdf:li>
+            <rdf:li>plus</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+        <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
+     id="layer1">
+    <ellipse
+       ry="4.5910006"
+       rx="16.000002"
+       cy="36.646465"
+       cx="24.975922"
+       id="path1361"
+       style="opacity:0.10824741;fill:url(#radialGradient2097);fill-opacity:1;stroke:none;stroke-width:5.25468683;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <path
+       id="text1314"
+       d="m 29.374162,37.542682 v -9.02696 l 0.01114,-0.04018 v -6.995324 h -0.0022 l -0.0089,-9.96017 -4.565294,0.01116 -2.080467,0.04553 -5.868635,2.830125 -0.01961,8.166666 5.531084,-2.45098 0.0067,17.393347 z"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:59.90107727px;line-height:125%;font-family:'Bitstream Vera Sans';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#75a1d0;fill-opacity:1;stroke:#3465a4;stroke-width:1.00000036px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       id="path7076"
+       d="m 28.358508,36.53392 v -9.034182 0 l 0.0089,-5.024429 v 0 -9.994974 L 23.372574,12.498195 17.859806,15 v 6 L 23.350002,18.593137 23.392894,32 l -0.01339,4.502672 z"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:59.90107727px;line-height:125%;font-family:'Bitstream Vera Sans';text-align:start;writing-mode:lr-tb;text-anchor:start;opacity:0.40860219;fill:url(#linearGradient4975);fill-opacity:1;stroke:url(#linearGradient7922);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       id="path7914"
+       d="m 22.859806,25 c 0,1.9375 5.984375,-0.96875 5.984375,-0.03125 v -3 L 28.859806,22 l 0.02124,-9.982614 -2.521242,-0.0087 -3.45915,-0.0087 -5.54085,2.685751 -0.0098,6.989086 5.509804,-2.287582 V 24 Z"
+       style="opacity:0.31182796;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+  </g>
+</svg>
--- a/libgui/src/m-editor/file-editor-interface.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/file-editor-interface.h	Thu Dec 20 17:18:56 2018 -0500
@@ -37,9 +37,8 @@
   public:
 
     file_editor_interface (QWidget *p)
-      : octave_dock_widget (p)
+      : octave_dock_widget ("FileEditor", p)
     {
-      setObjectName ("FileEditor");
     }
 
     virtual ~file_editor_interface (void) = default;
@@ -74,6 +73,8 @@
 
   public slots:
 
+    virtual void handle_file_remove (const QString& o, const QString& n) = 0;
+
     virtual void request_new_file (const QString& command = QString ()) = 0;
 
     virtual void request_open_file (const QString& openFileName,
@@ -82,7 +83,8 @@
                                     bool debug_pointer = false,
                                     bool breakpoint_marker = false,
                                     bool insert = true,
-                                    const QString& cond = "") = 0;
+                                    const QString& cond = "",
+                                    int index = -1) = 0;
   };
 }
 
--- a/libgui/src/m-editor/file-editor-tab.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/file-editor-tab.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -60,7 +60,9 @@
 #include <QDialogButtonBox>
 #include <QPushButton>
 
+#include "gui-preferences.h"
 #include "resource-manager.h"
+
 #include "file-editor-tab.h"
 #include "file-editor.h"
 #include "octave-txt-lexer.h"
@@ -70,7 +72,6 @@
 
 #include "bp-table.h"
 #include "call-stack.h"
-#include "defaults.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
 #include "oct-map.h"
@@ -80,7 +81,6 @@
 #include "unwind-prot.h"
 #include "utils.h"
 #include "version.h"
-#include "octave-settings.h"
 
 namespace octave
 {
@@ -112,6 +112,9 @@
     _bp_conditions.clear ();
     m_bp_restore_count = 0;
 
+    // Initialize last modification date to now
+    m_last_modified = QDateTime::currentDateTimeUtc();
+
     connect (_edit_area, SIGNAL (cursorPositionChanged (int, int)),
              this, SLOT (handle_cursor_moved (int,int)));
 
@@ -394,8 +397,8 @@
                 frame.protect_var (buffer_error_messages);
                 buffer_error_messages++;
 
-                octave::bp_table& bptab
-                  = octave::__get_bp_table__ ("handle_context_menu_break_condition");
+                bp_table& bptab
+                  = __get_bp_table__ ("handle_context_menu_break_condition");
 
                 bptab.condition_valid (new_condition.toStdString ());
                 valid = true;
@@ -431,8 +434,11 @@
     QStringList trackedFiles = _file_system_watcher.files ();
     if (! trackedFiles.isEmpty ())
       _file_system_watcher.removePath (_file_name);
-    if (! fileName.isEmpty ())
+    if (! fileName.isEmpty () && QFile::exists (fileName))
+    {
       _file_system_watcher.addPath (fileName);
+      m_last_modified =  QFileInfo (fileName).lastModified ().toUTC ();
+    }
 
     // update lexer and file name variable if file name changes
     if (_file_name != fileName)
@@ -471,10 +477,10 @@
   bool file_editor_tab::unchanged_or_saved (void)
   {
     bool retval = true;
-    if (_edit_area->isModified ())
+    if (_edit_area->isModified () || ! valid_file_name ())
       {
         int ans = QMessageBox::question (nullptr, tr ("Octave Editor"),
-                                         tr ("Cannot add breakpoint to modified file.\n"
+                                         tr ("Cannot add breakpoint to modified or unnamed file.\n"
                                              "Save and add breakpoint, or cancel?"),
                                          QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Save);
 
@@ -710,8 +716,7 @@
                 add_octave_apis (Fiskeyword ());            // add new entries
 
                 interpreter& interp
-                  = __get_interpreter__ (
-                      "file_editor_tab::update_lexer_settings");
+                  = __get_interpreter__ ("file_editor_tab::update_lexer_settings");
 
                 if (octave_builtins)
                   add_octave_apis (F__builtins__ (interp));       // add new entries
@@ -992,8 +997,7 @@
 
     if (octave_qt_link::file_in_path (info.file, info.dir))
       {
-        octave::bp_table& bptab
-          = octave::__get_bp_table__ ("octave_qt_link::file_in_path");
+        bp_table& bptab = __get_bp_table__ ("octave_qt_link::file_in_path");
 
         bptab.add_breakpoint (info.function_name, line_info, info.condition);
       }
@@ -1006,8 +1010,7 @@
 
     if (octave_qt_link::file_in_path (info.file, info.dir))
       {
-        octave::bp_table& bptab
-          = octave::__get_bp_table__ ("remove_breakpoint_callback");
+        bp_table& bptab = __get_bp_table__ ("remove_breakpoint_callback");
 
         bptab.remove_breakpoint (info.function_name, line_info);
       }
@@ -1017,8 +1020,7 @@
   {
     if (octave_qt_link::file_in_path (info.file, info.dir))
       {
-        octave::bp_table& bptab
-          = octave::__get_bp_table__ ("remove_all_breakpoints_callback");
+        bp_table& bptab = __get_bp_table__ ("remove_all_breakpoints_callback");
 
         bptab.remove_all_breakpoints_in_file (info.function_name, true);
       }
@@ -1440,13 +1442,13 @@
             used_comment_str = QInputDialog::getText (
                                  this, tr ("Comment selected text"),
                                  tr ("Comment string to use:\n"), QLineEdit::Normal,
-                                 settings->value (oct_last_comment_str, comment_str.at (0)).toString (),
+                                 settings->value (ed_last_comment_str, comment_str.at (0)).toString (),
                                  &ok);
 
             if ((! ok) || used_comment_str.isEmpty ())
               return;  // No input, do nothing
             else
-              settings->setValue (oct_last_comment_str, used_comment_str);  // Store last
+              settings->setValue (ed_last_comment_str, used_comment_str);  // Store last
           }
       }
     else
@@ -1732,18 +1734,63 @@
     else
       file_to_load = fileName;
     QFile file (file_to_load);
-    if (! file.open (QFile::ReadOnly))
+    if (!file.open(QIODevice::ReadOnly))
       return file.errorString ();
 
-    // read the file
-    QTextStream in (&file);
-    // set the desired codec
-    QTextCodec *codec = QTextCodec::codecForName (_encoding.toLatin1 ());
-    in.setCodec (codec);
+    int col = 0, line = 0;
+    if (fileName == _file_name)
+      {
+        // We have to reload the current file, thus get current cursor position
+        line = _line;
+        col = _col;
+      }
 
     QApplication::setOverrideCursor (Qt::WaitCursor);
-    _edit_area->setText (in.readAll ());
+
+    // read the file binary, decoding later
+    const QByteArray text_data = file.readAll ();
+
+    // decode
+    QTextCodec::ConverterState st;
+    QTextCodec *codec = QTextCodec::codecForName (_encoding.toLatin1 ());
+    if (codec == nullptr)
+      codec = QTextCodec::codecForLocale ();
+
+    const QString text = codec->toUnicode(text_data.constData(),
+                                          text_data.size(), &st);
+
+    // Decoding with invalid characters?
+    if (st.invalidChars > 0)
+      {
+        // Set read only
+        _edit_area->setReadOnly (true);
+
+        // Message box for user decision
+        QString msg = tr ("There were problems reading the file\n"
+                          "%1\n"
+                          "with the selected encoding %2.\n\n"
+                          "Modifying and saving the file might "
+                          "cause data loss!")
+                          .arg (file_to_load).arg (_encoding);
+        QMessageBox *msg_box = new QMessageBox ();
+        msg_box->setIcon (QMessageBox::Warning);
+        msg_box->setText (msg);
+        msg_box->setWindowTitle (tr ("Octave Editor"));
+        msg_box->addButton (tr ("&Edit anyway"), QMessageBox::YesRole);
+        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 *)));
+
+        msg_box->setWindowModality (Qt::WindowModal);
+        msg_box->setAttribute (Qt::WA_DeleteOnClose);
+        msg_box->show ();
+      }
+
+    _edit_area->setText (text);
     _edit_area->setEolMode (detect_eol_mode ());
+
     QApplication::restoreOverrideCursor ();
 
     _copy_available = false;     // no selection yet available
@@ -1753,6 +1800,8 @@
 
     update_eol_indicator ();
 
+    _edit_area->setCursorPosition (line, col);
+
     // FIXME: (BREAKPOINTS) At this point it would be nice to put any set
     // breakpoints on the margin.  In order to do this, somehow the
     // "dbstatus" command needs to be accessed.  All it would require is a
@@ -1774,6 +1823,67 @@
     return QString ();
   }
 
+  void file_editor_tab::handle_decode_warning_answer (QAbstractButton *btn)
+  {
+    QString txt = btn->text ();
+
+    if (txt == tr ("&Close"))
+      {
+        // Just close the file
+        close ();
+        return;
+      }
+
+    if (txt == tr ("Chan&ge encoding"))
+      {
+        // Dialog for reloading the file with another encoding
+        QDialog dlg;
+        dlg.setWindowTitle (tr ("Select new default encoding"));
+
+        QLabel *text
+          = new QLabel (tr ("Please select a new encoding\n"
+                            "for reloading the current file.\n\n"
+                            "This does not change the default encoding.\n"));
+
+        QComboBox *enc_combo = new QComboBox ();
+        resource_manager::combo_encoding (enc_combo);
+        _new_encoding = enc_combo->currentText ();
+        connect (enc_combo, SIGNAL (currentTextChanged (const QString&)),
+                 this , SLOT (handle_current_enc_changed (const QString&)));
+
+        QDialogButtonBox *buttons
+          = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+                                  Qt::Horizontal);
+        connect (buttons, SIGNAL (accepted ()), &dlg, SLOT (accept ()));
+        connect (buttons, SIGNAL (rejected ()), &dlg, SLOT (reject ()));
+
+        QGridLayout *main_layout = new QGridLayout;
+        main_layout->setSizeConstraint (QLayout::SetFixedSize);
+        main_layout->addWidget (text, 0, 0);
+        main_layout->addWidget (enc_combo, 1, 0);
+        main_layout->addWidget (buttons, 2, 0);
+        dlg.setLayout (main_layout);
+
+        int answer = dlg.exec ();
+
+        if (answer == QDialog::Accepted)
+          {
+            // Reload the file with new encoding but using the same tab
+            QString reload_file_name = _file_name;  // store file name
+            _file_name = "";  // force reuse of this tab when opening a new file
+            emit request_open_file (reload_file_name, _new_encoding);
+          }
+      }
+
+    // Continue editing, set writable again
+    _edit_area->setReadOnly (false);
+  }
+
+  void file_editor_tab::handle_current_enc_changed (const QString& enc)
+  {
+    _new_encoding = enc;
+  }
+
   QsciScintilla::EolMode file_editor_tab::detect_eol_mode (void)
   {
     QByteArray text = _edit_area->text ().toLatin1 ();
@@ -1836,30 +1946,34 @@
       }
   }
 
-  // FIXME: See patch #8016 for a general way to get Octave results from
-  // commands processed in the background, e.g., dbstatus.
-  void file_editor_tab::handle_octave_result (QObject *requester,
-                                              QString& command,
-                                              octave_value_list&)
+  void file_editor_tab::update_breakpoints ()
   {
-    // Check if this object initiated the command.
-    if (requester == this)
+    if (_file_name.isEmpty ())
+      return;
+
+    octave_value_list argout = ovl ();
+
+    // Create and queue the command object
+    octave_cmd_builtin *cmd = new octave_cmd_builtin (&Fdbstatus, ovl (), 1,
+        this, SLOT (update_breakpoints_handler (const octave_value_list&)));
+
+    emit request_queue_cmd (cmd);
+  }
+
+  void file_editor_tab::update_breakpoints_handler (const octave_value_list& argout)
+  {
+    octave_map dbg = argout(0).map_value ();
+    octave_idx_type n_dbg = dbg.numel ();
+
+    Cell file = dbg.contents ("file");
+    Cell line = dbg.contents ("line");
+    Cell cond = dbg.contents ("cond");
+
+    for (octave_idx_type i = 0; i < n_dbg; i++)
       {
-        if (command == "dbstatus")
-          {
-            // Should be installing breakpoints in this file
-            /*
-              octave:1> result = dbstatus
-              result =
-
-              0x1 struct array containing the fields:
-
-              name
-              file
-              line
-            */
-            // Check for results that match "file".
-          }
+        if (file (i).string_value () == _file_name.toStdString ())
+          do_breakpoint_marker (true, this, line (i).int_value (),
+                                QString::fromStdString (cond (i).string_value ()));
       }
   }
 
@@ -1902,7 +2016,13 @@
     octave_value sym;
     try
       {
-        sym = symtab.find (base_name);
+        // FIXME: maybe we should be looking up functions directly
+        // instead of using a function that can also find variables?
+
+        symbol_scope curr_scope
+          = __get_current_scope__ ("file_editor_tab::exit_debug_and_clear");
+
+        sym = curr_scope.find (base_name);
       }
     catch (const execution_exception& e)
       {
@@ -1940,11 +2060,14 @@
 
             if (ans == QMessageBox::Save)
               {
-                emit execute_command_in_terminal_signal ("dbquit");
+                // add a dbquit command to the queue
+                octave_cmd_debug *cmd = new octave_cmd_debug ("quit", true);
+                emit request_queue_cmd (cmd);
+
                 // Wait until dbquit has actually occurred
                 while (names.numel () > i)
                   {
-                    octave_sleep (0.01);
+                    octave::sleep (0.01);
                     stk = cs.backtrace (nskip, curr_frame, false);
                     names = stk.contents ("name");
                   }
@@ -2089,53 +2212,6 @@
     else
       fileDialog = new QFileDialog (this);
 
-    // Giving trouble under KDE (problem is related to Qt signal handling on unix,
-    // see https://bugs.kde.org/show_bug.cgi?id=260719 ,
-    // it had/has no effect on Windows, though)
-    fileDialog->setOption (QFileDialog::DontUseNativeDialog, true);
-
-    // define a new grid layout with the extra elements
-    QGridLayout *extra = new QGridLayout (fileDialog);
-    QFrame *separator = new QFrame (fileDialog);
-    separator->setFrameShape (QFrame::HLine);   // horizontal line as separator
-    separator->setFrameStyle (QFrame::Sunken);
-
-    // combo box for choosing new line ending chars
-    QLabel *label_eol = new QLabel (tr ("Line Endings:"));
-    QComboBox *combo_eol = new QComboBox ();
-    combo_eol->addItem ("Windows (CRLF)");  // ensure the same order as in
-    combo_eol->addItem ("Mac (CR)");        // the settings dialog
-    combo_eol->addItem ("Unix (LF)");
-    _save_as_desired_eol = _edit_area->eolMode ();      // init with current eol
-    combo_eol->setCurrentIndex (_save_as_desired_eol);
-
-    // combo box for encoding
-    QLabel *label_enc = new QLabel (tr ("File Encoding:"));
-    QComboBox *combo_enc = new QComboBox ();
-    resource_manager::combo_encoding (combo_enc, _encoding);
-
-    // track changes in the combo boxes
-    connect (combo_eol, SIGNAL (currentIndexChanged (int)),
-             this, SLOT (handle_combo_eol_current_index (int)));
-    connect (combo_enc, SIGNAL (currentIndexChanged (QString)),
-             this, SLOT (handle_combo_enc_current_index (QString)));
-
-    // build the extra grid layout
-    extra->addWidget (separator,0,0,1,6);
-    extra->addWidget (label_eol,1,0);
-    extra->addWidget (combo_eol,1,1);
-    extra->addItem   (new QSpacerItem (1,20,QSizePolicy::Fixed,
-                                       QSizePolicy::Fixed), 1,2);
-    extra->addWidget (label_enc,1,3);
-    extra->addWidget (combo_enc,1,4);
-    extra->addItem   (new QSpacerItem (1,20,QSizePolicy::Expanding,
-                                       QSizePolicy::Fixed), 1,5);
-
-    // and add the extra grid layout to the dialog's layout
-    QGridLayout *dialog_layout = dynamic_cast<QGridLayout *> (fileDialog->layout ());
-    dialog_layout->addLayout (extra,dialog_layout->rowCount (),0,
-                              1,dialog_layout->columnCount ());
-
     // add the possible filters and the default suffix
     QStringList filters;
     filters << tr ("Octave Files (*.m)")
@@ -2168,6 +2244,11 @@
     fileDialog->setAcceptMode (QFileDialog::AcceptSave);
     fileDialog->setViewMode (QFileDialog::Detail);
 
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      fileDialog->setOption(QFileDialog::DontUseNativeDialog);
+
     connect (fileDialog, SIGNAL (filterSelected (const QString&)),
              this, SLOT (handle_save_as_filter_selected (const QString&)));
 
@@ -2188,16 +2269,6 @@
     show_dialog (fileDialog, ! valid_file_name ());
   }
 
-  void file_editor_tab::handle_combo_eol_current_index (int index)
-  {
-    _save_as_desired_eol = static_cast<QsciScintilla::EolMode> (index);
-  }
-
-  void file_editor_tab::handle_combo_enc_current_index (QString text)
-  {
-    _new_encoding = text;
-  }
-
   void file_editor_tab::handle_save_as_filter_selected (const QString& filter)
   {
     QFileDialog *file_dialog = qobject_cast<QFileDialog *> (sender ());
@@ -2310,6 +2381,20 @@
 
   void file_editor_tab::file_has_changed (const QString&, bool do_close)
   {
+    bool file_exists = QFile::exists (_file_name);
+
+    if (file_exists && ! do_close)
+      {
+        // Test if file is really modified or if just the timezone has
+        // changed. In the latter, just return without doing anything
+        QDateTime modified = QFileInfo (_file_name).lastModified ().toUTC ();
+
+        if (modified <= m_last_modified)
+          return;
+
+        m_last_modified = modified;
+      }
+
     // Prevent popping up multiple message boxes when the file has
     // been changed multiple times by temporarily removing from the
     // file watcher.
@@ -2317,11 +2402,11 @@
     if (! trackedFiles.isEmpty ())
       _file_system_watcher.removePath (_file_name);
 
-    if (QFile::exists (_file_name) && ! do_close)
+    if (file_exists && ! do_close)
       {
+
         // The file is modified
         if (_always_reload_changed_files)
-
           load_file (_file_name);
 
         else
--- a/libgui/src/m-editor/file-editor-tab.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/file-editor-tab.h	Thu Dec 20 17:18:56 2018 -0500
@@ -23,18 +23,20 @@
 #if ! defined (octave_file_editor_tab_h)
 #define octave_file_editor_tab_h 1
 
+#include <QAbstractButton>
 #include <QWidget>
 #include <QCloseEvent>
+#include <QDateTime>
 #include <QFileSystemWatcher>
 #include <QSettings>
 #include <QFileInfo>
 #include <Qsci/qsciapis.h>
 #include <QStatusBar>
 #include <QLabel>
-#include <QComboBox>
 
 #include "find-dialog.h"
 #include "octave-qscintilla.h"
+#include "octave-cmd.h"
 #include "builtin-defun-decls.h"
 
 #include "marker.h" /* Only needed for typedef of "QIntList", which may be
@@ -64,6 +66,8 @@
     static void reset_cancel (void) {_cancelled = false;}
     static bool was_cancelled (void) {return _cancelled;}
 
+    void update_breakpoints ();
+
   public slots:
 
     void update_window_title (bool modified);
@@ -146,8 +150,7 @@
     void handle_request_add_breakpoint (int line, const QString& cond);
     void handle_request_remove_breakpoint (int line);
 
-    void handle_octave_result (QObject *requester, QString& command,
-                               octave_value_list& result);
+    void update_breakpoints_handler (const octave_value_list& argout);
 
   signals:
 
@@ -160,7 +163,7 @@
     void editor_check_conflict_save (const QString& saveFileName,
                                      bool remove_on_success);
     void run_file_signal (const QFileInfo& info);
-    void request_open_file (const QString&);
+    void request_open_file (const QString&, const QString& = QString ());
     void edit_mfile_request (const QString&, const QString&,
                              const QString&, int);
 
@@ -177,7 +180,7 @@
     void report_marker_linenr (QIntList& lines, QStringList& conditions);
     void remove_position_via_debugger_linenr (int debugger_linenr);
     void remove_all_positions (void);
-    void execute_command_in_terminal_signal (const QString&);
+    void request_queue_cmd (octave_cmd *);
 
     // FIXME: The following is similar to "process_octave_code"
     // signal.  However, currently that signal is connected to
@@ -193,6 +196,9 @@
 
   private slots:
 
+    // When user closes message box for decoding problems
+    void handle_decode_warning_answer (QAbstractButton *btn);
+
     // When user closes message box for reload question.
     void handle_file_reload_answer (int decision);
 
@@ -210,8 +216,9 @@
     void handle_save_file_as_answer_close (const QString& fileName);
     void handle_save_file_as_answer_cancel (void);
     void handle_save_as_filter_selected (const QString& filter);
-    void handle_combo_eol_current_index (int index);
-    void handle_combo_enc_current_index (QString text);
+
+    // When user changes encoding after decoding errors where found
+    void handle_current_enc_changed (const QString& enc);
 
     // When apis preparation has finished and is ready to save
     void save_apis_info (void);
@@ -284,6 +291,7 @@
     QString _ced;
     QString _encoding;
     QString _new_encoding;
+    QDateTime m_last_modified;
 
     bool _long_title;
     bool _copy_available;
--- a/libgui/src/m-editor/file-editor.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/file-editor.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -45,6 +45,8 @@
 #include <Qsci/qscicommandset.h>
 
 #include "main-window.h"
+#include "gui-preferences.h"
+#include "oct-env.h"
 #include "oct-map.h"
 #include "octave-link.h"
 #include "utils.h"
@@ -256,22 +258,27 @@
 
     // get the data from the settings file
     QStringList sessionFileNames
-      = settings->value ("editor/savedSessionTabs",
-                         QStringList ()).toStringList ();
+      = settings->value (ed_session_names.key, ed_session_names.def)
+                         .toStringList ();
 
     QStringList session_encodings
-      = settings->value ("editor/saved_session_encodings",
-                         QStringList ()).toStringList ();
+      = settings->value (ed_session_enc.key, ed_session_enc.def)
+                        .toStringList ();
 
     QStringList session_index
-      = settings->value ("editor/saved_session_tab_index",
-                         QStringList ()).toStringList ();
+      = settings->value (ed_session_ind.key, ed_session_ind.def)
+                         .toStringList ();
+
+    QStringList session_lines
+      = settings->value (ed_session_lines.key, ed_session_lines.def)
+                         .toStringList ();
 
     // fill a list of the struct and sort it (depending on index)
     QList<session_data> s_data;
 
     bool do_encoding = (session_encodings.count () == sessionFileNames.count ());
     bool do_index = (session_index.count () == sessionFileNames.count ());
+    bool do_lines = (session_lines.count () == sessionFileNames.count ());
 
     for (int n = 0; n < sessionFileNames.count (); ++n)
       {
@@ -279,7 +286,10 @@
         if (! file.exists ())
           continue;
 
-        session_data item = { 0, sessionFileNames.at (n), QString ()};
+        session_data item = { 0, -1, sessionFileNames.at (n),
+                              QString (), QString ()};
+        if (do_lines)
+          item.line = session_lines.at (n).toInt ();
         if (do_index)
           item.index = session_index.at (n).toInt ();
         if (do_encoding)
@@ -292,7 +302,8 @@
 
     // finally open the file with the desired encoding in the desired order
     for (int n = 0; n < s_data.count (); ++n)
-      request_open_file (s_data.at (n).file_name, s_data.at (n).encoding);
+      request_open_file (s_data.at (n).file_name, s_data.at (n).encoding,
+                         s_data.at (n).line);
   }
 
   void file_editor::focus (void)
@@ -375,29 +386,42 @@
     QStringList fetFileNames;
     QStringList fet_encodings;
     QStringList fet_index;
+    QStringList fet_lines;
 
     // save all open tabs before they are definitely closed
-    for (editor_tab_map_const_iterator p = m_editor_tab_map.begin ();
-         p != m_editor_tab_map.end (); p++)
+    for (auto p = m_editor_tab_map.cbegin ();
+         p != m_editor_tab_map.cend (); p++)
       {
         QString file_name = p->first;   // get file name of tab
         if (! file_name.isEmpty ())      // do not append unnamed files
           {
             fetFileNames.append (file_name);
             fet_encodings.append (m_editor_tab_map[file_name].encoding);
+
             QString index;
+            file_editor_tab *editor_tab
+              = static_cast<file_editor_tab *> (m_editor_tab_map[file_name].fet_ID);
             fet_index.append (index.setNum
-                              (m_tab_widget->indexOf (m_editor_tab_map[file_name].fet_ID)));
+                              (m_tab_widget->indexOf (editor_tab)));
+
+            int l, c;
+            editor_tab->qsci_edit_area ()->getCursorPosition (&l, &c);
+            fet_lines.append (index.setNum (l + 1));
           }
       }
 
-    settings->setValue ("editor/savedSessionTabs", fetFileNames);
-    settings->setValue ("editor/saved_session_encodings", fet_encodings);
-    settings->setValue ("editor/saved_session_tab_index", fet_index);
+    settings->setValue (ed_session_names.key, fetFileNames);
+    settings->setValue (ed_session_enc.key, fet_encodings);
+    settings->setValue (ed_session_ind.key, fet_index);
+    settings->setValue (ed_session_lines.key, fet_lines);
     settings->sync ();
 
     // Finally close all the tabs and return indication that we can exit
-    // the application or close the editor
+    // the application or close the editor.
+    // Closing and deleting the tabs makes the editor visible. In case it was
+    // hidden before, this state has to be restored afterwards
+    bool vis = isVisible ();
+
     for (int i = m_tab_widget->count () - 1; i >= 0; i--)
       {
         // backwards loop since m_tab_widget->count () changes during the loop
@@ -405,6 +429,8 @@
         m_tab_widget->removeTab (i);
       }
 
+    setVisible (vis);
+
     return true;
   }
 
@@ -918,44 +944,79 @@
   void file_editor::handle_file_remove (const QString& old_name,
                                         const QString& new_name)
   {
-    // Clear old lsit of files to reload
+    // Clear old list of file data and declare a structure for file data
     m_tmp_closed_files.clear ();
-
-    // Check if old name is a file or directory
-    QFileInfo old (old_name);
-    if (old.isDir ())
-      {
-        // Call the function which handles directories and return
-        handle_dir_remove (old_name, new_name);
-        return;
-      }
-
-    // Is old file open?
-    file_editor_tab *editor_tab
-      = static_cast<file_editor_tab *> (find_tab_widget (old_name));
-
-    if (editor_tab)
+    session_data f_data;
+
+    // Preprocessing old name(s)
+    QString old_name_clean = old_name.trimmed ();
+    int s = old_name_clean.size ();
+
+    if (old_name_clean.at (0) == QChar ('\"') &&
+        old_name_clean.at (s - 1) == QChar ('\"'))
+      old_name_clean = old_name_clean.mid (1, s - 2);
+
+    QStringList old_names = old_name_clean.split ("\" \"");
+
+    // Check if new name is a file or directory
+    QFileInfo newf (new_name);
+    bool new_is_dir = newf.isDir ();
+
+    // Now loop over all old files/dirs (several files by movefile ())
+    for (int i = 0; i < old_names.count (); i++)
       {
-        // Yes, close it silently
-        m_no_focus = true;  // Remember for not focussing editor
-        editor_tab->file_has_changed (QString (), true);  // Close the tab
-        m_no_focus = false;  // Back to normal
-
-        m_tmp_closed_files << old_name;  // for reloading if error removing
-
-        if (! new_name.isEmpty ())
-          m_tmp_closed_files << new_name;  // store new name
+        // Check if old name is a file or directory
+        QFileInfo old (old_names.at (i));
+
+        if (old.isDir ())
+          {
+            // Call the function which handles directories and return
+            handle_dir_remove (old_names.at (i), new_name);
+          }
         else
-          m_tmp_closed_files << ""; // no new name, just removing this file
-
-        // Get and store the related encoding
-        for (editor_tab_map_const_iterator p = m_editor_tab_map.begin ();
-             p != m_editor_tab_map.end (); p++)
           {
-            if (editor_tab == p->second.fet_ID)
+            // It is a single file. Is it open?
+            file_editor_tab *editor_tab
+              = static_cast<file_editor_tab *> (find_tab_widget (old_names.at (i)));
+
+            if (editor_tab)
               {
-                m_tmp_closed_files << p->second.encoding;
-                break;
+                // YES: Get and store the related encoding
+                for (editor_tab_map_const_iterator p = m_editor_tab_map.begin ();
+                      p != m_editor_tab_map.end (); p++)
+                  {
+                    if (editor_tab == p->second.fet_ID)
+                      {
+                        // Get index and line
+                        f_data.encoding = p->second.encoding;
+                        f_data.index = m_tab_widget->indexOf (editor_tab);
+                        int l, c;
+                        editor_tab->qsci_edit_area ()->getCursorPosition (&l, &c);
+                        f_data.line = l + 1;
+                        break;
+                      }
+                  }
+
+                // Close it silently
+                m_no_focus = true;  // Remember for not focussing editor
+                editor_tab->file_has_changed (QString (), true);  // Close the tab
+                m_no_focus = false;  // Back to normal
+
+                // For reloading old file if error while removing
+                f_data.file_name = old_names.at (i);
+                // For reloading new file (if new_file is not empty)
+                if (new_is_dir)
+                  {
+                    std::string ndir = new_name.toStdString ();
+                    std::string ofile = old.fileName ().toStdString ();
+                    f_data.new_file_name = QString::fromStdString (
+                      octave::sys::env::make_absolute (ofile, ndir));
+                  }
+                else
+                  f_data.new_file_name = new_name;
+
+                // Add file data to list
+                m_tmp_closed_files << f_data;
               }
           }
       }
@@ -965,27 +1026,47 @@
   void file_editor::handle_file_renamed (bool load_new)
   {
     m_no_focus = true;  // Remember for not focussing editor
-    for (int i = 0; i < m_tmp_closed_files.count (); i = i + 3)
+
+    // Loop over all file that have to be reloaded. Start at the end of the
+    // list, otherwise the stored indexes are not correct
+    for (int i = m_tmp_closed_files.count () - 1; i >= 0; i--)
       {
-        if (! m_tmp_closed_files.at (i + load_new).isEmpty ())
-          request_open_file (m_tmp_closed_files.at (i + load_new),
-                             m_tmp_closed_files.at (i+2));
+        // Load old or new file
+        if (load_new)
+          {
+            if (! m_tmp_closed_files.at (i).new_file_name.isEmpty ())
+              request_open_file (m_tmp_closed_files.at (i).new_file_name,
+                                 m_tmp_closed_files.at (i).encoding,
+                                 m_tmp_closed_files.at (i).line,
+                                 false, false, true, "",
+                                 m_tmp_closed_files.at (i).index);
+          }
+        else
+          {
+            request_open_file (m_tmp_closed_files.at (i).file_name,
+                                 m_tmp_closed_files.at (i).encoding,
+                                 m_tmp_closed_files.at (i).line,
+                                 false, false, true, "",
+                                 m_tmp_closed_files.at (i).index);
+          }
+
       }
+
     m_no_focus = false;  // Back to normal focus
+
+    // Clear the list of file data
+    m_tmp_closed_files.clear ();
   }
 
   void file_editor::notice_settings (const QSettings *settings)
   {
-    int icon_size_settings = settings->value ("toolbar_icon_size",0).toInt ();
+    int size_idx = settings->value (global_icon_size.key,
+                                    global_icon_size.def).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 (QStyle::PM_ToolBarIconSize);
-
-    if (icon_size_settings == 1)
-      icon_size = st->pixelMetric (QStyle::PM_LargeIconSize);
-    else if (icon_size_settings == -1)
-      icon_size = st->pixelMetric (QStyle::PM_SmallIconSize);
-
-    m_tool_bar->setIconSize (QSize (icon_size,icon_size));
+    int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
+    m_tool_bar->setIconSize (QSize (icon_size, icon_size));
 
     int tab_width_min = settings->value ("editor/notebook_tab_width_min", 160)
                         .toInt ();
@@ -1179,11 +1260,15 @@
                                        const QString& encoding,
                                        int line, bool debug_pointer,
                                        bool breakpoint_marker, bool insert,
-                                       const QString& cond)
+                                       const QString& cond, int index)
   {
     if (call_custom_editor (openFileName, line))
       return;   // custom editor called
 
+    QSettings *settings = resource_manager::get_settings ();
+    bool show_dbg_file
+      = settings->value (ed_show_dbg_file.key, ed_show_dbg_file.def).toBool ();
+
     if (openFileName.isEmpty ())
       {
         // This happens if edit is calles without an argument
@@ -1211,7 +1296,7 @@
                   emit fetab_do_breakpoint_marker (insert, tab, line, cond);
               }
 
-            if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ()))
+            if (show_dbg_file && ! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ()))
               {
                 emit fetab_set_focus (tab);
                 focus ();
@@ -1219,6 +1304,12 @@
           }
         else
           {
+            if (! show_dbg_file && (breakpoint_marker  || debug_pointer))
+              return;   // Do not open a file for showing dbg markers
+
+            if (breakpoint_marker && ! insert)
+              return;   // Never open a file when removing breakpoints
+
             file_editor_tab *fileEditorTab = nullptr;
             // Reuse <unnamed> tab if it hasn't yet been modified.
             bool reusing = false;
@@ -1245,7 +1336,7 @@
                     // Supply empty title then have the file_editor_tab update
                     // with full or short name.
                     if (! reusing)
-                      add_file_editor_tab (fileEditorTab, "");
+                      add_file_editor_tab (fileEditorTab, "", index);
                     fileEditorTab->update_window_title (false);
                     // file already loaded, add file to mru list here
                     QFileInfo file_info = QFileInfo (openFileName);
@@ -1268,6 +1359,7 @@
                 else
                   {
                     delete fileEditorTab;
+                    fileEditorTab = nullptr;
 
                     if (QFile::exists (openFileName))
                       {
@@ -1289,7 +1381,6 @@
                         // File does not exist, should it be created?
                         bool create_file = true;
                         QMessageBox *msgBox;
-                        QSettings *settings = resource_manager::get_settings ();
 
                         if (! settings->value ("editor/create_new_file", false).toBool ())
                           {
@@ -1340,7 +1431,10 @@
 
             if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ()))
               {
-                // really show editor and the current editor tab
+                // update breakpoint pointers, really show editor
+                // and the current editor tab
+                if (fileEditorTab)
+                  fileEditorTab->update_breakpoints ();
                 focus ();
                 emit file_loaded_signal ();
               }
@@ -1423,9 +1517,6 @@
       menu->removeAction (a);
 
     // add editor's actions with icons and customized shortcuts
-    menu->addAction (m_undo_action);
-    menu->addAction (m_redo_action);
-    menu->addSeparator ();
     menu->addAction (m_cut_action);
     menu->addAction (m_copy_action);
     menu->addAction (m_paste_action);
@@ -1465,10 +1556,15 @@
             e->accept ();
           }
         else
-          e->ignore ();
+          {
+            e->ignore ();
+            return;
+          }
       }
     else
       e->accept ();
+
+    octave_dock_widget::closeEvent (e);
   }
 
   void file_editor::dragEnterEvent (QDragEnterEvent *e)
@@ -1490,7 +1586,7 @@
 
   bool file_editor::is_editor_console_tabbed (void)
   {
-    octave::main_window *w = static_cast<octave::main_window *>(main_win ());
+    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));
@@ -1989,6 +2085,7 @@
     m_tool_bar->addSeparator ();
     // m_undo_action: later via main window
     m_tool_bar->addAction (m_redo_action);
+    m_tool_bar->addSeparator ();
     // m_copy_action: later via the main window
     m_tool_bar->addAction (m_cut_action);
     // m_paste_action: later via the main window
@@ -2020,10 +2117,6 @@
     ctx_men->addAction (m_close_others_action);
 
     // signals
-    connect (this,
-             SIGNAL (execute_command_in_terminal_signal (const QString&)),
-             main_win (), SLOT (execute_command_in_terminal (const QString&)));
-
     connect (this, SIGNAL (request_settings_dialog (const QString&)),
              main_win (),
              SLOT (process_settings_dialog_request (const QString&)));
@@ -2046,9 +2139,13 @@
     check_actions ();
   }
 
-  void file_editor::add_file_editor_tab (file_editor_tab *f, const QString& fn)
+  void file_editor::add_file_editor_tab (file_editor_tab *f, const QString& fn,
+                                         int index)
   {
-    m_tab_widget->addTab (f, fn);
+    if (index == -1)
+      m_tab_widget->addTab (f, fn);
+    else
+      m_tab_widget->insertTab (index, f, fn);
 
     // signals from the qscintilla edit area
     connect (f->qsci_edit_area (), SIGNAL (status_update (bool, bool)),
@@ -2090,8 +2187,8 @@
     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&)),
-             this, SLOT (request_open_file (const QString&)));
+    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)),
@@ -2102,6 +2199,9 @@
     connect (f, SIGNAL (set_focus_editor_signal (QWidget*)),
              this, SLOT (set_focus (QWidget*)));
 
+    connect (f, SIGNAL (request_queue_cmd (octave_cmd*)),
+             main_win (), SLOT (queue_cmd (octave_cmd*)));
+
     // Signals from the file_editor non-trivial operations
     connect (this, SIGNAL (fetab_settings_changed (const QSettings *)),
              f, SLOT (notice_settings (const QSettings *)));
@@ -2119,9 +2219,6 @@
     connect (this, SIGNAL (fetab_check_modified_file (void)),
              f, SLOT (check_modified_file (void)));
 
-    connect (f, SIGNAL (execute_command_in_terminal_signal (const QString&)),
-             main_win (), SLOT (execute_command_in_terminal (const QString&)));
-
     // Signals from the file_editor trivial operations
     connect (this, SIGNAL (fetab_recover_from_exit (void)),
              f, SLOT (recover_from_exit (void)));
@@ -2311,14 +2408,15 @@
                                        const QString& new_name)
   {
     QDir old_dir (old_name);
+    session_data f_data;
 
     // Have all file editor tabs signal what their filenames are.
     m_editor_tab_map.clear ();
     emit fetab_file_name_query (nullptr);
 
     // Loop over all open files and pick those within old_dir
-    for (editor_tab_map_const_iterator p = m_editor_tab_map.begin ();
-         p != m_editor_tab_map.end (); p++)
+    for (auto p = m_editor_tab_map.cbegin ();
+         p != m_editor_tab_map.cend (); p++)
       {
         QString rel_path_to_file = old_dir.relativeFilePath (p->first);
         if (rel_path_to_file.left (3) != QString ("../"))
@@ -2329,23 +2427,49 @@
             m_no_focus = true;  // Remember for not focussing editor
             file_editor_tab *editor_tab
               = static_cast<file_editor_tab *> (p->second.fet_ID);
-            editor_tab->file_has_changed (QString (), true);  // Close
+            if (editor_tab)
+              {
+                // Get index and line
+                int l, c;
+                editor_tab->qsci_edit_area ()->getCursorPosition (&l, &c);
+                f_data.line = l + 1;
+                f_data.index = m_tab_widget->indexOf (p->second.fet_ID);
+                // Close
+                editor_tab->file_has_changed (QString (), true);
+              }
             m_no_focus = false;  // Back to normal
 
             // Store file for possible later reload
-            m_tmp_closed_files << p->first;
+            f_data.file_name = p->first;
 
             // Add the new file path and the encoding for later reloading
             // if new_name is given
             if (! new_name.isEmpty ())
               {
                 QDir new_dir (new_name);
-                m_tmp_closed_files << new_dir.absoluteFilePath (rel_path_to_file);
+                QString append_to_new_dir;
+                if (new_dir.exists ())
+                  {
+                    // The new directory already exists (movefile was used).
+                    // This means, we have to add the name (not the path)
+                    // of the old dir and the relative path to the file
+                    // to new dir.
+                    append_to_new_dir = old_dir.dirName () +
+                                        "/" + rel_path_to_file;
+                  }
+                else
+                  append_to_new_dir = rel_path_to_file;
+
+                f_data.new_file_name
+                        = new_dir.absoluteFilePath (append_to_new_dir);
               }
             else
-              m_tmp_closed_files << ""; // no new name, just removing this file
-
-            m_tmp_closed_files << p->second.encoding; // store the encoding
+              f_data.new_file_name = ""; // no new name, just removing this file
+
+            f_data.encoding = p->second.encoding; // store the encoding
+
+            // Store data in list for later reloading
+            m_tmp_closed_files << f_data;
           }
       }
   }
@@ -2368,8 +2492,8 @@
     // Check all tabs for the given file name
     QWidget *retval = nullptr;
 
-    for (editor_tab_map_const_iterator p = m_editor_tab_map.begin ();
-         p != m_editor_tab_map.end (); p++)
+    for (auto p = m_editor_tab_map.cbegin ();
+         p != m_editor_tab_map.cend (); p++)
       {
         QString tab_file = p->first;
         if (same_file (file.toStdString (), tab_file.toStdString ())
--- a/libgui/src/m-editor/file-editor.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/file-editor.h	Thu Dec 20 17:18:56 2018 -0500
@@ -78,7 +78,9 @@
     struct session_data
     {
       int index;
+      int line;
       QString file_name;
+      QString new_file_name;
       QString encoding;
 
       bool operator < (const session_data& other) const
@@ -171,7 +173,6 @@
     void fetab_recover_from_exit (void);
 
     void request_settings_dialog (const QString&);
-    void execute_command_in_terminal_signal (const QString&);
     void request_open_file_external (const QString& file_name, int line);
     void file_loaded_signal (void);
 
@@ -284,7 +285,7 @@
                             const QString& encoding = QString (),
                             int line = -1, bool debug_pointer = false,
                             bool breakpoint_marker = false, bool insert = true,
-                            const QString& cond = "");
+                            const QString& cond = "", int index = -1);
     void request_preferences (bool);
     void request_styles_preferences (bool);
 
@@ -313,7 +314,8 @@
 
     bool is_editor_console_tabbed (void);
     void construct (void);
-    void add_file_editor_tab (file_editor_tab *f, const QString& fn);
+    void add_file_editor_tab (file_editor_tab *f, const QString& fn,
+                              int index = -1);
     void mru_menu_update (void);
     bool call_custom_editor (const QString& file_name = QString (), int line = -1);
 
@@ -449,11 +451,8 @@
     QStringList m_mru_files;
     QStringList m_mru_files_encodings;
 
-    // List of temporarily closed files for later reloading.
-    // Order: first closed old file
-    //        first new location of closed file
-    //        encoding to use for reload
-    QStringList m_tmp_closed_files;
+    // List of data on temporarily closed files for later reloading.
+    QList<session_data> m_tmp_closed_files;
   };
 }
 
--- a/libgui/src/m-editor/octave-qscintilla.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -46,20 +46,19 @@
 #include <Qsci/qscicommandset.h>
 
 #include <QKeySequence>
+#include <QMimeData>
 #include <QShortcut>
 #include <QToolTip>
 #include <QVBoxLayout>
 
-#include <QMimeData>
-
-// FIXME: hardwired marker numbers?
-#include "marker.h"
+#include "gui-preferences.h"
+#include "resource-manager.h"
+#include "shortcut-manager.h"
 
 #include "octave-qscintilla.h"
 #include "file-editor-tab.h"
-#include "shortcut-manager.h"
-#include "resource-manager.h"
-#include "octave-settings.h"
+// FIXME: hardwired marker numbers?
+#include "marker.h"
 
 // Return true if CANDIDATE is a "closing" that matches OPENING,
 // such as "end" or "endif" for "if", or "catch" for "try".
@@ -394,29 +393,29 @@
           if (comment)
             {
               // The commenting string is requested
-              if (settings->contains (oct_comment_str))
+              if (settings->contains (ed_comment_str.key))
                 // new version (radio buttons)
-                comment_string = settings->value (oct_comment_str,
-                                                  oct_comment_str_d).toInt ();
+                comment_string = settings->value (ed_comment_str.key,
+                                                  ed_comment_str.def).toInt ();
               else
                 // old version (combo box)
-                comment_string = settings->value (oct_comment_str_old,
-                                                  oct_comment_str_d).toInt ();
+                comment_string = settings->value (ed_comment_str_old.key,
+                                                  ed_comment_str.def).toInt ();
 
-              return (QStringList (oct_comment_strings.at (comment_string)));
+              return (QStringList (ed_comment_strings.at (comment_string)));
             }
           else
             {
               QStringList c_str;
 
               // The possible uncommenting string(s) are requested
-              comment_string = settings->value (oct_uncomment_str,
-                                                oct_uncomment_str_d).toInt ();
+              comment_string = settings->value (ed_uncomment_str.key,
+                                                ed_uncomment_str.def).toInt ();
 
-              for (int i = 0; i < oct_comment_strings_count; i++)
+              for (int i = 0; i < ed_comment_strings_count; i++)
                 {
                   if (1 << i & comment_string)
-                    c_str.append (oct_comment_strings.at (i));
+                    c_str.append (ed_comment_strings.at (i));
                 }
 
               return c_str;
--- a/libgui/src/main-window.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/main-window.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,6 +27,7 @@
 
 #include <QKeySequence>
 #include <QApplication>
+#include <QStyleFactory>
 #include <QInputDialog>
 #include <QLabel>
 #include <QMenuBar>
@@ -34,6 +35,7 @@
 #include <QAction>
 #include <QSettings>
 #include <QStyle>
+#include <QStyleFactory>
 #include <QToolBar>
 #include <QDesktopServices>
 #include <QDesktopWidget>
@@ -41,6 +43,7 @@
 #include <QMessageBox>
 #include <QIcon>
 #include <QTextBrowser>
+#include <QTextCodec>
 #include <QTextStream>
 #include <QThread>
 #include <QDateTime>
@@ -55,20 +58,23 @@
 #include "main-window.h"
 #include "settings-dialog.h"
 #include "shortcut-manager.h"
+#include "welcome-wizard.h"
 
 #include "Array.h"
 #include "cmd-edit.h"
+#include "oct-env.h"
 #include "url-transfer.h"
 
 #include "builtin-defun-decls.h"
+#include "call-stack.h"
 #include "defaults.h"
-#if defined (HAVE_QT_GRAPHICS)
-#  include "__init_qt__.h"
-#endif
+#include "defun.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
 #include "oct-map.h"
 #include "octave.h"
+#include "parse.h"
+#include "syminfo.h"
 #include "symscope.h"
 #include "utils.h"
 #include "version.h"
@@ -85,9 +91,19 @@
 #endif
 }
 
+// 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
+{ }
+
 namespace octave
 {
-  octave_interpreter::octave_interpreter (application *app_context)
+  octave_interpreter::octave_interpreter (gui_application& app_context)
     : QObject (), m_app_context (app_context)
   { }
 
@@ -95,7 +111,7 @@
   {
     // The application context owns the interpreter.
 
-    interpreter& interp = m_app_context->create_interpreter ();
+    interpreter& interp = m_app_context.create_interpreter ();
 
     int exit_status = 0;
 
@@ -105,6 +121,18 @@
 
         interp.initialize ();
 
+        if (m_app_context.start_gui_p ())
+          {
+            input_system& input_sys = interp.get_input_system ();
+
+            input_sys.PS1 (">> ");
+            input_sys.PS2 ("");
+
+            tree_evaluator& tw = interp.get_evaluator ();
+
+            tw.PS4 ("");
+          }
+
         if (interp.initialized ())
           {
             // The interpreter should be completely ready at this point so let
@@ -114,17 +142,6 @@
 
             // Start executing commands in the command window.
 
-#if defined (HAVE_QT_GRAPHICS)
-            // The qt graphics toolkit must be initialized before startup
-            // files are executed.
-
-            symbol_table& symtab = interp.get_symbol_table ();
-
-            install___init_qt___functions (symtab);
-
-            Fregister_graphics_toolkit (interp, ovl ("qt"));
-#endif
-
             exit_status = interp.execute ();
           }
       }
@@ -136,51 +153,82 @@
     // Whether or not initialization succeeds we need to clean up the
     // interpreter once we are done with it.
 
-    m_app_context->delete_interpreter ();
+    m_app_context.delete_interpreter ();
 
     emit octave_finished_signal (exit_status);
   }
 
-  main_window::main_window (QWidget *p, gui_application *app_context)
-    : QMainWindow (p), m_app_context (app_context),
-      m_interpreter (new octave_interpreter (app_context)),
-      m_main_thread (new QThread ()), m_workspace_model (nullptr),
+  main_window::main_window (octave_qt_app& oct_qt_app,
+                            octave_qt_link *oct_qt_lnk)
+    : QMainWindow (),
+      m_qt_app (oct_qt_app.qt_app ()), m_octave_qt_link (oct_qt_lnk),
+      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_external_editor (new external_editor_interface (this)),
+      m_active_editor (m_external_editor),
       m_settings_dlg (nullptr), m_find_files_dlg (nullptr),
       m_release_notes_window (nullptr), m_community_news_window (nullptr),
-      m_octave_qt_link (nullptr), m_clipboard (QApplication::clipboard ()),
+      m_clipboard (QApplication::clipboard ()),
       m_prevent_readline_conflicts (true), m_suppress_dbg_location (true),
-      m_start_gui (app_context && app_context->start_gui_p ()),
-      m_file_encoding (QString ())
+      m_closing (false), m_file_encoding (QString ())
   {
-    if (m_start_gui)
+    if (resource_manager::is_first_run ())
+      {
+        // Before wizard.
+        oct_qt_app.config_translators ();
+
+        welcome_wizard welcomeWizard;
+
+        if (welcomeWizard.exec () == QDialog::Rejected)
+          exit (1);
+
+        // Install settings file.
+        resource_manager::reload_settings ();
+      }
+    else
       {
-        m_workspace_model = new workspace_model ();
-        m_status_bar = new QStatusBar ();
-        m_command_window = new terminal_dock_widget (this);
-        m_history_window = new history_dock_widget (this);
-        m_file_browser_window = new files_dock_widget (this);
-        m_doc_browser_window = new documentation_dock_widget (this);
-        m_editor_window = create_default_editor (this);
-        m_variable_editor_window = new variable_editor (this);
-        m_workspace_window = new workspace_view (this);
+        // Get settings file.
+        resource_manager::reload_settings ();
+
+        // After settings.
+        oct_qt_app.config_translators ();
       }
 
-    // Initialize global Qt application metadata
-    QCoreApplication::setApplicationName ("GNU Octave");
-    QCoreApplication::setApplicationVersion (OCTAVE_VERSION);
+    resource_manager::update_network_settings ();
+
+    // We provide specific terminal capabilities, so ensure that
+    // TERM is always set appropriately.
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+    sys::env::putenv ("TERM", "cygwin");
+#else
+    sys::env::putenv ("TERM", "xterm");
+#endif
+
+    shortcut_manager::init_data ();
+
+    construct_central_widget ();
+
+    m_workspace_model = new workspace_model ();
+    m_status_bar = new QStatusBar ();
+    m_command_window = new terminal_dock_widget (this);
+    m_history_window = new history_dock_widget (this);
+    m_file_browser_window = new files_dock_widget (this);
+    m_doc_browser_window = new documentation_dock_widget (this);
+    m_editor_window = create_default_editor (this);
+    m_variable_editor_window = new variable_editor (this);
+    m_workspace_window = new workspace_view (this);
+
+    m_active_editor = m_editor_window;
+
 #if defined (HAVE_QGUIAPPLICATION_SETDESKTOPFILENAME)
-    if (m_start_gui)
-      QGuiApplication::setDesktopFileName ("org.octave.Octave.desktop");
+    QGuiApplication::setDesktopFileName ("org.octave.Octave.desktop");
 #endif
 
-    m_external_editor = new external_editor_interface (this);
-    m_active_editor = m_editor_window;  // for connecting signals
-    if (! m_editor_window)
-      m_active_editor = m_external_editor;
+    m_default_style = m_qt_app->style ()->objectName ();
 
     QSettings *settings = resource_manager::get_settings ();
 
@@ -198,33 +246,34 @@
           = settings->value ("news/last_time_checked", QDateTime ()).toDateTime ();
 
         serial = settings->value ("news/last_news_item", 0).toInt ();
+        m_default_encoding = settings->value (ed_default_enc.key,
+                                              ed_default_enc.def).toString ();
       }
 
     QDateTime current = QDateTime::currentDateTime ();
     QDateTime one_day_ago = current.addDays (-1);
 
-    if (m_start_gui && connect_to_web
+    if (connect_to_web
         && (! last_checked.isValid () || one_day_ago > last_checked))
       load_and_display_community_news (serial);
 
-    // We have to set up all our windows, before we finally launch octave.
+    construct_octave_qt_link ();
+
+    // We have to set up all our windows, before we finally launch
+    // octave.
+
     construct ();
 
-    connect (m_interpreter, SIGNAL (octave_ready_signal (void)),
-             this, SLOT (handle_octave_ready (void)));
-
-    connect (m_interpreter, SIGNAL (octave_finished_signal (int)),
-             this, SLOT (handle_octave_finished (int)));
-
-    connect (m_interpreter, SIGNAL (octave_finished_signal (int)),
-             m_main_thread, SLOT (quit (void)));
-
-    connect (m_main_thread, SIGNAL (finished (void)),
-             m_main_thread, SLOT (deleteLater (void)));
-
-    m_interpreter->moveToThread (m_main_thread);
-
-    m_main_thread->start ();
+    read_settings ();
+
+    init_terminal_size ();
+
+    // Connect signals for changes in visibility not before window is
+    // shown.
+
+    connect_visibility_changed ();
+
+    focus_command_window ();
   }
 
   main_window::~main_window (void)
@@ -246,28 +295,11 @@
     delete m_status_bar;
     delete m_workspace_model;
     delete m_variable_editor_window;
-    delete m_interpreter;
-
-    if (m_find_files_dlg)
-      {
-        delete m_find_files_dlg;
-        m_find_files_dlg = nullptr;
-      }
-    if (m_release_notes_window)
-      {
-        delete m_release_notes_window;
-        m_release_notes_window = nullptr;
-      }
-    if (m_settings_dlg)
-      {
-        delete m_settings_dlg;
-        m_settings_dlg = nullptr;
-      }
-    if (m_community_news_window)
-      {
-        delete m_community_news_window;
-        m_community_news_window = nullptr;
-      }
+
+    delete m_find_files_dlg;
+    delete m_release_notes_window;
+    delete m_settings_dlg;
+    delete m_community_news_window;
   }
 
   bool main_window::command_window_has_focus (void) const
@@ -356,33 +388,59 @@
 
   void main_window::handle_save_workspace_request (void)
   {
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = 0;  // No options by default.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts = QFileDialog::DontUseNativeDialog;
+
     QString file
       = QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), ".",
-                                      nullptr, nullptr,
-                                      QFileDialog::DontUseNativeDialog);
+                                      nullptr, nullptr, QFileDialog::Option (opts));
 
     if (! file.isEmpty ())
-      octave_link::post_event (this, &main_window::save_workspace_callback,
-                               file.toStdString ());
+      {
+        octave_cmd_builtin *cmd
+                = new octave_cmd_builtin (&Fsave, ovl (file.toStdString ()));
+        queue_cmd (cmd);
+      }
   }
 
   void main_window::handle_load_workspace_request (const QString& file_arg)
   {
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = 0;  // No options by default.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts = QFileDialog::DontUseNativeDialog;
+
     QString file = file_arg;
 
     if (file.isEmpty ())
       file = QFileDialog::getOpenFileName (this, tr ("Load Workspace"), ".",
-                                           nullptr, nullptr,
-                                           QFileDialog::DontUseNativeDialog);
+                                           nullptr, nullptr, QFileDialog::Option (opts));
 
     if (! file.isEmpty ())
-      octave_link::post_event (this, &main_window::load_workspace_callback,
-                               file.toStdString ());
+      {
+        octave_cmd_builtin *cmd
+          = new octave_cmd_builtin (&Fload, ovl (file.toStdString ()),
+                                    octave_cmd_builtin::CMD_UPD_WORKSPACE);
+        queue_cmd (cmd);
+      }
+  }
+
+  void main_window::handle_open_any_request (const QString& file_arg)
+  {
+    if (! file_arg.isEmpty ())
+      octave_link::post_event (this, &main_window::open_any_callback,
+                               file_arg.toStdString ());
   }
 
   void main_window::handle_clear_workspace_request (void)
   {
-    octave_link::post_event (this, &main_window::clear_workspace_callback);
+    octave_cmd_builtin *cmd = new octave_cmd_builtin (&Fclear, ovl ());
+
+    queue_cmd (cmd);
   }
 
   void main_window::handle_clear_command_window_request (void)
@@ -431,6 +489,19 @@
     handle_edit_mfile_request (name, QString (), QString (), line);
   }
 
+  void main_window::file_remove_proxy (const QString& o, const QString& n)
+  {
+    // Wait for worker to suspend
+    m_octave_qt_link->lock ();
+
+    // Close the file if opened
+    m_editor_window->handle_file_remove (o, n);
+
+    // We are done: Unlock and wake the worker thread
+    m_octave_qt_link->unlock ();
+    m_octave_qt_link->wake_all ();
+  }
+
   void main_window::open_online_documentation_page (void)
   {
     QDesktopServices::openUrl (
@@ -569,6 +640,19 @@
         m_community_news_window->move ((win_x - m_community_news_window->width ())/2,
                                        (win_y - m_community_news_window->height ())/2);
       }
+    else
+      {
+        // Window already exists, just update the browser contents
+        QTextBrowser *browser
+
+          = m_community_news_window->findChild<QTextBrowser *>("OctaveNews"
+#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
+                                                               , Qt::FindDirectChildrenOnly
+#endif
+                                                              );
+        if (browser)
+          browser->setHtml (news);
+      }
 
     if (! m_community_news_window->isVisible ())
       m_community_news_window->show ();
@@ -622,25 +706,6 @@
     m_settings_dlg->show ();
   }
 
-  void main_window::copy_image_to_clipboard (const QString& file,
-                                             bool remove_file)
-  {
-    QClipboard *clipboard = QApplication::clipboard ();
-
-    QImage img (file);
-
-    if (img.isNull ())
-      {
-        // Report error?
-        return;
-      }
-
-    clipboard->setImage (img);
-
-    if (remove_file)
-      QFile::remove (file);
-  }
-
   void main_window::show_about_octave (void)
   {
     std::string message
@@ -654,6 +719,18 @@
   {
     // QSettings pointer is checked before emitting.
 
+    // Get desired style from preferences or take the default one if
+    // the desired one is not found
+    QString preferred_style
+          = settings->value (global_style.key, global_style.def).toString ();
+
+    if (preferred_style == global_style.def.toString ())
+      preferred_style = m_default_style;
+
+    QStyle *new_style = QStyleFactory::create (preferred_style);
+    if (new_style)
+      m_qt_app->setStyle (new_style);
+
     // the widget's icons (when floating)
     QString icon_set
       = settings->value ("DockWidgets/widget_icon_set", "NONE").toString ();
@@ -708,15 +785,12 @@
     else
       m_release_notes_icon = ":/actions/icons/logo.png";
 
-    int icon_size_settings = settings->value ("toolbar_icon_size",0).toInt ();
+    int size_idx = settings->value (global_icon_size.key,
+                                    global_icon_size.def).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 (QStyle::PM_ToolBarIconSize);
-
-    if (icon_size_settings == 1)
-      icon_size = st->pixelMetric (QStyle::PM_LargeIconSize);
-    else if (icon_size_settings == -1)
-      icon_size = st->pixelMetric (QStyle::PM_SmallIconSize);
-
+    int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
     m_main_tool_bar->setIconSize (QSize (icon_size,icon_size));
 
     if (settings->value ("show_status_bar",true).toBool ())
@@ -738,6 +812,17 @@
     set_global_shortcuts (m_active_dock == m_command_window);
     disable_menu_shortcuts (m_active_dock == m_editor_window);
 
+    // Ckeck whether some octave internal preferences have to be updated
+    QString new_default_encoding
+      = settings->value (ed_default_enc.key, ed_default_enc.def).toString ();
+    if (new_default_encoding != m_default_encoding)
+      {
+        m_default_encoding = new_default_encoding;
+        octave_cmd_builtin *cmd = new octave_cmd_builtin (
+                                    &F__mfile_encoding__,
+                                    ovl (m_default_encoding.toStdString ()));
+        queue_cmd (cmd);
+      }
 
     // Set cursor blinking depending on the settings
     // Cursor blinking: consider old terminal related setting if not yet set
@@ -757,41 +842,30 @@
 
   }
 
-  void main_window::confirm_shutdown_octave (void)
+  bool main_window::confirm_shutdown_octave (void)
   {
     bool closenow = true;
 
-    if (m_start_gui)
+    QSettings *settings = resource_manager::get_settings ();
+
+    if (settings->value ("prompt_to_exit", false).toBool ())
       {
-        QSettings *settings = resource_manager::get_settings ();
-
-        if (settings->value ("prompt_to_exit", false).toBool ())
-          {
-            int ans = QMessageBox::question (this, tr ("Octave"),
-                                             tr ("Are you sure you want to exit Octave?"),
-                                             (QMessageBox::Ok
-                                              | QMessageBox::Cancel),
-                                             QMessageBox::Ok);
-
-            if (ans != QMessageBox::Ok)
-              closenow = false;
-          }
+        int ans = QMessageBox::question (this, tr ("Octave"),
+                                         tr ("Are you sure you want to exit Octave?"),
+                                         (QMessageBox::Ok
+                                          | QMessageBox::Cancel),
+                                         QMessageBox::Ok);
+
+        if (ans != QMessageBox::Ok)
+          closenow = false;
+      }
 
 #if defined (HAVE_QSCINTILLA)
-        if (closenow)
-          closenow = m_editor_window->check_closing ();
+    if (closenow)
+      closenow = m_editor_window->check_closing ();
 #endif
-      }
-
-    // Wait for link thread to go to sleep state.
-    m_octave_qt_link->lock ();
-
-    m_octave_qt_link->shutdown_confirmation (closenow);
-
-    m_octave_qt_link->unlock ();
-
-    // Awake the worker thread so that it continues shutting down (or not).
-    m_octave_qt_link->wake_all ();
+
+    return closenow;
   }
 
   void main_window::prepare_to_exit (void)
@@ -831,10 +905,15 @@
 
   void main_window::browse_for_directory (void)
   {
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = QFileDialog::ShowDirsOnly;
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts = QFileDialog::DontUseNativeDialog;
+
     QString dir
       = QFileDialog::getExistingDirectory (this, tr ("Browse directories"), nullptr,
-                                           QFileDialog::ShowDirsOnly |
-                                           QFileDialog::DontUseNativeDialog);
+                                           QFileDialog::Option (opts));
 
     set_current_working_directory (dir);
 
@@ -853,8 +932,11 @@
     QFileInfo fileInfo (xdir);
 
     if (fileInfo.exists () && fileInfo.isDir ())
-      octave_link::post_event (this, &main_window::change_directory_callback,
-                               xdir.toStdString ());
+      {
+        octave_cmd_builtin *cmd
+                = new octave_cmd_builtin (&Fcd, ovl (xdir.toStdString ()));
+        queue_cmd (cmd);
+      }
   }
 
   void main_window::change_directory_up (void)
@@ -884,7 +966,7 @@
   {
     octave_cmd_exec *cmd = new octave_cmd_exec (command);
 
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
 
     if (focus_console_after_command ())
       focus_command_window ();
@@ -894,7 +976,7 @@
   {
     octave_cmd_eval *cmd = new octave_cmd_eval (info);
 
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
 
     if (focus_console_after_command ())
       focus_command_window ();
@@ -939,33 +1021,33 @@
   {
     octave_cmd_debug *cmd
       = new octave_cmd_debug ("cont", m_suppress_dbg_location);
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
   void main_window::debug_step_into (void)
   {
     octave_cmd_debug *cmd = new octave_cmd_debug ("in", m_suppress_dbg_location);
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
   void main_window::debug_step_over (void)
   {
     octave_cmd_debug *cmd
       = new octave_cmd_debug ("step", m_suppress_dbg_location);
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
   void main_window::debug_step_out (void)
   {
     octave_cmd_debug *cmd = new octave_cmd_debug ("out", m_suppress_dbg_location);
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
   void main_window::debug_quit (void)
   {
     octave_cmd_debug *cmd
       = new octave_cmd_debug ("quit", m_suppress_dbg_location);
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
   //
@@ -990,48 +1072,16 @@
     QFileDialog *fileDialog = new QFileDialog (p);
     fileDialog->setNameFilter (tr ("Octave Files (*.m);;All Files (*)"));
 
-    // Giving trouble under KDE (problem is related to Qt signal handling on unix,
-    // see https://bugs.kde.org/show_bug.cgi?id=260719 ,
-    // it had/has no effect on Windows, though)
-    fileDialog->setOption (QFileDialog::DontUseNativeDialog, true);
-
-    // define a new grid layout with the extra elements
-    QGridLayout *extra = new QGridLayout (fileDialog);
-    QFrame *separator = new QFrame (fileDialog);
-    separator->setFrameShape (QFrame::HLine);   // horizontal line as separator
-    separator->setFrameStyle (QFrame::Sunken);
-
-    if (is_internal)
-      {
-        // combo box for encoding, only when using the internal editor
-        QLabel *label_enc = new QLabel (tr ("File Encoding:"));
-        QComboBox *combo_enc = new QComboBox ();
-        resource_manager::combo_encoding (combo_enc);
-        m_file_encoding = QString ();  // default
-
-        // track changes in the combo boxes
-        connect (combo_enc, SIGNAL (currentIndexChanged (QString)),
-                 this, SLOT (set_file_encoding (QString)));
-
-        // build the extra grid layout
-        extra->addWidget (separator,0,0,1,3);
-        extra->addWidget (label_enc,1,0);
-        extra->addWidget (combo_enc,1,1);
-        extra->addItem   (new QSpacerItem (1,20,QSizePolicy::Expanding,
-                                           QSizePolicy::Fixed), 1,2);
-
-        // and add the extra grid layout to the dialog's layout
-        QGridLayout *dialog_layout = dynamic_cast<QGridLayout *> (
-                                                                  fileDialog->layout ());
-        dialog_layout->addLayout (extra,dialog_layout->rowCount (),0,
-                                  1,dialog_layout->columnCount ());
-      }
-
     fileDialog->setAcceptMode (QFileDialog::AcceptOpen);
     fileDialog->setViewMode (QFileDialog::Detail);
     fileDialog->setFileMode (QFileDialog::ExistingFiles);
     fileDialog->setDirectory (m_current_directory_combo_box->itemText (0));
 
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      fileDialog->setOption(QFileDialog::DontUseNativeDialog);
+
     connect (fileDialog, SIGNAL (filesSelected (const QStringList&)),
              this, SLOT (request_open_files (const QStringList&)));
 
@@ -1086,26 +1136,38 @@
     interpreter& interp
       = __get_interpreter__ ("main_window::clear_workspace_callback");
 
-    // Is it a regular function within the search path? (Call __which__)
-    octave_value_list fct = F__which__ (interp, ovl (fname.toStdString ()),0);
-    octave_map map = fct(0).map_value ();
-
-    QString type = QString::fromStdString (
-                                           map.contents ("type").data ()[0].string_value ());
-    QString name = QString::fromStdString (
-                                           map.contents ("name").data ()[0].string_value ());
+    // Split possible subfuntions
+    QStringList fcn_list = fname.split ('>');
+    QString fcn_name = fcn_list.at (0) + ".m";
+
+    // Is it a regular function within the search path? (Call Fexist)
+    octave_value_list fct = Fexist (interp, ovl (fname.toStdString ()),0);
+    int type = fct (0).int_value ();
 
     QString message = QString ();
     QString filename = QString ();
 
-    if (type == QString ("built-in function"))
+    switch (type)
       {
-        // built in function: can't edit
-        message = tr ("%1 is a built-in function");
+        case 3:
+        case 5:
+        case 103:
+          message = tr ("%1 is a built-in, compiled or inline\n"
+                        "function and can not be edited.");
+          break;
+
+        case 2:
+          octave_value_list file_path
+              = Ffile_in_loadpath (interp, ovl (fcn_name.toStdString ()), 0);
+          if (file_path.length () > 0)
+            filename = QString::fromStdString (file_path (0).string_value ());
+          break;
       }
-    else if (type.isEmpty ())
+
+    if (filename.isEmpty () && message.isEmpty ())
       {
-        // function not known to octave -> try directory of edited file
+        // No error so far, but function still not known
+        // -> try directory of edited file
         // get directory
         QDir dir;
         if (ffile.isEmpty ())
@@ -1118,28 +1180,20 @@
         else
           dir = QDir (QFileInfo (ffile).canonicalPath ());
 
-        // function not known to octave -> try directory of edited file
-        QFileInfo file = QFileInfo (dir, fname + ".m");
-
+        QFileInfo file = QFileInfo (dir, fcn_name);
         if (file.exists ())
-          {
-            filename = file.canonicalFilePath (); // local file exists
-          }
+          filename = file.canonicalFilePath (); // local file exists
         else
           {
             // local file does not exist -> try private directory
             file = QFileInfo (ffile);
             file = QFileInfo (QDir (file.canonicalPath () + "/private"),
-                              fname + ".m");
-
+                              fcn_name);
             if (file.exists ())
-              {
-                filename = file.canonicalFilePath ();  // private function exists
-              }
+              filename = file.canonicalFilePath ();  // private function exists
             else
-              {
-                message = tr ("Can not find function %1");  // no file found
-              }
+              message = tr ("Can not find function %1");  // no file found
+
           }
       }
 
@@ -1148,7 +1202,7 @@
         QMessageBox *msgBox
           = new QMessageBox (QMessageBox::Critical,
                              tr ("Octave Editor"),
-                             message.arg (name),
+                             message.arg (fname),
                              QMessageBox::Ok, this);
 
         msgBox->setWindowModality (Qt::NonModal);
@@ -1157,10 +1211,6 @@
         return;
       }
 
-    if (filename.isEmpty ())
-      filename = QString::fromStdString (
-                                         map.contents ("file").data ()[0].string_value ());
-
     if (! filename.endsWith (".m"))
       filename.append (".m");
 
@@ -1253,7 +1303,7 @@
 
                 if (visible)
                   {
-                    if (settings->value ("DockWidgets/" + widget->objectName ()
+                    if (settings->value ("DockWidgets/" + name
                                          + "_minimized").toBool ())
                       widget->showMinimized ();
                     else
@@ -1352,121 +1402,6 @@
       emit selectAll_signal ();
   }
 
-  // Connect the signals emitted when the Octave thread wants to create
-  // a dialog box of some sort.  Perhaps a better place for this would be
-  // as part of the QUIWidgetCreator class.  However, mainWindow currently
-  // is not a global variable and not accessible for connecting.
-
-  void main_window::connect_uiwidget_links (void)
-  {
-    connect (&uiwidget_creator,
-             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&)));
-
-    // Register QIntList so that list of ints may be part of a signal.
-    qRegisterMetaType<QIntList> ("QIntList");
-    connect (&uiwidget_creator,
-             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&)));
-
-    // Register QFloatList so that list of floats may be part of a signal.
-    qRegisterMetaType<QFloatList> ("QFloatList");
-    connect (&uiwidget_creator,
-             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 (&uiwidget_creator,
-             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&)));
-  }
-
-  // Create a message dialog with specified string, buttons and decorative
-  // text.
-
-  void main_window::handle_create_dialog (const QString& message,
-                                          const QString& title,
-                                          const QString& icon,
-                                          const QStringList& button,
-                                          const QString& defbutton,
-                                          const QStringList& role)
-  {
-    MessageDialog *message_dialog = new MessageDialog (message, title, icon,
-                                                       button, defbutton, role);
-    message_dialog->setAttribute (Qt::WA_DeleteOnClose);
-    message_dialog->show ();
-  }
-
-  // Create a list dialog with specified list, initially selected, mode,
-  // view size and decorative text.
-
-  void main_window::handle_create_listview (const QStringList& list,
-                                            const QString& mode,
-                                            int wd, int ht,
-                                            const QIntList& initial,
-                                            const QString& name,
-                                            const QStringList& prompt,
-                                            const QString& ok_string,
-                                            const QString& cancel_string)
-  {
-    ListDialog *list_dialog = new ListDialog (list, mode, wd, ht,
-                                              initial, name, prompt,
-                                              ok_string, cancel_string);
-
-    list_dialog->setAttribute (Qt::WA_DeleteOnClose);
-    list_dialog->show ();
-  }
-
-  // Create an input dialog with specified prompts and defaults, title and
-  // row/column size specifications.
-  void main_window::handle_create_inputlayout (const QStringList& prompt,
-                                               const QString& title,
-                                               const QFloatList& nr,
-                                               const QFloatList& nc,
-                                               const QStringList& defaults)
-  {
-    InputDialog *input_dialog = new InputDialog (prompt, title, nr, nc,
-                                                 defaults);
-
-    input_dialog->setAttribute (Qt::WA_DeleteOnClose);
-    input_dialog->show ();
-  }
-
-  void main_window::handle_create_filedialog (const QStringList& filters,
-                                              const QString& title,
-                                              const QString& filename,
-                                              const QString& dirname,
-                                              const QString& multimode)
-  {
-    FileDialog *file_dialog = new FileDialog (filters, title, filename,
-                                              dirname, multimode);
-
-    file_dialog->setAttribute (Qt::WA_DeleteOnClose);
-    file_dialog->show ();
-  }
-
   void main_window::handle_show_doc (const QString& file)
   {
     m_doc_browser_window->setVisible (true);
@@ -1527,13 +1462,7 @@
 #endif
       }
 
-    if (m_start_gui)
-      focus_command_window ();  // make sure that the command window has focus
-  }
-
-  void main_window::handle_octave_finished (int exit_status)
-  {
-    qApp->exit (exit_status);
+    focus_command_window ();  // make sure that the command window has focus
   }
 
   void main_window::find_files (const QString& start_dir)
@@ -1711,15 +1640,11 @@
   {
     e->ignore ();
     octave_cmd_exec *cmd = new octave_cmd_exec ("exit");
-    m_cmd_queue.add_cmd (cmd);
+    queue_cmd (cmd);
   }
 
-  // Main subroutine of the constructor
-
-  void main_window::construct (void)
+  void main_window::construct_central_widget (void)
   {
-    m_closing = false;   // flag for editor files when closed
-
     // Create and set the central widget.  QMainWindow takes ownership of
     // the widget (pointer) so there is no need to delete the object upon
     // destroying this main_window.
@@ -1730,277 +1655,273 @@
     dummyWidget->setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum);
     dummyWidget->hide ();
     setCentralWidget (dummyWidget);
-
-    connect_uiwidget_links ();
-
-    construct_octave_qt_link ();
-
-    if (m_start_gui)
-      {
-        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)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (edit_variable_signal (const QString&,
-                                               const octave_value&)),
-                 this,
-                 SLOT (edit_variable (const QString&, const octave_value&)));
-
-        connect (m_octave_qt_link, SIGNAL (refresh_variable_editor_signal (void)),
-                 this, SLOT (refresh_variable_editor (void)));
-
-        connect (m_workspace_model,
-                 SIGNAL (rename_variable (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)));
-
-        construct_menu_bar ();
-
-        construct_tool_bar ();
-
-        // Order is important.  Deleting QSettings 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 (aboutToQuit (void)),
-                 shortcut_manager::instance, SLOT (cleanup_instance (void)));
-
-        // QSettings are saved upon deletion (i.e., cleanup_instance)
-        connect (qApp, SIGNAL (aboutToQuit (void)),
-                 resource_manager::instance, SLOT (cleanup_instance (void)));
-
-        connect (qApp, SIGNAL (focusChanged (QWidget*, QWidget*)),
-                 this, SLOT (focus_changed (QWidget*, QWidget*)));
-
-        connect (this, SIGNAL (settings_changed (const QSettings *)),
-                 this, SLOT (notice_settings (const QSettings *)));
-
-        connect (this, SIGNAL (editor_focus_changed (bool)),
-                 this, SLOT (disable_menu_shortcuts (bool)));
-
-        connect (this, SIGNAL (editor_focus_changed (bool)),
-                 m_editor_window, SLOT (enable_menu_shortcuts (bool)));
-
-        connect (m_editor_window,
-                 SIGNAL (request_open_file_external (const QString&, int)),
-                 m_external_editor,
-                 SLOT (call_custom_editor (const QString&, int)));
-
-        connect (m_external_editor,
-                 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 (find_files_signal (const QString&)),
-                 this, SLOT (find_files (const QString&)));
-
-        setWindowTitle ("Octave");
-
-// See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357
+  }
+
+// Main subroutine of the constructor
+
+  void main_window::construct (void)
+  {
+    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)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (edit_variable_signal (const QString&,
+                                           const octave_value&)),
+             this,
+             SLOT (edit_variable (const QString&, const octave_value&)));
+
+    connect (m_octave_qt_link, SIGNAL (refresh_variable_editor_signal (void)),
+             this, SLOT (refresh_variable_editor (void)));
+
+    connect (m_workspace_model,
+             SIGNAL (rename_variable (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)));
+
+    construct_menu_bar ();
+
+    construct_tool_bar ();
+
+    // Order is important.  Deleting QSettings 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 (aboutToQuit (void)),
+             shortcut_manager::instance, SLOT (cleanup_instance (void)));
+
+    // QSettings are saved upon deletion (i.e., cleanup_instance)
+    connect (qApp, SIGNAL (aboutToQuit (void)),
+             resource_manager::instance, SLOT (cleanup_instance (void)));
+
+    connect (qApp, SIGNAL (focusChanged (QWidget*, QWidget*)),
+             this, SLOT (focus_changed (QWidget*, QWidget*)));
+
+    connect (this, SIGNAL (settings_changed (const QSettings *)),
+             this, SLOT (notice_settings (const QSettings *)));
+
+    connect (this, SIGNAL (editor_focus_changed (bool)),
+             this, SLOT (disable_menu_shortcuts (bool)));
+
+    connect (this, SIGNAL (editor_focus_changed (bool)),
+             m_editor_window, SLOT (enable_menu_shortcuts (bool)));
+
+    connect (m_editor_window,
+             SIGNAL (request_open_file_external (const QString&, int)),
+             m_external_editor,
+             SLOT (call_custom_editor (const QString&, int)));
+
+    connect (m_external_editor,
+             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&)));
+
+    setWindowTitle ("Octave");
+
+    // See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357
 #if (QT_VERSION < 0x050601) || (QT_VERSION >= 0x050701)
-        setDockOptions (QMainWindow::AnimatedDocks
-                        | QMainWindow::AllowNestedDocks
-                        | QMainWindow::AllowTabbedDocks);
+    setDockOptions (QMainWindow::AnimatedDocks
+                    | QMainWindow::AllowNestedDocks
+                    | QMainWindow::AllowTabbedDocks);
 #else
-        setDockNestingEnabled (true);
+    setDockNestingEnabled (true);
 #endif
 
-        addDockWidget (Qt::RightDockWidgetArea, m_command_window);
-        addDockWidget (Qt::RightDockWidgetArea, m_doc_browser_window);
-        tabifyDockWidget (m_command_window, m_doc_browser_window);
+    addDockWidget (Qt::RightDockWidgetArea, m_command_window);
+    addDockWidget (Qt::RightDockWidgetArea, m_doc_browser_window);
+    tabifyDockWidget (m_command_window, m_doc_browser_window);
 
 #if defined (HAVE_QSCINTILLA)
-        addDockWidget (Qt::RightDockWidgetArea, m_editor_window);
-        tabifyDockWidget (m_command_window, m_editor_window);
+    addDockWidget (Qt::RightDockWidgetArea, m_editor_window);
+    tabifyDockWidget (m_command_window, m_editor_window);
 #endif
-        addDockWidget (Qt::RightDockWidgetArea, m_variable_editor_window);
-        tabifyDockWidget (m_command_window, m_variable_editor_window);
-
-        addDockWidget (Qt::LeftDockWidgetArea, m_file_browser_window);
-        addDockWidget (Qt::LeftDockWidgetArea, m_workspace_window);
-        addDockWidget (Qt::LeftDockWidgetArea, m_history_window);
-
-        int win_x = QApplication::desktop ()->width ();
-        int win_y = QApplication::desktop ()->height ();
-
-        if (win_x > 960)
-          win_x = 960;
-
-        if (win_y > 720)
-          win_y = 720;
-
-        setGeometry (0, 0, win_x, win_y);
-
-        setStatusBar (m_status_bar);
+    addDockWidget (Qt::RightDockWidgetArea, m_variable_editor_window);
+    tabifyDockWidget (m_command_window, m_variable_editor_window);
+
+    addDockWidget (Qt::LeftDockWidgetArea, m_file_browser_window);
+    addDockWidget (Qt::LeftDockWidgetArea, m_workspace_window);
+    addDockWidget (Qt::LeftDockWidgetArea, m_history_window);
+
+    int win_x = QApplication::desktop ()->width ();
+    int win_y = QApplication::desktop ()->height ();
+
+    if (win_x > 960)
+      win_x = 960;
+
+    if (win_y > 720)
+      win_y = 720;
+
+    setGeometry (0, 0, win_x, win_y);
+
+    setStatusBar (m_status_bar);
 
 #if defined (HAVE_QSCINTILLA)
-        connect (this,
-                 SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
-                 m_editor_window,
-                 SLOT (handle_insert_debugger_pointer_request (const QString&,
-                                                               int)));
-
-        connect (this,
-                 SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
-                 m_editor_window,
-                 SLOT (handle_delete_debugger_pointer_request (const QString&,
-                                                               int)));
-
-        connect (this,
-                 SIGNAL (update_breakpoint_marker_signal (bool, const QString&,
-                                                          int, const QString&)),
-                 m_editor_window,
-                 SLOT (handle_update_breakpoint_marker_request (bool,
-                                                                const QString&,
-                                                                int,
-                                                                const QString&)));
-
-        connect (m_file_browser_window,
-                 SIGNAL (file_remove_signal (const QString&, const QString&)),
-                 m_editor_window,
-                 SLOT (handle_file_remove (const QString&, const QString&)));
-
-        connect (m_file_browser_window, SIGNAL (file_renamed_signal (bool)),
-                 m_editor_window, SLOT (handle_file_renamed (bool)));
+    connect (this,
+             SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
+             m_editor_window,
+             SLOT (handle_insert_debugger_pointer_request (const QString&,
+                                                           int)));
+
+    connect (this,
+             SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
+             m_editor_window,
+             SLOT (handle_delete_debugger_pointer_request (const QString&,
+                                                           int)));
+
+    connect (this,
+             SIGNAL (update_breakpoint_marker_signal (bool, const QString&,
+                                                      int, const QString&)),
+             m_editor_window,
+             SLOT (handle_update_breakpoint_marker_request (bool,
+                                                            const QString&,
+                                                            int,
+                                                            const QString&)));
+
+    // Signals for removing/renaming files/dirs in the file browser
+    connect (m_file_browser_window,
+             SIGNAL (file_remove_signal (const QString&, const QString&)),
+             m_editor_window,
+             SLOT (handle_file_remove (const QString&, const QString&)));
+
+    connect (m_file_browser_window, SIGNAL (file_renamed_signal (bool)),
+             m_editor_window, SLOT (handle_file_renamed (bool)));
+
+    // Signals for removing/renaming files/dirs in the temrinal window
+    connect (m_octave_qt_link,
+             SIGNAL (file_remove_signal (const QString&, const QString&)),
+             this, SLOT (file_remove_proxy (const QString&, const QString&)));
+    connect (m_octave_qt_link, SIGNAL (file_renamed_signal (bool)),
+             m_editor_window, SLOT (handle_file_renamed (bool)));
 #endif
 
-        octave_link::post_event (this,
-                                 &main_window::resize_command_window_callback);
-
-        configure_shortcuts ();
-      }
+    octave_link::post_event (this,
+                             &main_window::resize_command_window_callback);
+
+    configure_shortcuts ();
   }
 
   void main_window::construct_octave_qt_link (void)
   {
-    m_octave_qt_link = new octave_qt_link (this, m_app_context);
-
-    octave_link::connect_link (m_octave_qt_link);
-
-    connect (m_octave_qt_link, SIGNAL (confirm_shutdown_signal (void)),
-             this, SLOT (confirm_shutdown_octave (void)));
+    connect (m_octave_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 (m_octave_qt_link, SIGNAL (clear_workspace_signal (void)),
+             m_workspace_model, SLOT (clear_workspace (void)));
+
+    connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
+             this, SLOT (change_directory (QString)));
+
+    connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
+             m_file_browser_window, SLOT (update_octave_directory (QString)));
+
+    connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
+             m_editor_window, SLOT (update_octave_directory (QString)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (execute_command_in_terminal_signal (QString)),
+             this, SLOT (execute_command_in_terminal (QString)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (set_history_signal (const QStringList&)),
+             m_history_window, SLOT (set_history (const QStringList&)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (append_history_signal (const QString&)),
+             m_history_window, SLOT (append_history (const QString&)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (clear_history_signal (void)),
+             m_history_window, SLOT (clear_history (void)));
+
+    connect (m_octave_qt_link, SIGNAL (enter_debugger_signal (void)),
+             this, SLOT (handle_enter_debugger (void)));
+
+    connect (m_octave_qt_link, SIGNAL (exit_debugger_signal (void)),
+             this, SLOT (handle_exit_debugger (void)));
 
     connect (m_octave_qt_link,
-             SIGNAL (copy_image_to_clipboard_signal (const QString&, bool)),
-             this, SLOT (copy_image_to_clipboard (const QString&, bool)));
-
-    if (m_start_gui)
-      {
-        connect (m_octave_qt_link,
-                 SIGNAL (set_workspace_signal (bool, bool,
-                                               const symbol_scope&)),
-                 m_workspace_model,
-                 SLOT (set_workspace (bool, bool, const symbol_scope&)));
-
-        connect (m_octave_qt_link, SIGNAL (clear_workspace_signal (void)),
-                 m_workspace_model, SLOT (clear_workspace (void)));
-
-        connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
-                 this, SLOT (change_directory (QString)));
-
-        connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
-                 m_file_browser_window, SLOT (update_octave_directory (QString)));
-
-        connect (m_octave_qt_link, SIGNAL (change_directory_signal (QString)),
-                 m_editor_window, SLOT (update_octave_directory (QString)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (execute_command_in_terminal_signal (QString)),
-                 this, SLOT (execute_command_in_terminal (QString)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (set_history_signal (const QStringList&)),
-                 m_history_window, SLOT (set_history (const QStringList&)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (append_history_signal (const QString&)),
-                 m_history_window, SLOT (append_history (const QString&)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (clear_history_signal (void)),
-                 m_history_window, SLOT (clear_history (void)));
-
-        connect (m_octave_qt_link, SIGNAL (enter_debugger_signal (void)),
-                 this, SLOT (handle_enter_debugger (void)));
-
-        connect (m_octave_qt_link, SIGNAL (exit_debugger_signal (void)),
-                 this, SLOT (handle_exit_debugger (void)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (show_preferences_signal (void)),
-                 this, SLOT (process_settings_dialog_request (void)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (edit_file_signal (const QString&)),
-                 m_active_editor,
-                 SLOT (handle_edit_file_request (const QString&)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
-                 this,
-                 SLOT (handle_insert_debugger_pointer_request (const QString&,
-                                                               int)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
-                 this,
-                 SLOT (handle_delete_debugger_pointer_request (const QString&,
-                                                               int)));
-
-        connect (m_octave_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 (m_octave_qt_link,
-                 SIGNAL (show_doc_signal (const QString &)),
-                 this, SLOT (handle_show_doc (const QString &)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (register_doc_signal (const QString &)),
-                 this, SLOT (handle_register_doc (const QString &)));
-
-        connect (m_octave_qt_link,
-                 SIGNAL (unregister_doc_signal (const QString &)),
-                 this, SLOT (handle_unregister_doc (const QString &)));
-      }
-
-    // Defer initializing and executing the interpreter until after the main
-    // window and QApplication are running to prevent race conditions
-    QTimer::singleShot (0, m_interpreter, SLOT (execute (void)));
+             SIGNAL (show_preferences_signal (void)),
+             this, SLOT (process_settings_dialog_request (void)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (gui_preference_signal (const QString&, const QString&,
+                                            QString*)),
+             this, SLOT (gui_preference (const QString&, const QString&,
+                                         QString*)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (edit_file_signal (const QString&)),
+             m_active_editor,
+             SLOT (handle_edit_file_request (const QString&)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
+             this,
+             SLOT (handle_insert_debugger_pointer_request (const QString&,
+                                                           int)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
+             this,
+             SLOT (handle_delete_debugger_pointer_request (const QString&,
+                                                           int)));
+
+    connect (m_octave_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 (m_octave_qt_link,
+             SIGNAL (show_doc_signal (const QString &)),
+             this, SLOT (handle_show_doc (const QString &)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (register_doc_signal (const QString &)),
+             this, SLOT (handle_register_doc (const QString &)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (unregister_doc_signal (const QString &)),
+             this, SLOT (handle_unregister_doc (const QString &)));
   }
 
   QAction* main_window::add_action (QMenu *menu, const QIcon& icon,
@@ -2465,24 +2386,63 @@
              this, SLOT (handle_undo_request (void)));
   }
 
-  void main_window::save_workspace_callback (const std::string& file)
-  {
-    // INTERPRETER THREAD
-
-    Fsave (ovl (file));
-  }
-
-  void main_window::load_workspace_callback (const std::string& file)
+  QString main_window::gui_preference_adjust (const QString& key,
+                                              const QString& value)
   {
-    // INTERPRETER THREAD
-
-    Fload (ovl (file));
-
-    symbol_scope scope
-      = __get_current_scope__ ("main_window::load_workspace_callback");
-
-    if (scope)
-      octave_link::set_workspace (true, scope);
+    QString adjusted_value = value;
+
+    // Immediately return if no new value is given
+    if (adjusted_value.isEmpty ())
+      return adjusted_value;
+
+    // Not all encodings are available. Encodings are uppercase and do not
+    // use CPxxx but IBMxxx or WINDOWS-xxx.
+    if (key == ed_default_enc.key)
+      {
+        adjusted_value = adjusted_value.toUpper ();
+
+        QStringList codecs;
+        resource_manager::get_codecs (&codecs);
+
+        QRegExp re ("^CP(\\d+)$");
+        if (re.indexIn (adjusted_value) > -1)
+          {
+            if (codecs.contains ("IBM" + re.cap (1)))
+              adjusted_value = "IBM" + re.cap (1);
+            else if (codecs.contains ("WINDOWS-" + re.cap (1)))
+              adjusted_value = "WINDOWS-" + re.cap (1);
+            else
+              adjusted_value.clear ();
+          }
+        else if (! codecs.contains (adjusted_value))
+          adjusted_value.clear ();
+      }
+
+    return adjusted_value;
+  }
+
+  void main_window::gui_preference (const QString& key, const QString& value,
+                                    QString* read_value)
+  {
+    QSettings *settings = resource_manager::get_settings ();
+    *read_value = settings->value (key).toString ();
+
+    // Wait for worker to suspend
+    m_octave_qt_link->lock ();
+
+    // Some preferences need extra handling
+    QString adjusted_value = gui_preference_adjust (key, value);
+
+    if (! adjusted_value.isEmpty () && (*read_value != adjusted_value))
+      {
+        // Change settings only for new, non-empty values
+        settings->setValue (key, QVariant (adjusted_value));
+        emit settings_changed (settings);
+      }
+
+    // We are done: Unlock and wake the worker thread
+    m_octave_qt_link->unlock ();
+    m_octave_qt_link->wake_all ();
   }
 
   void main_window::rename_variable_callback (const main_window::name_pair& names)
@@ -2496,7 +2456,10 @@
       {
         scope.rename (names.first, names.second);
 
-        octave_link::set_workspace (true, scope);
+        call_stack& cs
+          = __get_call_stack__ ("main_window::rename_variable_callback");
+
+        octave_link::set_workspace (true, cs.get_symbol_info ());
       }
 
     // FIXME: if this action fails, do we need a way to display that info
@@ -2533,32 +2496,37 @@
     command_editor::set_screen_size (sz.first, sz.second);
   }
 
-  void main_window::clear_workspace_callback (void)
+  void main_window::open_any_callback (const std::string& file)
   {
     // INTERPRETER THREAD
 
-    interpreter& interp
-      = __get_interpreter__ ("main_window::clear_workspace_callback");
-
-    Fclear (interp);
+    octave::feval ("open", ovl (file));
+
+    // Update the workspace since open.m may have loaded new variables.
+    call_stack& cs
+      = __get_call_stack__ ("main_window::open_any_callback");
+
+    octave_link::set_workspace (true, cs.get_symbol_info ());
   }
 
   void main_window::clear_history_callback (void)
   {
     // INTERPRETER THREAD
 
-    Fhistory (ovl ("-c"));
+    history_system& history_sys
+      = __get_history_system__ ("main_window::clear_history_callback");
+
+    history_sys.do_history (ovl ("-c"));
   }
 
   void main_window::refresh_workspace_callback (void)
   {
     // INTERPRETER THREAD
 
-    symbol_scope scope
-      = __get_current_scope__ ("main_window::force_refresh_workspace");
-
-    if (scope)
-      octave_link::set_workspace (true, scope, false);
+    call_stack& cs
+      = __get_call_stack__ ("main_window::force_refresh_workspace");
+
+    octave_link::set_workspace (true, cs.get_symbol_info (), false);
   }
 
   bool main_window::focus_console_after_command (void)
@@ -2578,13 +2546,6 @@
     Fdrawnow ();
   }
 
-  void main_window::change_directory_callback (const std::string& directory)
-  {
-    // INTERPRETER THREAD
-
-    Fcd (ovl (directory));
-  }
-
   void main_window::configure_shortcuts (void)
   {
     // file menu
@@ -2788,4 +2749,292 @@
 
     emit finished ();
   }
+
+  octave_qt_app::octave_qt_app (gui_application& app_context)
+    : QObject (), m_app_context (app_context),
+      m_argc (m_app_context.sys_argc ()),
+      m_argv (m_app_context.sys_argv ()), m_qt_app (nullptr),
+      m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()),
+      m_qsci_tr (new QTranslator ()), m_translators_installed (false),
+      m_octave_qt_link (new octave_qt_link ()),
+      m_interpreter (new octave_interpreter (m_app_context)),
+      m_main_thread (new QThread ()),
+      m_main_window (nullptr)
+  {
+    std::string show_gui_msgs =
+      sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES");
+
+    // Installing our handler suppresses the messages.
+
+    if (show_gui_msgs.empty ())
+      {
+#if defined (HAVE_QINSTALLMESSAGEHANDLER)
+        qInstallMessageHandler (message_handler);
+#else
+        qInstallMsgHandler (message_handler);
+#endif
+      }
+
+    // Set the codec for all strings (before wizard or any GUI object)
+#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");
+    QCoreApplication::setApplicationVersion (OCTAVE_VERSION);
+
+    // Register octave_value_list for connecting thread crossing signals.
+
+    qRegisterMetaType<octave_value_list> ("octave_value_list");
+
+    // Even if START_GUI is false, we still set up the QApplication so
+    // that we can use Qt widgets for plot windows.
+
+    m_qt_app = new QApplication (m_argc, m_argv);
+
+    // Force left-to-right alignment (see bug #46204)
+    m_qt_app->setLayoutDirection (Qt::LeftToRight);
+
+    octave_link::connect_link (m_octave_qt_link);
+
+    connect (m_octave_qt_link, SIGNAL (confirm_shutdown_signal (void)),
+             this, SLOT (confirm_shutdown_octave (void)));
+
+    connect (m_octave_qt_link,
+             SIGNAL (copy_image_to_clipboard_signal (const QString&, bool)),
+             this, SLOT (copy_image_to_clipboard (const QString&, bool)));
+
+    connect_uiwidget_links ();
+
+    connect (m_interpreter, SIGNAL (octave_finished_signal (int)),
+             this, SLOT (handle_octave_finished (int)));
+
+    connect (m_interpreter, SIGNAL (octave_finished_signal (int)),
+             m_main_thread, SLOT (quit (void)));
+
+    connect (m_main_thread, SIGNAL (finished (void)),
+             m_main_thread, SLOT (deleteLater (void)));
+
+    if (m_app_context.start_gui_p ())
+      create_main_window ();
+    else
+      {
+        // Get settings file.
+        resource_manager::reload_settings ();
+
+        // After settings.
+        config_translators ();
+
+        m_qt_app->setQuitOnLastWindowClosed (false);
+      }
+
+    // Defer initializing and executing the interpreter until after the main
+    // window and QApplication are running to prevent race conditions
+    QTimer::singleShot (0, m_interpreter, SLOT (execute (void)));
+
+    m_interpreter->moveToThread (m_main_thread);
+
+    m_main_thread->start ();
+  }
+
+  octave_qt_app::~octave_qt_app (void)
+  {
+    delete m_main_window;
+    delete m_interpreter;
+    delete m_qt_app;
+
+    string_vector::delete_c_str_vec (m_argv);
+  }
+
+  void octave_qt_app::config_translators (void)
+  {
+    if (m_translators_installed)
+      return;
+
+    resource_manager::config_translators (m_qt_tr, m_qsci_tr, m_gui_tr);
+
+    m_qt_app->installTranslator (m_qt_tr);
+    m_qt_app->installTranslator (m_gui_tr);
+    m_qt_app->installTranslator (m_qsci_tr);
+
+    m_translators_installed = true;
+  }
+
+  void octave_qt_app::create_main_window (void)
+  {
+    m_main_window = new main_window (*this, m_octave_qt_link);
+
+    connect (m_interpreter, SIGNAL (octave_ready_signal (void)),
+             m_main_window, SLOT (handle_octave_ready (void)));
+
+    m_app_context.gui_running (true);
+  }
+
+  int octave_qt_app::exec (void)
+  {
+    return m_qt_app->exec ();
+  }
+
+  void octave_qt_app::handle_octave_finished (int exit_status)
+  {
+    qApp->exit (exit_status);
+  }
+
+  void octave_qt_app::confirm_shutdown_octave (void)
+  {
+    bool closenow = true;
+
+    if (m_main_window)
+      closenow = m_main_window->confirm_shutdown_octave ();
+
+    // Wait for link thread to go to sleep state.
+    m_octave_qt_link->lock ();
+
+    m_octave_qt_link->shutdown_confirmation (closenow);
+
+    m_octave_qt_link->unlock ();
+
+    // Awake the worker thread so that it continues shutting down (or not).
+    m_octave_qt_link->wake_all ();
+  }
+
+  void octave_qt_app::copy_image_to_clipboard (const QString& file,
+                                                bool remove_file)
+  {
+    QClipboard *clipboard = QApplication::clipboard ();
+
+    QImage img (file);
+
+    if (img.isNull ())
+      {
+        // Report error?
+        return;
+      }
+
+    clipboard->setImage (img);
+
+    if (remove_file)
+      QFile::remove (file);
+  }
+
+  // Create a message dialog with specified string, buttons and decorative
+  // text.
+
+  void octave_qt_app::handle_create_dialog (const QString& message,
+                                            const QString& title,
+                                            const QString& icon,
+                                            const QStringList& button,
+                                            const QString& defbutton,
+                                            const QStringList& role)
+  {
+    MessageDialog *message_dialog = new MessageDialog (message, title, icon,
+                                                       button, defbutton, role);
+    message_dialog->setAttribute (Qt::WA_DeleteOnClose);
+    message_dialog->show ();
+  }
+
+  // Create a list dialog with specified list, initially selected, mode,
+  // view size and decorative text.
+
+  void octave_qt_app::handle_create_listview (const QStringList& list,
+                                              const QString& mode,
+                                              int wd, int ht,
+                                              const QIntList& initial,
+                                              const QString& name,
+                                              const QStringList& prompt,
+                                              const QString& ok_string,
+                                              const QString& cancel_string)
+  {
+    ListDialog *list_dialog = new ListDialog (list, mode, wd, ht,
+                                              initial, name, prompt,
+                                              ok_string, cancel_string);
+
+    list_dialog->setAttribute (Qt::WA_DeleteOnClose);
+    list_dialog->show ();
+  }
+
+  // Create an input dialog with specified prompts and defaults, title and
+  // row/column size specifications.
+  void octave_qt_app::handle_create_inputlayout (const QStringList& prompt,
+                                                 const QString& title,
+                                                 const QFloatList& nr,
+                                                 const QFloatList& nc,
+                                                 const QStringList& defaults)
+  {
+    InputDialog *input_dialog = new InputDialog (prompt, title, nr, nc,
+                                                 defaults);
+
+    input_dialog->setAttribute (Qt::WA_DeleteOnClose);
+    input_dialog->show ();
+  }
+
+  void octave_qt_app::handle_create_filedialog (const QStringList& filters,
+                                                const QString& title,
+                                                const QString& filename,
+                                                const QString& dirname,
+                                                const QString& multimode)
+  {
+    FileDialog *file_dialog = new FileDialog (filters, title, filename,
+                                              dirname, multimode);
+
+    file_dialog->setAttribute (Qt::WA_DeleteOnClose);
+    file_dialog->show ();
+  }
+
+  // Connect the signals emitted when the Octave thread wants to create
+  // a dialog box of some sort.  Perhaps a better place for this would be
+  // as part of the QUIWidgetCreator class.  However, mainWindow currently
+  // is not a global variable and not accessible for connecting.
+
+  void octave_qt_app::connect_uiwidget_links (void)
+  {
+    connect (&uiwidget_creator,
+             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&)));
+
+    // Register QIntList so that list of ints may be part of a signal.
+    qRegisterMetaType<QIntList> ("QIntList");
+    connect (&uiwidget_creator,
+             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&)));
+
+    // Register QFloatList so that list of floats may be part of a signal.
+    qRegisterMetaType<QFloatList> ("QFloatList");
+    connect (&uiwidget_creator,
+             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 (&uiwidget_creator,
+             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&)));
+  }
 }
--- a/libgui/src/main-window.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/main-window.h	Thu Dec 20 17:18:56 2018 -0500
@@ -33,6 +33,7 @@
 #include <QQueue>
 #include <QCloseEvent>
 #include <QToolButton>
+#include <QTranslator>
 #include <QComboBox>
 #include <QPointer>
 
@@ -59,19 +60,19 @@
 #include "workspace-model.h"
 #include "workspace-view.h"
 
-class settings_dialog;
-
 class octave_value;
 
 namespace octave
 {
+  class settings_dialog;
+
   class octave_interpreter : public QObject
   {
     Q_OBJECT
 
   public:
 
-    octave_interpreter (application *app_context);
+    octave_interpreter (gui_application& app_context);
 
     ~octave_interpreter (void) = default;
 
@@ -88,9 +89,11 @@
 
   private:
 
-    application *m_app_context;
+    gui_application& m_app_context;
   };
 
+  class octave_qt_app;
+
   //! Represents the main window.
 
   class main_window : public QMainWindow
@@ -102,7 +105,7 @@
     typedef std::pair <std::string, std::string> name_pair;
     typedef std::pair <int, int> int_pair;
 
-    main_window (QWidget *parent, gui_application *app_context);
+    main_window (octave_qt_app& oct_qt_app, octave_qt_link *oct_qt_lnk);
 
     ~main_window (void);
 
@@ -145,6 +148,7 @@
     void report_status_message (const QString& statusMessage);
     void handle_save_workspace_request (void);
     void handle_load_workspace_request (const QString& file = QString ());
+    void handle_open_any_request (const QString& file = QString ());
     void handle_clear_workspace_request (void);
     void handle_clear_command_window_request (void);
     void handle_clear_history_request (void);
@@ -154,6 +158,7 @@
     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);
     void display_release_notes (void);
     void load_and_display_community_news (int serial = -1);
@@ -165,11 +170,9 @@
     void process_settings_dialog_request (const QString& desired_tab
                                           = QString ());
 
-    void copy_image_to_clipboard (const QString& file, bool remove_file);
-
     void show_about_octave (void);
     void notice_settings (const QSettings *settings);
-    void confirm_shutdown_octave (void);
+    bool confirm_shutdown_octave (void);
     void prepare_to_exit (void);
     void reset_windows (void);
 
@@ -214,37 +217,13 @@
     void pasteClipboard (void);
     void selectAll (void);
 
-    void connect_uiwidget_links (void);
-
-    void handle_create_dialog (const QString& message, const QString& title,
-                               const QString& icon, const QStringList& button,
-                               const QString& defbutton,
-                               const QStringList& role);
-
-    void handle_create_listview (const QStringList& list, const QString& mode,
-                                 int width, int height,
-                                 const QIntList& initial,
-                                 const QString& name,
-                                 const QStringList& prompt,
-                                 const QString& ok_string,
-                                 const QString& cancel_string);
-
-    void handle_create_inputlayout (const QStringList&, const QString&,
-                                    const QFloatList&, const QFloatList&,
-                                    const QStringList&);
-
-    void handle_create_filedialog (const QStringList& filters,
-                                   const QString& title,
-                                   const QString& filename,
-                                   const QString& dirname,
-                                   const QString& multimode);
-
+    void gui_preference (const QString& key, const QString& value,
+                         QString* read_value);
     void handle_show_doc (const QString& file);
     void handle_register_doc (const QString& file);
     void handle_unregister_doc (const QString& file);
 
     void handle_octave_ready ();
-    void handle_octave_finished (int);
 
     //! Find files dialog.
     //!@{
@@ -264,6 +243,13 @@
     void clear_clipboard ();
     //!@}
 
+    //! Queue a command into the worker thread's command queue
+
+    void queue_cmd (octave_cmd *cmd)
+    {
+      m_cmd_queue.add_cmd (cmd);
+    }
+
     //! Returns a list of dock widgets.
 
     QList<octave_dock_widget *> get_dock_widget_list (void)
@@ -292,6 +278,8 @@
 
   private:
 
+    void construct_central_widget (void);
+
     void construct (void);
 
     void construct_octave_qt_link (void);
@@ -318,9 +306,9 @@
 
     void construct_tool_bar (void);
 
-    void save_workspace_callback (const std::string& file);
+    QString gui_preference_adjust (const QString& key, const QString& value);
 
-    void load_workspace_callback (const std::string& file);
+    void open_any_callback (const std::string& file);
 
     void rename_variable_callback (const name_pair& names);
 
@@ -332,8 +320,6 @@
 
     void set_screen_size_callback (const int_pair&);
 
-    void clear_workspace_callback (void);
-
     void clear_history_callback (void);
 
     void refresh_workspace_callback (void);
@@ -342,22 +328,22 @@
 
     void new_figure_callback (void);
 
-    void change_directory_callback (const std::string& directory);
-
     void configure_shortcuts (void);
 
     QList<octave_dock_widget *> dock_widget_list (void);
 
-    gui_application *m_app_context;
+    QApplication *m_qt_app;
 
-    octave_interpreter *m_interpreter;
-
-    QThread *m_main_thread;
+    octave_qt_link *m_octave_qt_link;
 
     workspace_model *m_workspace_model;
 
     QHash<QMenu*, QStringList> m_hash_menu_text;
 
+    QString m_default_encoding;
+
+    QString m_default_style;
+
     //! Toolbar.
 
     QStatusBar *m_status_bar;
@@ -458,8 +444,6 @@
 
     QWidget *m_community_news_window;
 
-    octave_qt_link *m_octave_qt_link;
-
     QClipboard *m_clipboard;
 
     //! Command queue and semaphore to synchronize execution signals and
@@ -471,7 +455,6 @@
     //!@{
     bool m_prevent_readline_conflicts;
     bool m_suppress_dbg_location;
-    bool m_start_gui;
 
     //! Flag for closing the whole application.
 
@@ -510,6 +493,84 @@
     int m_serial;
     bool m_connect_to_web;
   };
+
+  class octave_qt_app : public QObject
+  {
+    Q_OBJECT
+
+  public:
+
+    octave_qt_app (gui_application& app_context);
+
+    ~octave_qt_app (void);
+
+    void config_translators (void);
+
+    void create_main_window (void);
+
+    int exec (void);
+
+    QApplication *qt_app (void) { return m_qt_app; };
+
+  public slots:
+
+    void handle_octave_finished (int);
+
+    void confirm_shutdown_octave (void);
+
+    void copy_image_to_clipboard (const QString& file, bool remove_file);
+
+    void handle_create_dialog (const QString& message, const QString& title,
+                               const QString& icon, const QStringList& button,
+                               const QString& defbutton,
+                               const QStringList& role);
+
+    void handle_create_listview (const QStringList& list, const QString& mode,
+                                 int width, int height,
+                                 const QIntList& initial,
+                                 const QString& name,
+                                 const QStringList& prompt,
+                                 const QString& ok_string,
+                                 const QString& cancel_string);
+
+    void handle_create_inputlayout (const QStringList&, const QString&,
+                                    const QFloatList&, const QFloatList&,
+                                    const QStringList&);
+
+    void handle_create_filedialog (const QStringList& filters,
+                                   const QString& title,
+                                   const QString& filename,
+                                   const QString& dirname,
+                                   const QString& multimode);
+
+  private:
+
+    gui_application& m_app_context;
+
+    // Use these to ensure that argc and argv exist for as long as the
+    // QApplication object.
+
+    int m_argc;
+    char **m_argv;
+
+    QApplication *m_qt_app;
+
+    QTranslator *m_qt_tr;
+    QTranslator *m_gui_tr;
+    QTranslator *m_qsci_tr;
+
+    bool m_translators_installed;
+
+    octave_qt_link *m_octave_qt_link;
+
+    octave_interpreter *m_interpreter;
+
+    QThread *m_main_thread;
+
+    main_window *m_main_window;
+
+    void connect_uiwidget_links (void);
+  };
 }
 
 #endif
--- a/libgui/src/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -9,6 +9,9 @@
   %reldir%/icons/db-step-out.png \
   %reldir%/icons/db-step.png \
   %reldir%/icons/db-stop.png \
+  %reldir%/icons/dialog-error.png \
+  %reldir%/icons/dialog-information.png \
+  %reldir%/icons/dialog-warning.png \
   %reldir%/icons/document-new.png \
   %reldir%/icons/document-open.png \
   %reldir%/icons/document-print.png \
@@ -26,7 +29,10 @@
   %reldir%/icons/folder-new.png \
   %reldir%/icons/go-down.png \
   %reldir%/icons/go-first.png \
+  %reldir%/icons/go-home.png \
   %reldir%/icons/go-last.png \
+  %reldir%/icons/go-next.png \
+  %reldir%/icons/go-previous.png \
   %reldir%/icons/go-up.png \
   %reldir%/icons/graphic_logo_DocumentationDockWidget.png \
   %reldir%/icons/graphic_logo_FileEditor.png \
@@ -78,6 +84,7 @@
   %reldir%/icons/widget-dock-light.png \
   %reldir%/icons/widget-undock-light.png \
   %reldir%/icons/zoom-in.png \
+  %reldir%/icons/zoom-original.png \
   %reldir%/icons/zoom-out.png
 
 octave_gui_MOC =
@@ -108,6 +115,7 @@
   %reldir%/moc-dialog.cc \
   %reldir%/moc-documentation-dock-widget.cc \
   %reldir%/moc-documentation.cc \
+  %reldir%/moc-dw-main-window.cc \
   %reldir%/moc-files-dock-widget.cc \
   %reldir%/moc-history-dock-widget.cc \
   %reldir%/moc-main-window.cc \
@@ -153,6 +161,8 @@
   %reldir%/octave-dock-widget.h \
   %reldir%/documentation-dock-widget.h \
   %reldir%/documentation.h \
+  %reldir%/dw-main-window.h \
+  %reldir%/gui-preferences.h \
   %reldir%/external-editor-interface.h \
   %reldir%/files-dock-widget.h \
   %reldir%/history-dock-widget.h \
@@ -167,7 +177,6 @@
   %reldir%/octave-gui.h \
   %reldir%/octave-cmd.h \
   %reldir%/octave-qt-link.h \
-  %reldir%/octave-settings.h \
   %reldir%/resource-manager.h \
   %reldir%/settings-dialog.h \
   %reldir%/shortcut-manager.h \
@@ -186,6 +195,7 @@
   %reldir%/dialog.cc \
   %reldir%/documentation-dock-widget.cc \
   %reldir%/documentation.cc \
+  %reldir%/dw-main-window.cc \
   %reldir%/external-editor-interface.cc \
   %reldir%/files-dock-widget.cc \
   %reldir%/history-dock-widget.cc \
@@ -227,7 +237,7 @@
   -I$(srcdir)/libgui/qterminal/libqterminal \
   -Ilibgui/src -I$(srcdir)/libgui/src \
   -I$(srcdir)/%reldir%/m-editor \
-  -I$(srcdir)/libgui/graphics \
+  -Iliboctave \
   -I$(srcdir)/liboctave/array \
   -Iliboctave/numeric -I$(srcdir)/liboctave/numeric \
   -Iliboctave/operators -I$(srcdir)/liboctave/operators \
@@ -239,10 +249,6 @@
   -I$(srcdir)/libinterp/octave-value \
   -I$(srcdir)/liboctave/wrappers
 
-%canon_reldir%_%canon_reldir%_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
-
-%canon_reldir%_%canon_reldir%_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
-
 noinst_LTLIBRARIES += %reldir%/libgui-src.la
 
 libgui_EXTRA_DIST += \
--- a/libgui/src/octave-cmd.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-cmd.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,80 +28,121 @@
 
 #include "octave-cmd.h"
 
-#include "octave-qt-link.h"
+#include "builtin-defun-decls.h"
 #include "cmd-edit.h"
-#include "builtin-defun-decls.h"
+#include "interpreter-private.h"
+#include "interpreter.h"
+#include "octave-qt-link.h"
+#include "syminfo.h"
 #include "utils.h"
 
 namespace octave
 {
-  void octave_cmd_exec::execute (void)
+  void octave_cmd_exec::execute (interpreter&)
   {
-    std::string pending_input = octave::command_editor::get_current_line ();
+    std::string pending_input = command_editor::get_current_line ();
 
-    octave::command_editor::set_initial_input (pending_input);
-    octave::command_editor::replace_line (m_cmd.toStdString ());
-    octave::command_editor::redisplay ();
-    octave::command_editor::accept_line ();
+    command_editor::set_initial_input (pending_input);
+    command_editor::replace_line (m_cmd.toStdString ());
+    command_editor::redisplay ();
+    command_editor::accept_line ();
   }
 
-  void octave_cmd_eval::execute (void)
+  void octave_cmd_eval::execute (interpreter&)
   {
     QString function_name = m_info.fileName ();
     function_name.chop (m_info.suffix ().length () + 1);
     std::string file_path = m_info.absoluteFilePath ().toStdString ();
 
-    std::string pending_input = octave::command_editor::get_current_line ();
+    std::string pending_input = command_editor::get_current_line ();
 
     if (valid_identifier (function_name.toStdString ()))
       {
         // valid identifier: call as function with possibility to debug
         std::string path = m_info.absolutePath ().toStdString ();
         if (octave_qt_link::file_in_path (file_path, path))
-          octave::command_editor::replace_line (function_name.toStdString ());
+          command_editor::replace_line (function_name.toStdString ());
       }
     else
       {
         // no valid identifier: use Fsource (), no debug possible
         Fsource (ovl (file_path));
-        octave::command_editor::replace_line ("");
+        command_editor::replace_line ("");
       }
 
-    octave::command_editor::set_initial_input (pending_input);
-    octave::command_editor::redisplay ();
+    command_editor::set_initial_input (pending_input);
+    command_editor::redisplay ();
 
-    octave::command_editor::accept_line ();
+    command_editor::accept_line ();
   }
 
-  void octave_cmd_debug::execute (void)
+  void octave_cmd_builtin::execute (interpreter& interp)
+  {
+    octave_value_list argout;
+    if (m_callback_fi)
+      argout = m_callback_fi (interp, m_argin, m_nargout);
+    else if (m_callback_f)
+      argout = m_callback_f (m_argin, m_nargout);
+
+    switch (m_update)
+      {
+        case CMD_UPD_WORKSPACE:
+          {
+            call_stack& cs
+              = __get_call_stack__ ("octave_cmd_builtin::execute");
+
+            octave_link::set_workspace (true, cs.get_symbol_info ());
+          }
+          break;
+
+        default:
+          break;
+      }
+
+    if (m_nargout)    // Return value expected: connect the related value
+      emit argout_signal (argout);
+  }
+
+  void octave_cmd_builtin::init_cmd_retval ()
+  {
+    if (m_nargout)
+      connect (this, SIGNAL (argout_signal (const octave_value_list&)),
+               m_argout_receiver, m_argout_handler, Qt::QueuedConnection);
+  }
+
+  void octave_cmd_debug::execute (interpreter& interp)
   {
     if (m_cmd == "step")
       {
-        F__db_next_breakpoint_quiet__ (ovl (m_suppress_dbg_location));
-        Fdbstep ();
+        F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
+        Fdbstep (interp);
       }
     else if (m_cmd == "cont")
       {
-        F__db_next_breakpoint_quiet__ (ovl (m_suppress_dbg_location));
-        Fdbcont ();
+        F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
+        Fdbcont (interp);
       }
     else if (m_cmd == "quit")
-      Fdbquit ();
+      Fdbquit (interp);
     else
       {
-        F__db_next_breakpoint_quiet__ (ovl (m_suppress_dbg_location));
-        Fdbstep (ovl (m_cmd.toStdString ()));
+        F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
+        Fdbstep (interp, ovl (m_cmd.toStdString ()));
       }
 
-    octave::command_editor::interrupt (true);
+    command_editor::interrupt (true);
   }
 
   // add a command to the queue
 
   void octave_command_queue::add_cmd (octave_cmd *cmd)
   {
+    // Get a guarded pointer from the pointer to the command object
+    QPointer<octave_cmd> cmd_gp (cmd);
+
+    // And add it to the command queue
     m_queue_mutex.lock ();
-    m_queue.append (cmd);
+    m_queue.append (cmd_gp);
     m_queue_mutex.unlock ();
 
     if (m_processing.tryAcquire ())  // if callback not processing, post event
@@ -118,7 +159,7 @@
       {
         m_queue_mutex.lock ();     // critical path
 
-        octave_cmd *cmd = m_queue.takeFirst ();
+        QPointer<octave_cmd> cmd_gp = m_queue.takeFirst ();
 
         if (m_queue.isEmpty ())
           m_processing.release (); // cmd queue empty, processing will stop
@@ -126,9 +167,19 @@
           repost = true;          // not empty, repost at end
         m_queue_mutex.unlock ();
 
-        cmd->execute ();
+        if (! cmd_gp.isNull ())
+          {
+            // The pointer to the command object is still valid
 
-        delete cmd;
+            // FIXME: Could we store a reference to the interpreter in the
+            // octave_command_queue object?  If so, where is the proper
+            // place to initialize that?
+            interpreter& interp = __get_interpreter__ ("octave_command_queue::execute_command_callback");
+
+            cmd_gp->execute (interp);
+          }
+
+        delete cmd_gp;    // destroy the referred octave_cmd object
       }
 
     if (repost)  // queue not empty, so repost event for further processing
--- a/libgui/src/octave-cmd.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-cmd.h	Thu Dec 20 17:18:56 2018 -0500
@@ -20,29 +20,36 @@
 
 */
 
-// Author: Torsten <ttl@justmail.de>
+// Author: Torsten <mttl@mailbox.org>
 
 #if ! defined (octave_octave_cmd_h)
 #define octave_octave_cmd_h 1
 
 #include <QSemaphore>
 #include <QMutex>
+#include <QPointer>
 #include <QString>
 #include <QFileInfo>
 
 #include "octave-qt-link.h"
+#include "ovl.h"
+
 
 namespace octave
 {
-  class octave_cmd
+  class interpreter;
+
+  class octave_cmd : public QObject
   {
+    Q_OBJECT;
+
   public:
 
-    octave_cmd (void) = default;
+    octave_cmd (void) : QObject () {  };
 
     virtual ~octave_cmd (void) = default;
 
-    virtual void execute (void) { }
+    virtual void execute (interpreter&) { }
   };
 
   class octave_cmd_exec : public octave_cmd
@@ -51,7 +58,7 @@
 
     octave_cmd_exec (const QString& cmd) : octave_cmd () { m_cmd = cmd; }
 
-    void execute (void);
+    void execute (interpreter& interp);
 
   protected:
 
@@ -64,13 +71,117 @@
 
     octave_cmd_eval (const QFileInfo& info) : octave_cmd () { m_info = info; }
 
-    void execute (void);
+    void execute (interpreter& interp);
 
   protected:
 
     QFileInfo m_info;
   };
 
+  class octave_cmd_builtin : public octave_cmd
+  {
+    Q_OBJECT;
+
+  public:
+
+    enum cmd_upd {
+      CMD_UPD_NO        = 0,
+      CMD_UPD_WORKSPACE = 1
+    };
+
+    //! Command using built in functions requiring interpreter, no return values
+    /*! Command calling a built in function, which uses an interpreter and does
+     *  not have any return values
+     * @param Ff Pointer to the builtin function
+     * @param argin Input parameters for Ff as octave value list (default empty)
+     * @param update A memeber of cmd_upd for possibly required updates after
+     *               the executing Ff
+     */
+    octave_cmd_builtin (
+          octave_value_list (*Ff) (octave::interpreter&, const octave_value_list&, int),
+          octave_value_list argin = ovl (), cmd_upd update = CMD_UPD_NO)
+      : octave_cmd (), m_callback_fi (Ff), m_callback_f (nullptr),
+        m_argin (argin), m_nargout (0), m_argout_receiver (nullptr),
+        m_argout_handler (nullptr), m_update (update)
+    {  }
+
+    //! Command using built in functions not requiring interpreter, no return values
+    octave_cmd_builtin (
+          octave_value_list (*Ff) (const octave_value_list&, int),
+          octave_value_list argin = ovl (), cmd_upd update = CMD_UPD_NO)
+      : octave_cmd (), m_callback_fi (nullptr), m_callback_f (Ff),
+        m_argin (argin), m_nargout (0), m_argout_receiver (nullptr),
+        m_argout_handler (nullptr), m_update (update)
+    {  }
+
+    //! Command using built in functions requiring interpreter, with return values
+    /*! Command calling a built in function, which uses an interpreter and
+     *  has return values
+     * @param Ff Pointer to the builtin function
+     * @param argin Input parameters for Ff as octave value list
+     * @param argout Number of output values
+     * @param argout_receiver Receiver of the the signal containing the return values
+     * @param argout_handler  Slot for the signal containing the return values
+     * @param update A member of cmd_upd for possibly required updates after
+     *               the executing Ff
+     * argout_receiver and argout_handler live in the GUI thread. Using a thread
+     * crossing signal/slot mechanism, the GUI thread is not blocked if the
+     * worker thread is busy and can not execute the desired command immediately.
+     */
+    octave_cmd_builtin (
+          octave_value_list (*Ff) (octave::interpreter&, const octave_value_list&, int),
+          octave_value_list argin, int nargout, QObject *argout_receiver,
+          const char *argout_handler = nullptr, cmd_upd update = CMD_UPD_NO)
+      : octave_cmd (), m_callback_fi (Ff), m_callback_f (nullptr),
+        m_argin (argin), m_nargout (nargout), m_argout_receiver (argout_receiver),
+        m_argout_handler (argout_handler), m_update (update)
+    {
+      init_cmd_retval ();
+    }
+
+    //! Command using built in functions not requiring interpreter, with return values
+    octave_cmd_builtin (
+          octave_value_list (*Ff) (const octave_value_list&, int),
+          octave_value_list argin, int nargout, QObject *argout_receiver,
+          const char *argout_handler = nullptr, cmd_upd update = CMD_UPD_NO)
+      : octave_cmd (), m_callback_fi (nullptr), m_callback_f (Ff),
+        m_argin (argin), m_nargout (nargout), m_argout_receiver (argout_receiver),
+        m_argout_handler (argout_handler), m_update (update)
+    {
+      init_cmd_retval ();
+    }
+
+    void execute (interpreter& interp);
+
+  signals:
+
+    //! Signal for sending the return values to the GUI thread
+    void argout_signal (const octave_value_list&);
+
+  protected:
+
+    octave_value_list (*m_callback_fi) (octave::interpreter&,
+                                        const octave_value_list&, int);
+    octave_value_list (*m_callback_f) (const octave_value_list&, int);
+
+    octave_value_list m_argin;
+
+    int m_nargout;
+    QObject *m_argout_receiver;
+    const char *m_argout_handler;
+
+    cmd_upd m_update;
+
+  private:
+
+    //! Internal method connecting the signal for the return values
+    /*! Internal method for connecting the signal for later sending the return
+     * values to the caller. The connection has to be queued ensuring that
+     * the receiver's slot is actually executed in the GUI thread
+     */
+    void init_cmd_retval (void);
+  };
+
   class octave_cmd_debug : public octave_cmd_exec
   {
   public:
@@ -78,7 +189,7 @@
     octave_cmd_debug (const QString& cmd, bool suppress_location)
       : octave_cmd_exec (cmd), m_suppress_dbg_location (suppress_location) { }
 
-    void execute (void);
+    void execute (interpreter& interp);
 
   protected:
 
@@ -94,7 +205,7 @@
   public:
 
     octave_command_queue (void)
-      : QObject (), m_queue (QList<octave_cmd *> ()), m_processing (1),
+      : QObject (), m_queue (QList<QPointer<octave_cmd>> ()), m_processing (1),
         m_queue_mutex ()
     { }
 
@@ -112,7 +223,7 @@
 
   private:
 
-    QList<octave_cmd *> m_queue;
+    QList<QPointer<octave_cmd>> m_queue;
     QSemaphore m_processing;
     QMutex m_queue_mutex;
   };
--- a/libgui/src/octave-dock-widget.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-dock-widget.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -39,11 +39,29 @@
 namespace octave
 {
   label_dock_widget::label_dock_widget (QWidget *p)
-    : QDockWidget (p)
+    : QDockWidget (p), m_default_float_button (nullptr),
+      m_default_close_button (nullptr)
   {
     QStyle *st = style ();
     m_icon_size = 0.75*st->pixelMetric (QStyle::PM_SmallIconSize);
 
+    // keep track of the original buttons on the default title bar,
+    // the button further left is considered "float"
+    QList<QAbstractButton *> buttonlist = findChildren<QAbstractButton *> ();
+    if (buttonlist.size () == 2)
+      {
+        if (buttonlist.at (0)->x () < buttonlist.at (1)->x ())
+          {
+            m_default_float_button = buttonlist.at (0);
+            m_default_close_button = buttonlist.at (1);
+          }
+        else
+          {
+            m_default_float_button = buttonlist.at (0);
+            m_default_close_button = buttonlist.at (1);
+          }
+      }
+
     // the custom (extra) title bar of the widget
     m_title_widget = new QWidget ();
 
@@ -71,11 +89,10 @@
     h_layout->addStretch (100);
     h_layout->addWidget (m_dock_button);
     h_layout->addWidget (m_close_button);
-    h_layout->setSpacing (0);
+    h_layout->setSpacing (10);
     h_layout->setContentsMargins (5,2,2,2);
 
     m_title_widget->setLayout (h_layout);
-    setTitleBarWidget (m_title_widget);
 
     // copy & paste handling
     connect (p, SIGNAL (copyClipboard_signal ()),
@@ -93,21 +110,79 @@
   label_dock_widget::set_title (const QString& title)
   {
     QHBoxLayout *h_layout
-      = static_cast<QHBoxLayout *> (titleBarWidget ()->layout ());
-    QLabel *label = new QLabel (title, titleBarWidget ());
-    label->setStyleSheet ("background: transparent;");
+      = static_cast<QHBoxLayout *> (m_title_widget->layout ());
+    QLabel *label = new QLabel (title, m_title_widget);
+    label->setStyleSheet ("background-color: transparent;");
     h_layout->insertWidget (0,label);
+    setTitleBarWidget (m_title_widget);
     setWindowTitle (title);
   }
 
 
-  octave_dock_widget::octave_dock_widget (QWidget *p)
-    : label_dock_widget (p)
+  static QString
+  qdockwidget_css (const QString& close_icon, const QString& close_tooltip,
+                   const QString& float_icon, const QString& float_tooltip,
+                   int icon_size, const QString& titlebar_foreground,
+                   const QString& titlebar_background)
   {
+    return QString ("QDockWidget\n"
+                    "{\n"
+                    "%6"
+                    "  border: none;\n"
+                    "  titlebar-close-icon: url(%1);\n"
+                    "  titlebar-normal-icon: url(%2);\n"
+                    "}\n"
+                    "\n"
+                    "QDockWidget::close-button, QDockWidget::float-button\n"
+                    "{\n"
+                    "  border: none;\n"
+                    "  icon-size: %3px;\n"
+                    "}\n"
+                    "\n"
+                    "QAbstractButton#qt_dockwidget_closebutton\n"
+                    "{\n"
+                    "  qproperty-toolTip: \"%4\";\n"
+                    "}\n"
+                    "\n"
+                    "QAbstractButton#qt_dockwidget_floatbutton\n"
+                    "{\n"
+                    "  qproperty-toolTip: \"%5\";\n"
+                    "}\n"
+                    "\n"
+                    "QDockWidget::title {\n"
+                    "  text-align: left;\n"
+                    "%7"
+                    "  padding-left: 1px;\n"
+                    "}\n"
+                    "\n"
+                    "QDockWidget::close-button\n"
+                    "{\n"
+                    "  right: %8px;\n"
+                    "  top: 3px;\n"
+                    "}\n"
+                    "\n"
+                    "QDockWidget::float-button\n"
+                    "{\n"
+                    "  right: %9px;\n"
+                    "  top: 3px;\n"
+                    "}\n"
+                    ).arg (close_icon).arg (float_icon).arg (icon_size)
+                     .arg (close_tooltip).arg (float_tooltip)
+                     .arg (titlebar_foreground). arg (titlebar_background)
+                     .arg ((icon_size*2)/3). arg((icon_size*7)/3);
+  }
+
+  octave_dock_widget::octave_dock_widget (const QString& obj_name, QWidget *p)
+    : label_dock_widget (p), 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
-    m_floating = false;
     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)));
 
@@ -119,21 +194,47 @@
              this, SLOT (handle_active_dock_changed (octave_dock_widget*,
                                                      octave_dock_widget*)));
 
-    setFeatures (QDockWidget::DockWidgetMovable); // not floatable or closeable
+    connect (this, SIGNAL (request_queue_cmd (octave_cmd*)),
+             p, SLOT (queue_cmd (octave_cmd*)));
+
+    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 (this, SIGNAL (queue_make_window ()),
+             this, SLOT (make_window ()), Qt::QueuedConnection);
+    connect (this, SIGNAL (queue_make_widget ()),
+             this, SLOT (make_widget ()), Qt::QueuedConnection);
 
     connect (m_dock_action, SIGNAL (triggered (bool)),
-             this, SLOT (change_floating (bool)));
+             this, SLOT (make_window (bool)));
     connect (m_close_action, SIGNAL (triggered (bool)),
              this, SLOT (change_visibility (bool)));
 
     m_close_action->setToolTip (tr ("Hide widget"));
 
+    setStyleSheet (qdockwidget_css (QString (":/actions/icons/widget-close.png"),
+                                    QString ("Close widget"),
+                                    QString (":/actions/icons/widget-undock.png"),
+                                    QString ("Undock widget"),
+                                    m_icon_size,
+                                    QString (""),
+                                    QString ("")));
+    if (widget ())
+      widget ()->setToolTip (QString (""));
+
     m_icon_color = "";
     m_title_3d = 50;
 
     installEventFilter (this);
 
     setFocusPolicy (Qt::StrongFocus);
+
+    setFeatures (QDockWidget::AllDockWidgetFeatures);
+
+    handle_settings (resource_manager::get_settings ());
   }
 
   // connect signal visibility changed to related slot (called from main-window)
@@ -147,82 +248,108 @@
 
   // make the widget floating
   void
-  octave_dock_widget::make_window (void)
+  octave_dock_widget::make_window (bool)
   {
-    // the widget has to be reparented (parent = 0)
-
-    QSettings *settings = resource_manager::get_settings ();
+    bool vis = isVisible ();
 
-    // save the docking area and geometry for later redocking
-    settings->setValue ("DockWidgets/" + objectName () + "_dock_area",
-                        m_parent->dockWidgetArea (this));
-    settings->setValue ("DockWidgets/" + objectName (), saveGeometry ());
-    settings->sync ();
+    // prevent follow-up calls by clearing state variable
+    m_waiting_for_mouse_button_release = false;
+
+    set_focus_predecessor ();  // set focus previously active widget if tabbed
 
-    // remove parent and adjust the (un)dock icon
-    setTitleBarWidget (0);
-    setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
-               Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
-    setTitleBarWidget (m_title_widget);
-    setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
-               Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
-
-#if defined (Q_OS_UNIX)
-    m_title_widget->setToolTip (
-      tr ("Use <Alt> + <Left Mouse Button> for moving the window"));
-#endif
-
-    m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock"
-                                   + m_icon_color + ".png"));
-    m_dock_action->setToolTip (tr ("Dock widget"));
+    // the widget has to be reparented (parent = 0), preferably
+    // from a non-toplevel widget otherwise may not have full
+    // decorations, e.g., no taskbar icon and always in front
+    if (isFloating ())
+      setFloating (false);
+// Remove after thorough testing 3/20/18    m_parent->removeDockWidget (this);
+    setParent (0, Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+               Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::Window);
 
     // restore the last geometry when floating
-    setGeometry (settings->value ("DockWidgets/" + objectName ()
-                                  + "_floating_geometry",
-                                  QRect (50,100,480,480)).toRect ());
+    QRect geom = m_recent_float_geom.isNull () ? QRect (50,100,480,480)
+                                               : m_recent_float_geom;
+    setGeometry (geom);
 
-    m_floating = true;
+    // adjust the (un)dock icon
+    if (titleBarWidget ())
+      {
+        m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock"
+                                       + m_icon_color + ".png"));
+        m_dock_action->setToolTip (tr ("Dock widget"));
+        disconnect (m_dock_action, 0, this, 0);
+        connect (m_dock_action, SIGNAL (triggered (bool)),
+                 this, SLOT (make_widget (bool)));
+      }
+    else
+      {
+        disconnect (m_default_float_button, 0, this, 0);
+        connect (m_default_float_button, SIGNAL (clicked (bool)),
+                 this, SLOT (make_widget (bool)));
+      }
 
-    set_focus_predecessor ();  // set focus previously active widget if tabbed
+    raise ();
+    activateWindow ();
+
+    if (vis)
+    {
+      show ();
+      focus ();
+      set_style (true);
+    }
   }
 
   // dock the widget
   void
-  octave_dock_widget::make_widget (bool dock)
+  octave_dock_widget::make_widget (bool)
   {
+    bool vis = isVisible ();
+
     // Since floating widget has no parent, we have to read it
-
     QSettings *settings = resource_manager::get_settings ();
 
-    // save last floating geometry if widget really was floating
-    if (m_floating)
-      settings->setValue ("DockWidgets/" + objectName () + "_floating_geometry",
-                          geometry ());
-    settings->sync ();
-
-    if (dock)
-      {
-        settings->setValue ("MainWindow/windowState", 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::TopDockWidgetArea, this);
-        // recover old window states, hide and re-show new added widget
-        m_parent->restoreState (settings->value ("MainWindow/windowState").toByteArray ());
-        setFloating (false);
-        focus ();
-        QApplication::setActiveWindow (this);
-        m_title_widget->setToolTip ("");
-      }
-    else  // only reparent, no docking
-      setParent (m_parent);
+    settings->setValue ("MainWindow/windowState", 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 ("MainWindow/windowState").toByteArray ());
+    setFloating (false);
 
     // adjust the (un)dock icon
-    m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock"
-                                   + m_icon_color + ".png"));
-    m_dock_action->setToolTip (tr ("Undock widget"));
+    if (titleBarWidget ())
+      {
+        m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock"
+                                       + m_icon_color + ".png"));
+        m_dock_action->setToolTip (tr ("Undock widget"));
+        disconnect (m_dock_action, 0, this, 0);
+        connect (m_dock_action, SIGNAL (triggered (bool)),
+                 this, SLOT (make_window (bool)));
+      }
+    else
+      {
+        disconnect (m_default_float_button, 0, this, 0);
+        connect (m_default_float_button, SIGNAL (clicked (bool)),
+                 this, SLOT (make_window (bool)));
+      }
 
-    m_floating = false;
+    raise ();
+    QApplication::setActiveWindow (this);
+
+    if (vis)
+      {
+        show ();
+        focus ();
+        set_style (true);
+      }
+  }
+
+  // dock the widget
+  void
+  octave_dock_widget::default_dock (bool)
+  {
+    setFloating (false);
   }
 
   // set the widget which previously had focus when tabified
@@ -250,6 +377,26 @@
     return w;
   }
 
+  bool
+  octave_dock_widget::event (QEvent *event)
+  {
+    // low-level check of whether docked-widget became a window via
+    // double-click or via drag-and-drop
+    if ((event->type () == QEvent::MouseButtonDblClick && ! isFloating ())
+        || (event->type () == QEvent::ActivationChange && m_waiting_for_mouse_button_release))
+      {
+        bool retval = QDockWidget::event (event);
+        if (isFloating () && parent () != 0)
+          {
+            m_waiting_for_mouse_button_release = false;
+            emit queue_make_window ();
+          }
+        return retval;
+      }
+
+    return QDockWidget::event (event);
+  }
+
   void
   octave_dock_widget::handle_settings (const QSettings *settings)
   {
@@ -278,7 +425,7 @@
 
     if (! m_custom_style)
       {
-        bcol = QWidget::palette ().color (m_title_widget->backgroundRole());
+        bcol = QWidget::palette ().color (m_title_widget->backgroundRole ());
         bcola = bcol;
       }
 
@@ -295,6 +442,13 @@
     else
       m_icon_color_active = "";
 
+    m_recent_float_geom = settings->value ("DockWidgets/" + objectName ()
+                                           + "_floating_geometry",
+                                           QRect (50,100,480,480)).toRect ();
+
+    m_recent_dock_geom = settings->value ("DockWidgets/" + objectName (),
+                                          QByteArray ()).toByteArray ();
+
     notice_settings (settings);  // call individual handler
 
     set_style (false);
@@ -327,15 +481,18 @@
     if (! settings)
       return;
 
+    store_geometry ();
+
     settings->beginGroup ("DockWidgets");
 
-    if (m_floating) // widget is floating (windows), save actual floating geometry
-      settings->setValue (name+"_floating_geometry", geometry ());
-    else           // not floating save docked (normal) geometry
-      settings->setValue (name, saveGeometry ());
+    // conditional needed?
+    if (! m_recent_float_geom.isNull ())
+      settings->setValue (name + "_floating_geometry", m_recent_float_geom);
 
+    if (! m_recent_dock_geom.isEmpty ())
+      settings->setValue (name, m_recent_dock_geom);
     settings->setValue (name+"Visible", isVisible ()); // store visibility
-    settings->setValue (name+"Floating", m_floating);    // store visibility
+    settings->setValue (name+"Floating", isFloating ()); // store floating
     settings->setValue (name+"_minimized", isMinimized ()); // store minimized
 
     settings->endGroup ();
@@ -353,19 +510,36 @@
     return QDockWidget::eventFilter (obj,e);
   }
 
-  // slot for (un)dock action
   void
-  octave_dock_widget::change_floating (bool)
+  octave_dock_widget::store_geometry (void)
   {
-    if (m_floating)
-      make_widget ();
+    if (isFloating ())
+      {
+        if (! parent ())
+          m_recent_float_geom = geometry ();
+      }
     else
       {
-        make_window ();
-        focus ();
+        m_recent_dock_geom = saveGeometry ();
       }
   }
 
+  void
+  octave_dock_widget::moveEvent (QMoveEvent *event)
+  {
+    store_geometry ();
+
+    QDockWidget::moveEvent (event);
+  }
+
+  void
+  octave_dock_widget::resizeEvent (QResizeEvent *event)
+  {
+    store_geometry ();
+
+    QDockWidget::resizeEvent (event);
+  }
+
   // slot for hiding the widget
   void
   octave_dock_widget::change_visibility (bool)
@@ -375,18 +549,69 @@
   }
 
   void
+  octave_dock_widget::toplevel_change (bool toplevel)
+  {
+    QObject *dockobj;
+    const char *docksig;
+
+    if (titleBarWidget ())
+      {
+        dockobj = m_dock_action;
+        docksig = SIGNAL (triggered (bool));
+      }
+    else
+      {
+        dockobj = m_default_float_button;
+        docksig = SIGNAL (clicked (bool));
+      }
+
+    if (toplevel)
+      {
+        // This is a fallback in case the attempt to create a floated
+        // top-level window fails and the QDockWidget remains a child
+        // of the QMainWindow.
+        connect (dockobj, docksig, this, SLOT (default_dock (bool)));
+
+        // Could be dragging window, so must wait until there is a
+        // change in focus.
+        if (parent () != 0)
+          m_waiting_for_mouse_button_release = true;
+      }
+    else
+      {
+        // If a drag-and-drop within the QMainWindow occurred, want to remain a widget.
+        m_waiting_for_mouse_button_release = false;
+
+        // Making into a widget immediately will mangle the double-click
+        // status and cause problems on followup button clicks.
+        if (parent () == 0)
+          emit queue_make_widget ();
+      }
+  }
+
+  void
   octave_dock_widget::set_style (bool active)
   {
-    QString css;
+    QString css_foreground;
+    QString css_background;
     QString css_button;
     QString dock_icon;
 
     QString icon_col = m_icon_color;
 
-    if (m_floating)
-      dock_icon = "widget-dock";
+    QString close_tooltip = "Close widget";
+    QString dock_tooltip;
+
+    if (isFloating ())
+      {
+        dock_icon = "widget-dock";
+        dock_tooltip = "Dock widget";
+      }
     else
-      dock_icon = "widget-undock";
+      {
+        dock_icon = "widget-undock";
+        dock_tooltip = "Undock widget";
+      }
 
 #if defined (Q_OS_MAC)
     QString alignment = "center";
@@ -423,35 +648,50 @@
             bg_col_bottom = bg_col.lighter (100 - m_title_3d);
           }
 
-        QString background =
-          QString ("background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
-                   "            stop: 0 %1, stop: 0.60 %2, stop: 0.95 %2 stop: 1.0 %3);").
+        css_foreground = QString ("  color: %1;\n").arg (fg_col.name ());
+
+        css_background =
+          QString ("  background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
+                   " stop: 0 %1, stop: 0.60 %2, stop: 0.95 %2 stop: 1.0 %3);\n").
           arg (bg_col_top.name ()).
           arg (bg_col.name ()).
           arg (bg_col_bottom.name ());
-
-        css = background + QString (" color: %1 ;").arg (fg_col.name ());
       }
     else
       {
-        css = QString ("");
+        css_foreground = QString ("");
+        css_background = QString ("");
       }
 
-    m_title_widget->setStyleSheet (css);
-    css_button = QString ("QToolButton {background: transparent; border: 0px;}");
-    m_dock_button->setStyleSheet (css_button);
-    m_close_button->setStyleSheet (css_button);
-    m_dock_action->setIcon (QIcon (":/actions/icons/" + dock_icon + icon_col +
-                                   ".png"));
-    m_close_action->setIcon (QIcon (":/actions/icons/widget-close" + icon_col +
-                                    ".png"));
+    QString full_dock_icon = ":/actions/icons/" + dock_icon + icon_col + ".png";
+    QString full_close_icon = ":/actions/icons/widget-close" + icon_col + ".png";
+    if (titleBarWidget ())
+      {
+        titleBarWidget ()->setStyleSheet (css_foreground + css_background);
+        css_button = QString ("QToolButton {background: transparent; border: 0px;}");
+        m_dock_button->setStyleSheet (css_button);
+        m_close_button->setStyleSheet (css_button);
+        m_dock_action->setIcon (QIcon (full_dock_icon));
+        m_close_action->setIcon (QIcon (full_close_icon));
+      }
+    else
+      {
+        setStyleSheet (qdockwidget_css (full_close_icon,
+                                        close_tooltip,
+                                        full_dock_icon,
+                                        dock_tooltip,
+                                        m_icon_size,
+                                        css_foreground,
+                                        css_background));
+      }
   }
 
   // set focus to previously active widget in tabbed widget stack
   void
   octave_dock_widget::set_focus_predecessor (void)
   {
-    if (m_predecessor_widget)    // only != 0 if widget was tabbed
+    // only != 0 if widget was tabbed
+    if (m_predecessor_widget && m_predecessor_widget->isVisible ())
       m_predecessor_widget->focus ();
 
     m_predecessor_widget = nullptr;
--- a/libgui/src/octave-dock-widget.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-dock-widget.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,6 +30,8 @@
 #include <QToolButton>
 #include <QMouseEvent>
 
+#include "octave-cmd.h"
+
 namespace octave
 {
 
@@ -43,6 +45,8 @@
 
     label_dock_widget (QWidget *p = nullptr);
 
+    // set_title() uses the custom title bar while setWindowTitle() uses
+    // the default title bar (with style sheets)
     void set_title (const QString&);
 
   protected slots:
@@ -66,6 +70,9 @@
     QToolButton *m_close_button;
     QAction *m_dock_action;
     QAction *m_close_action;
+
+    QAbstractButton *m_default_float_button;
+    QAbstractButton *m_default_close_button;
   };
 
   class octave_dock_widget : public label_dock_widget
@@ -74,14 +81,12 @@
 
   public:
 
-    octave_dock_widget (QWidget *p = nullptr);
+    octave_dock_widget (const QString& obj_name, QWidget *p = nullptr);
 
     virtual ~octave_dock_widget (void) = default;
 
     virtual void connect_visibility_changed (void);
 
-    void make_window (void);
-    void make_widget (bool dock=true);
     void set_predecessor_widget (octave_dock_widget *prev_widget);
 
   signals:
@@ -91,12 +96,20 @@
 
     void active_changed (bool active);
 
+    void queue_make_window (void);
+
+    void queue_make_widget (void);
+
+    void request_queue_cmd (octave_cmd *);
+
   protected:
 
     virtual void closeEvent (QCloseEvent *e);
 
     QWidget * focusWidget (void);
 
+    bool event (QEvent *event);
+
   public slots:
 
     virtual void focus (void)
@@ -125,6 +138,16 @@
 
     void save_settings (void);
 
+    void moveEvent (QMoveEvent *event);
+
+    void resizeEvent (QResizeEvent *event);
+
+    void make_window (bool not_used = false);
+
+    void make_widget (bool not_used = false);
+
+    void default_dock (bool not_used = false);
+
   protected slots:
 
     //! Slot to steer changing visibility from outside.
@@ -141,19 +164,19 @@
 
   private slots:
 
-    void change_floating (bool);
     void change_visibility (bool);
+    void toplevel_change (bool);
 
   private:
 
     void set_style (bool active);
     void set_focus_predecessor (void);
+    void store_geometry (void);
 
     //! Stores the parent, since we are reparenting to 0.
 
     QMainWindow *m_parent;
 
-    bool m_floating;
     bool m_custom_style;
     int m_title_3d;
     QColor m_bg_color;
@@ -163,6 +186,9 @@
     QString m_icon_color;
     QString m_icon_color_active;
     octave_dock_widget *m_predecessor_widget;
+    QRect m_recent_float_geom;
+    QByteArray m_recent_dock_geom;
+    bool m_waiting_for_mouse_button_release;
 
   };
 }
--- a/libgui/src/octave-gui.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-gui.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,54 +24,23 @@
 #  include "config.h"
 #endif
 
-#include <QApplication>
-#include <QTextCodec>
-#include <QThread>
-#include <QTranslator>
-#include <QtGlobal>
-#include <QStyleFactory>
-
-#include <cstdio>
-
-#include <iostream>
-
-#if defined (HAVE_SYS_IOCTL_H)
-#  include <sys/ioctl.h>
-#endif
-
 #include "lo-utils.h"
 #include "oct-env.h"
 #include "oct-syscalls.h"
 #include "signal-wrappers.h"
 
 #include "builtin-defun-decls.h"
-#include "defaults.h"
 #include "display.h"
 #include "octave.h"
 #include "sysdep.h"
-#include "unistd-wrappers.h"
 
 #include "main-window.h"
 #include "octave-gui.h"
-#include "resource-manager.h"
-#include "shortcut-manager.h"
-#include "welcome-wizard.h"
-
-// 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
-{ }
 
 namespace octave
 {
   gui_application::gui_application (int argc, char **argv)
-    : application (argc, argv), m_argc (argc), m_argv (argv),
-      m_gui_running (false)
+    : application (argc, argv)
   {
     // This should probably happen early.
     sysdep_init ();
@@ -88,117 +57,10 @@
 
     set_application_id ();
 
-    std::string show_gui_msgs =
-      sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES");
-
-    // Installing our handler suppresses the messages.
-
-    if (show_gui_msgs.empty ())
-      {
-#if defined (HAVE_QINSTALLMESSAGEHANDLER)
-        qInstallMessageHandler (message_handler);
-#else
-        qInstallMsgHandler (message_handler);
-#endif
-      }
-
-    // If START_GUI is false, we still set up the QApplication so that
-    // we can use Qt widgets for plot windows.
-
-    QApplication qt_app (m_argc, m_argv);
-    QTranslator gui_tr, qt_tr, qsci_tr;
-
-    // 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
-
-    // set windows style for windows
-#if defined (Q_OS_WIN32)
-    qt_app.setStyle (QStyleFactory::create ("Windows"));
-#endif
-
-    bool start_gui = start_gui_p ();
-
-    // Show welcome wizard if this is the first run.
-
-    if (resource_manager::is_first_run () && start_gui)
-      {
-        // Before wizard.
-        resource_manager::config_translators (&qt_tr, &qsci_tr, &gui_tr);
-
-        qt_app.installTranslator (&qt_tr);
-        qt_app.installTranslator (&gui_tr);
-        qt_app.installTranslator (&qsci_tr);
-
-        welcome_wizard welcomeWizard;
-
-        if (welcomeWizard.exec () == QDialog::Rejected)
-          exit (1);
-
-        // Install settings file.
-        resource_manager::reload_settings ();
-      }
-    else
-      {
-        // Get settings file.
-        resource_manager::reload_settings ();
-
-        // After settings.
-        resource_manager::config_translators (&qt_tr, &qsci_tr, &gui_tr);
-
-        qt_app.installTranslator (&qt_tr);
-        qt_app.installTranslator (&gui_tr);
-
-        if (start_gui)
-          qt_app.installTranslator (&qsci_tr);
-      }
-
-    if (start_gui)
-      {
-        resource_manager::update_network_settings ();
-
-        // We provide specific terminal capabilities, so ensure that
-        // TERM is always set appropriately.
-
-#if defined (OCTAVE_USE_WINDOWS_API)
-        sys::env::putenv ("TERM", "cygwin");
-#else
-        sys::env::putenv ("TERM", "xterm");
-#endif
-
-        shortcut_manager::init_data ();
-      }
-
-    // Force left-to-right alignment (see bug #46204)
-    qt_app.setLayoutDirection (Qt::LeftToRight);
-
     // Create and show main window.
 
-    main_window w (nullptr, this);
-
-    if (start_gui)
-      {
-        w.read_settings ();
-
-        w.init_terminal_size ();
-
-        // Connect signals for changes in visibility not before w
-        // is shown.
+    octave_qt_app oct_qt_app (*this);
 
-        w.connect_visibility_changed ();
-
-        w.focus_command_window ();
-
-        gui_running (true);
-      }
-    else
-      qt_app.setQuitOnLastWindowClosed (false);
-
-    return qt_app.exec ();
+    return oct_qt_app.exec ();
   }
 }
--- a/libgui/src/octave-gui.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-gui.h	Thu Dec 20 17:18:56 2018 -0500
@@ -39,6 +39,8 @@
 
     gui_application& operator = (const gui_application&) = delete;
 
+    ~gui_application (void) = default;
+
     // Should we start the GUI or fall back to the CLI?
     bool start_gui_p (void) const;
 
@@ -51,7 +53,9 @@
 
     int m_argc;
     char **m_argv;
-    bool m_gui_running;
+
+    // If TRUE, the GUI should be started.
+    bool m_gui_running = false;
   };
 }
 
--- a/libgui/src/octave-qt-link.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-qt-link.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,9 @@
 #include "interpreter-private.h"
 #include "load-path.h"
 #include "ov.h"
-#include "symscope.h"
+#include "octave.h"
+#include "oct-map.h"
+#include "syminfo.h"
 #include "utils.h"
 
 #include "octave-gui.h"
@@ -49,15 +51,15 @@
 #include "resource-manager.h"
 
 Q_DECLARE_METATYPE (octave_value)
-Q_DECLARE_METATYPE (octave::symbol_scope)
+Q_DECLARE_METATYPE (octave::symbol_info_list)
 
 namespace octave
 {
-  octave_qt_link::octave_qt_link (QWidget *, gui_application *app_context)
-    : octave_link (), m_app_context (app_context)
+  octave_qt_link::octave_qt_link (void)
+    : octave_link ()
   {
     qRegisterMetaType<octave_value> ("octave_value");
-    qRegisterMetaType<symbol_scope> ("symbol_scope");
+    qRegisterMetaType<symbol_info_list> ("symbol_info_list");
   }
 
   bool octave_qt_link::do_confirm_shutdown (void)
@@ -98,7 +100,8 @@
     if (! settings || settings->value ("editor/create_new_file",false).toBool ())
       return true;
 
-    QFileInfo file_info (QString::fromStdString (file));
+    std::string abs_fname = octave::sys::env::make_absolute (file);
+
     QStringList btn;
     QStringList role;
     role << "YesRole" << "RejectRole";
@@ -109,8 +112,7 @@
 
     uiwidget_creator.signal_dialog (
                                     tr ("File\n%1\ndoes not exist. Do you want to create it?").
-                                    arg (QDir::currentPath () + QDir::separator ()
-                                         + QString::fromStdString (file)),
+                                    arg (QString::fromStdString (abs_fname)),
                                     tr ("Octave Editor"), "quest", btn, tr ("Create"), role);
 
     // Wait while the user is responding to message box.
@@ -125,29 +127,30 @@
     return (answer == tr ("Create"));
   }
 
-  int octave_qt_link::do_message_dialog (const std::string& dlg,
-                                         const std::string& msg,
-                                         const std::string& title)
+  uint8NDArray octave_qt_link::do_get_named_icon (const std::string& icon_name)
   {
-    // Lock mutex before signaling.
-    uiwidget_creator.lock ();
+    uint8NDArray retval;
+    QIcon icon = resource_manager::icon (QString::fromStdString (icon_name));
+    if (! icon.isNull ())
+      {
+        QImage img = icon.pixmap (QSize (32, 32)).toImage ();
 
-    uiwidget_creator.signal_dialog (QString::fromStdString (msg),
-                                    QString::fromStdString (title),
-                                    QString::fromStdString (dlg),
-                                    QStringList (), QString (),
-                                    QStringList ());
-
-    // Wait while the user is responding to message box.
-    uiwidget_creator.wait ();
-
-    // The GUI has sent a signal and the thread has been awakened.
-
-    int answer = uiwidget_creator.get_dialog_result ();
-
-    uiwidget_creator.unlock ();
-
-    return answer;
+        if (img.format () == QImage::Format_ARGB32_Premultiplied)
+          {
+            retval.resize (dim_vector (img.height (), img.width (), 4), 0);
+            uint8_t* bits = img.bits ();
+            for (int i = 0; i < img.height (); i++)
+              for (int j = 0; j < img.width (); j++)
+                {
+                  retval(i,j,2) = bits[0];
+                  retval(i,j,1) = bits[1];
+                  retval(i,j,0) = bits[2];
+                  retval(i,j,3) = bits[3];
+                  bits += 4;
+                }
+          }
+      }
+    return retval;
   }
 
   std::string octave_qt_link::do_question_dialog (const std::string& msg,
@@ -195,11 +198,8 @@
   {
     QStringList retval;
 
-    for (std::list<std::string>::const_iterator it = lst.begin ();
-         it != lst.end (); it++)
-      {
-        retval.append (QString::fromStdString (*it));
-      }
+    for (auto it = lst.begin (); it != lst.end (); it++)
+      retval.append (QString::fromStdString (*it));
 
     return retval;
   }
@@ -214,8 +214,7 @@
     // (optional).  Qt wants a list of filters in the format of
     // 'FilterName (space separated exts)'.
 
-    for (octave_link::filter_list::const_iterator it = lst.begin ();
-         it != lst.end (); it++)
+    for (auto it = lst.begin (); it != lst.end (); it++)
       {
         QString ext = QString::fromStdString (it->first);
         QString name = QString::fromStdString (it->second);
@@ -300,11 +299,8 @@
 
     uiwidget_creator.unlock ();
 
-    for (QStringList::const_iterator it = inputLine->begin ();
-         it != inputLine->end (); it++)
-      {
-        retval.push_back (it->toStdString ());
-      }
+    for (auto it = inputLine->begin (); it != inputLine->end (); it++)
+      retval.push_back (it->toStdString ());
 
     return retval;
   }
@@ -335,8 +331,7 @@
     // Add all the file dialog results to a string list.
     const QStringList *inputLine = uiwidget_creator.get_string_list ();
 
-    for (QStringList::const_iterator it = inputLine->begin ();
-         it != inputLine->end (); it++)
+    for (auto it = inputLine->begin (); it != inputLine->end (); it++)
       retval.push_back (it->toStdString ());
 
     retval.push_back (uiwidget_creator.get_dialog_path ()->toStdString ());
@@ -411,6 +406,26 @@
     emit change_directory_signal (QString::fromStdString (dir));
   }
 
+  void octave_qt_link::do_file_remove (const std::string& old_name,
+                                       const std::string& new_name)
+  {
+    // Lock the mutex before signaling
+    lock ();
+
+    // Emit the signal for the editor for closing the file if it is open
+    emit file_remove_signal (QString::fromStdString (old_name),
+                             QString::fromStdString (new_name));
+
+    // Wait for the GUI and unlock when resumed
+    wait ();
+    unlock ();
+  }
+
+  void octave_qt_link::do_file_renamed (bool load_new)
+  {
+    emit file_renamed_signal (load_new);
+  }
+
   void octave_qt_link::do_execute_command_in_terminal
     (const std::string& command)
   {
@@ -418,13 +433,13 @@
   }
 
   void octave_qt_link::do_set_workspace (bool top_level, bool debug,
-                                         const symbol_scope& scope,
+                                         const symbol_info_list& syminfo,
                                          bool update_variable_editor)
   {
     if (! top_level && ! debug)
       return;
 
-    emit set_workspace_signal (top_level, debug, scope);
+    emit set_workspace_signal (top_level, debug, syminfo);
 
     if (update_variable_editor)
       emit refresh_variable_editor_signal ();
@@ -464,6 +479,15 @@
   void octave_qt_link::do_enter_debugger_event (const std::string& file,
                                                 int line)
   {
+    interpreter& interp = __get_interpreter__ (
+                                  "octave_qt_link::do_enter_debugger_event");
+    octave_value_list fct = F__which__ (interp, ovl (file),0);
+    octave_map map = fct(0).map_value ();
+
+    std::string type = map.contents ("type").data ()[0].string_value ();
+    if (type == "command-line function")
+      return;
+
     do_insert_debugger_pointer (file, line);
 
     emit enter_debugger_signal ();
@@ -491,18 +515,6 @@
                                           line, QString::fromStdString (cond));
   }
 
-  void octave_qt_link::do_set_default_prompts (std::string& ps1,
-                                               std::string& ps2,
-                                               std::string& ps4)
-  {
-    if (m_app_context->start_gui_p ())
-      {
-        ps1 = ">> ";
-        ps2 = "";
-        ps4 = "";
-      }
-  }
-
   bool octave_qt_link::file_in_path (const std::string& file,
                                      const std::string& dir)
   {
@@ -582,6 +594,25 @@
     emit show_preferences_signal ();
   }
 
+  std::string octave_qt_link::do_gui_preference (const std::string& key,
+                                                 const std::string& value)
+  {
+    QString pref_value;
+
+    // Lock the mutex before signaling
+    lock ();
+
+    // Emit the signal for changing or getting a preference
+    emit gui_preference_signal (QString::fromStdString (key),
+                                QString::fromStdString (value), &pref_value);
+
+    // Wait for the GUI and unlock when resumed
+    wait ();
+    unlock ();
+
+    return pref_value.toStdString ();
+  }
+
   void octave_qt_link::do_show_doc (const std::string& file)
   {
     emit show_doc_signal (QString::fromStdString (file));
--- a/libgui/src/octave-qt-link.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/octave-qt-link.h	Thu Dec 20 17:18:56 2018 -0500
@@ -44,7 +44,6 @@
 
 namespace octave
 {
-
   //! Provides threadsafe access to octave.
   //! @author Jacob Dawid
   //!
@@ -58,7 +57,7 @@
 
   public:
 
-    octave_qt_link (QWidget *p, gui_application *app_context);
+    octave_qt_link (void);
 
     // No copying!
 
@@ -75,9 +74,6 @@
     bool do_edit_file (const std::string& file);
     bool do_prompt_new_edit_file (const std::string& file);
 
-    int do_message_dialog (const std::string& dlg, const std::string& msg,
-                           const std::string& title);
-
     std::string
     do_question_dialog (const std::string& msg, const std::string& title,
                         const std::string& btn1, const std::string& btn2,
@@ -112,10 +108,16 @@
 
     void do_change_directory (const std::string& dir);
 
+    void do_file_remove (const std::string& old_name,
+                         const std::string& new_name);
+    void do_file_renamed (bool load_new = true);
+
     void do_execute_command_in_terminal (const std::string& command);
 
+    uint8NDArray do_get_named_icon (const std::string& icon_name);
+
     void do_set_workspace (bool top_level, bool debug,
-                           const symbol_scope& scope,
+                           const symbol_info_list& syminfo,
                            bool update_variable_editor);
 
     void do_clear_workspace (void);
@@ -134,13 +136,12 @@
     void do_update_breakpoint (bool insert, const std::string& file, int line,
                                const std::string& cond);
 
-    void do_set_default_prompts (std::string& ps1, std::string& ps2,
-                                 std::string& ps4);
-
     static bool file_in_path (const std::string& file, const std::string& dir);
 
     void do_show_preferences (void);
 
+    std::string do_gui_preference (const std::string& key,
+                                   const std::string& value);
     void do_show_doc (const std::string& file);
     void do_register_doc (const std::string& file);
     void do_unregister_doc (const std::string& file);
@@ -159,8 +160,6 @@
     void do_insert_debugger_pointer (const std::string& file, int line);
     void do_delete_debugger_pointer (const std::string& file, int line);
 
-    gui_application *m_app_context;
-
     bool m_shutdown_confirm_result;
 
     QMutex m_mutex;
@@ -174,10 +173,13 @@
 
     void change_directory_signal (const QString& dir);
 
+    void file_remove_signal (const QString& old_name, const QString& new_name);
+    void file_renamed_signal (bool load_new);
+
     void execute_command_in_terminal_signal (const QString& command);
 
     void set_workspace_signal (bool top_level, bool debug,
-                               const symbol_scope& scope);
+                               const symbol_info_list& syminfo);
 
     void clear_workspace_signal (void);
 
@@ -196,6 +198,8 @@
 
     void show_preferences_signal (void);
 
+    void gui_preference_signal (const QString&, const QString&, QString*);
+
     void show_doc_signal (const QString& file);
 
     void register_doc_signal (const QString& file);
--- a/libgui/src/octave-settings.h	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
-
-Copyright (C) 2017-2018 Torsten <mttl@mailbox.de>
-
-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_settings_h)
-#define octave_settings_h 1
-
-//#if defined (HAVE_CONFIG_H)
-//#  include "config.h"
-//#endif
-
-#include <QStringList>
-
-// Octave comment strings
-const QString oct_comment_str_old ("editor/octave_comment_string");
-const int oct_comment_str_old_d = 0;
-
-const QString oct_comment_str ("editor/oct_comment_str");
-const QString oct_uncomment_str ("editor/oct_uncomment_str");
-const QString oct_last_comment_str ("editor/oct_last_comment_str");
-const QStringList oct_comment_strings (QStringList () << "##" << "#" << "%"<< "%%" << "%!");
-const int oct_comment_strings_count = 5;
-const int oct_comment_str_d = 0;
-const int oct_uncomment_str_d = 1 + 2 + 4 + 8;
-
-#endif
--- a/libgui/src/resource-manager.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/resource-manager.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -47,6 +47,7 @@
 #include "workspace-model.h"
 #include "variable-editor.h"
 #include "resource-manager.h"
+#include "gui-preferences.h"
 
 namespace octave
 {
@@ -55,11 +56,11 @@
   static QString
   default_qt_settings_file (void)
   {
-    std::string dsf = octave::sys::env::getenv ("OCTAVE_DEFAULT_QT_SETTINGS");
+    std::string dsf = sys::env::getenv ("OCTAVE_DEFAULT_QT_SETTINGS");
 
     if (dsf.empty ())
-      dsf = (octave::config::oct_etc_dir ()
-             + octave::sys::file_ops::dir_sep_str ()
+      dsf = (config::oct_etc_dir ()
+             + sys::file_ops::dir_sep_str ()
              + "default-qt-settings");
 
     return QString::fromStdString (dsf);
@@ -94,9 +95,9 @@
   QString resource_manager::get_gui_translation_dir (void)
   {
     // get environment variable for the locale dir (e.g. from run-octave)
-    std::string dldir = octave::sys::env::getenv ("OCTAVE_LOCALE_DIR");
+    std::string dldir = sys::env::getenv ("OCTAVE_LOCALE_DIR");
     if (dldir.empty ())
-      dldir = octave::config::oct_locale_dir (); // env-var empty, load the default location
+      dldir = config::oct_locale_dir (); // env-var empty, load the default location
     return QString::fromStdString (dldir);
   }
 
@@ -205,8 +206,28 @@
     return m_settings_file;
   }
 
+  QString resource_manager::do_get_default_font_family (void)
+  {
+    // Get the default monospaced font
+#if defined (HAVE_QFONT_MONOSPACE)
+    QFont fixed_font;
+    fixed_font.setStyleHint (QFont::Monospace);
+    QString default_family = fixed_font.defaultFamily ();
+#else
+    QString default_family = global_font_family;
+#endif
+
+    std::string env_default_family = sys::env::getenv ("OCTAVE_DEFAULT_FONT");
+    if (! env_default_family.empty ())
+      default_family = QString::fromStdString (env_default_family);
+
+    return default_family;
+  }
+
   void resource_manager::do_reload_settings (void)
   {
+    QString default_family = do_get_default_font_family ();
+
     if (! QFile::exists (m_settings_file))
       {
         QDir ("/").mkpath (m_settings_directory);
@@ -219,18 +240,15 @@
         QString settings_text = in.readAll ();
         qt_settings.close ();
 
-        // Get the default monospaced font
-#if defined (HAVE_QFONT_MONOSPACE)
-        QFont fixed_font;
-        fixed_font.setStyleHint (QFont::Monospace);
-        QString default_family = fixed_font.defaultFamily ();
-#elif defined (Q_WS_X11) || defined (Q_WS_WIN)
-        QString default_family = "Courier New";
-#elif defined (Q_WS_MAC)
-        QString default_family = "Courier";
-#else
-        QString default_family = "courier";
-#endif
+        default_family = do_get_default_font_family ();
+
+        QString default_font_size = "10";
+
+        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)
@@ -239,10 +257,16 @@
         QString custom_editor = "emacs +%l %f";
 #endif
 
+        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__", "10");
+        settings_text.replace ("__default_font_size__", default_font_size);
 
         QFile user_settings (m_settings_file);
 
@@ -257,6 +281,12 @@
       }
 
     do_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 prefernces.
+    if (m_settings)
+      m_settings->setValue (global_mono_font.key, default_family);
+
   }
 
   void resource_manager::do_set_settings (const QString& file)
@@ -333,6 +363,12 @@
 
   QIcon resource_manager::do_icon (const QString& icon_name, bool fallback)
   {
+    // If system icon theme is not desired, take own icon files
+    if (! m_settings->value (global_icon_theme.key, global_icon_theme.def).toBool ())
+      return QIcon (":/actions/icons/" + icon_name + ".png");
+
+    // Use system icon theme with own files as fallback except the fallback is
+    // explicitly disabled (fallback=false)
     if (fallback)
       return QIcon::fromTheme (icon_name,
                                QIcon (":/actions/icons/" + icon_name + ".png"));
@@ -340,34 +376,44 @@
       return QIcon::fromTheme (icon_name);
   }
 
-  // initialize a given combo box with available text encodings
-  void resource_manager::do_combo_encoding (QComboBox *combo, QString current)
+  // get a list of all available encodings
+  void resource_manager::do_get_codecs (QStringList *codecs)
   {
     // get the codec name for each mib
     QList<int> all_mibs = QTextCodec::availableMibs ();
-    QStringList all_codecs;
     foreach (int mib, all_mibs)
       {
         QTextCodec *c = QTextCodec::codecForMib (mib);
-        all_codecs << c->name ().toUpper ();
+        codecs->append (c->name ().toUpper ());
       }
-    all_codecs.removeDuplicates ();
-    qSort (all_codecs);
+    codecs->removeDuplicates ();
+    qSort (*codecs);
+  }
 
-    // the default encoding
-#if defined (Q_OS_WIN32)
-    QString def_enc = "SYSTEM";
-#else
-    QString def_enc = "UTF-8";
-#endif
+  // initialize a given combo box with available text encodings
+  void resource_manager::do_combo_encoding (QComboBox *combo, QString current)
+  {
+    QStringList all_codecs;
+    do_get_codecs (&all_codecs);
 
     // get the value from the settings file if no current encoding is given
     QString enc = current;
+
+    bool default_exists = false;
+    if (QTextCodec::codecForName (ed_default_enc.def.toString ().toLatin1 ()))
+      default_exists = true;
+
     if (enc.isEmpty ())
       {
-        enc = m_settings->value ("editor/default_encoding",def_enc).toString ();
+        enc = m_settings->value (ed_default_enc.key, ed_default_enc.def).toString ();
+
         if (enc.isEmpty ())  // still empty?
-          enc = def_enc;     // take default
+          {
+            if (default_exists)
+              enc = ed_default_enc.def.toString ();
+            else
+              enc = QTextCodec::codecForLocale ()->name ().toUpper ();
+          }
       }
 
     // fill the combo box
@@ -376,10 +422,13 @@
 
     // prepend the default item
     combo->insertSeparator (0);
-    combo->insertItem (0, def_enc);
+    if (default_exists)
+      combo->insertItem (0, ed_default_enc.def.toString ());
+    else
+      combo->insertItem (0, QTextCodec::codecForLocale ()->name ().toUpper ());
 
-    // select the current/default item
-    int idx = combo->findText (enc);
+    // select the default or the current one
+    int idx = combo->findText (enc, Qt::MatchExactly);
     if (idx >= 0)
       combo->setCurrentIndex (idx);
     else
--- a/libgui/src/resource-manager.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/resource-manager.h	Thu Dec 20 17:18:56 2018 -0500
@@ -93,6 +93,12 @@
               : false);
     }
 
+    static void get_codecs (QStringList *codecs)
+    {
+      if (instance_ok ())
+        instance->do_get_codecs (codecs);
+    }
+
     static void combo_encoding (QComboBox *combo, QString current = QString ())
     {
       if (instance_ok ())
@@ -144,6 +150,8 @@
 
     QString do_get_settings_file (void);
 
+    QString do_get_default_font_family (void);
+
     void do_reload_settings (void);
 
     void do_set_settings (const QString& file);
@@ -156,6 +164,7 @@
 
     QIcon do_icon (const QString& icon, bool fallback);
 
+    void do_get_codecs (QStringList *codecs);
     void do_combo_encoding (QComboBox *combo, QString current);
 
     QString m_settings_directory;
@@ -168,8 +177,4 @@
   };
 }
 
-// FIXME: This is temporary and should be removed when all classes that
-// use the resource_manager class are also inside the octave namespace.
-using octave::resource_manager;
-
 #endif
--- a/libgui/src/resource.qrc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/resource.qrc	Thu Dec 20 17:18:56 2018 -0500
@@ -10,6 +10,9 @@
         <file>icons/db-step-in.png</file>
         <file>icons/db-step-out.png</file>
         <file>icons/db-stop.png</file>
+        <file>icons/dialog-error.png</file>
+        <file>icons/dialog-information.png</file>
+        <file>icons/dialog-warning.png</file>
         <file>icons/document-new.png</file>
         <file>icons/document-open.png</file>
         <file>icons/document-print.png</file>
@@ -27,7 +30,10 @@
         <file>icons/folder-new.png</file>
         <file>icons/go-down.png</file>
         <file>icons/go-first.png</file>
+        <file>icons/go-home.png</file>
         <file>icons/go-last.png</file>
+        <file>icons/go-next.png</file>
+        <file>icons/go-previous.png</file>
         <file>icons/go-up.png</file>
         <file>icons/graphic_logo_FilesDockWidget.png</file>
         <file>icons/graphic_logo_FileEditor.png</file>
@@ -60,6 +66,7 @@
         <file>icons/widget-dock-light.png</file>
         <file>icons/widget-undock-light.png</file>
         <file>icons/zoom-in.png</file>
+        <file>icons/zoom-original.png</file>
         <file>icons/zoom-out.png</file>
     </qresource>
 </RCC>
--- a/libgui/src/settings-dialog.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/settings-dialog.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -33,7 +33,7 @@
 #include "variable-editor.h"
 #include "workspace-model.h"
 #include "settings-dialog.h"
-#include "ui-settings-dialog.h"
+#include "gui-preferences.h"
 
 #include <QButtonGroup>
 #include <QDir>
@@ -42,6 +42,8 @@
 #include <QVector>
 #include <QHash>
 #include <QMessageBox>
+#include <QScrollBar>
+#include <QStyleFactory>
 #include <QTextCodec>
 
 #if defined (HAVE_QSCINTILLA)
@@ -64,1086 +66,1146 @@
 #  include <Qsci/qscilexerdiff.h>
 #endif
 
+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;
-}
-
-static void
-read_lexer_settings (Ui::settings_dialog *ui, QsciLexer *lexer,
-                     QSettings *settings)
-{
-  lexer->readSettings (*settings);
-  int styles[MaxLexerStyles];  // array for saving valid styles
-                               // (enum is not continuous)
-  int max_style = get_valid_lexer_styles (lexer, styles);
-  QGridLayout *style_grid = new QGridLayout ();
-  QVector<QLabel*> description (max_style);
-  QVector<QFontComboBox*> select_font (max_style);
-  QVector<QSpinBox*> font_size (max_style);
-  QVector<QCheckBox*> attrib_font (3 * max_style);
-  QVector<color_picker*> color (max_style);
-  QVector<color_picker*> bg_color (max_style);
-  int default_size = 10;
-  QFont default_font = QFont ();
-  int label_width;
-  QColor default_color = QColor ();
-  QColor dummy_color = QColor (255, 0, 255);
+  static const int MaxLexerStyles = 64;
+  static const int MaxStyleNumber = 128;
 
-  for (int i = 0; i < max_style; i++)  // create dialog elements for all styles
-    {
-      QString actual_name = lexer->description (styles[i]);
-      QFont   actual_font = lexer->font (styles[i]);
-      description[i] = new QLabel (actual_name);
-      description[i]->setWordWrap (true);
-      label_width = 24*description[i]->fontMetrics ().averageCharWidth ();
-      description[i]->setMaximumSize (label_width, QWIDGETSIZE_MAX);
-      description[i]->setMinimumSize (label_width, 1);
-      select_font[i] = new QFontComboBox ();
-      select_font[i]->setObjectName (actual_name + "_font");
-      select_font[i]->setMaximumSize (label_width, QWIDGETSIZE_MAX);
-      select_font[i]->setMinimumSize (label_width, 1);
-      font_size[i] = new QSpinBox ();
-      font_size[i]->setObjectName (actual_name + "_size");
-      if (styles[i] == 0) // the default
-        {
-          select_font[i]->setCurrentFont (actual_font);
-          default_font = actual_font;
-          font_size[i]->setRange (6, 24);
-          default_size = actual_font.pointSize ();
-          font_size[i]->setValue (default_size);
-          default_color = lexer->defaultPaper ();
-          bg_color[i] = new color_picker (default_color);
-        }
-      else   // other styles
-        {
-          select_font[i]->setCurrentFont (actual_font);
-          if (actual_font.family () == default_font.family ())
-            select_font[i]->setEditText (lexer->description (0));
-          font_size[i]->setRange (-4, 4);
-          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);
-          else
-            bg_color[i] = new color_picker (lexer->paper (styles[i]));
-          bg_color[i]->setToolTip
-            (QObject::tr ("Background color, pink (255, 0, 255) means default"));
-        }
-      attrib_font[0+3*i] = new QCheckBox (QObject::tr ("b", "short form for bold"));
-      attrib_font[1+3*i] = new QCheckBox (QObject::tr ("i", "short form for italic"));
-      attrib_font[2+3*i] = new QCheckBox (QObject::tr ("u", "short form for underlined"));
-      attrib_font[0+3*i]->setChecked (actual_font.bold ());
-      attrib_font[0+3*i]->setObjectName (actual_name + "_bold");
-      attrib_font[1+3*i]->setChecked (actual_font.italic ());
-      attrib_font[1+3*i]->setObjectName (actual_name + "_italic");
-      attrib_font[2+3*i]->setChecked (actual_font.underline ());
-      attrib_font[2+3*i]->setObjectName (actual_name + "_underline");
-      color[i] = new color_picker (lexer->color (styles[i]));
-      color[i]->setObjectName (actual_name + "_color");
-      bg_color[i]->setObjectName (actual_name + "_bg_color");
-      int column = 1;
-      style_grid->addWidget (description[i], i, column++);
-      style_grid->addWidget (select_font[i], i, column++);
-      style_grid->addWidget (font_size[i], i, column++);
-      style_grid->addWidget (attrib_font[0+3*i], i, column++);
-      style_grid->addWidget (attrib_font[1+3*i], i, column++);
-      style_grid->addWidget (attrib_font[2+3*i], i, column++);
-      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 ();
-  scroll_area_contents->setObjectName (QString (lexer->language ()) + "_styles");
-  scroll_area_contents->setLayout (style_grid);
-  scroll_area->setWidget (scroll_area_contents);
-  ui->tabs_editor_lexers->addTab (scroll_area, lexer->language ());
-
-  ui->tabs_editor_lexers->setCurrentIndex (settings->value ("settings/last_editor_styles_tab", 0).toInt ());
-}
-
-static void
-write_lexer_settings (Ui::settings_dialog *ui, QsciLexer *lexer,
-                      QSettings *settings)
-{
-  QWidget *tab = ui->tabs_editor_lexers->
-                 findChild <QWidget *> (QString (lexer->language ()) + "_styles");
-  int styles[MaxLexerStyles];  // array for saving valid styles
-                               // (enum is not continuous)
-  int max_style = get_valid_lexer_styles (lexer, styles);
-  QFontComboBox *select_font;
-  QSpinBox *font_size;
-  QCheckBox *attrib_font[3];
-  color_picker *color;
-  color_picker *bg_color;
-  int default_size = 10;
-  QFont default_font = QFont ("Courier New", 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
-    {
-      QString actual_name = lexer->description (styles[i]);
-      select_font = tab->findChild <QFontComboBox *> (actual_name + "_font");
-      font_size = tab->findChild <QSpinBox *> (actual_name + "_size");
-      attrib_font[0] = tab->findChild <QCheckBox *> (actual_name + "_bold");
-      attrib_font[1] = tab->findChild <QCheckBox *> (actual_name + "_italic");
-      attrib_font[2] = tab->findChild <QCheckBox *> (actual_name + "_underline");
-      color = tab->findChild <color_picker *> (actual_name + "_color");
-      bg_color = tab->findChild <color_picker *> (actual_name + "_bg_color");
-      QFont new_font = default_font;
-      if (select_font)
-        {
-          new_font = select_font->currentFont ();
-          if (styles[i] == 0)
-            default_font = new_font;
-          else if (select_font->currentText () == lexer->description (0))
-            new_font = default_font;
-        }
-      if (font_size)
-        {
-          if (styles[i] == 0)
-            {
-              default_size = font_size->value ();
-              new_font.setPointSize (font_size->value ());
-            }
-          else
-            new_font.setPointSize (font_size->value ()+default_size);
-        }
-      if (attrib_font[0])
-        new_font.setBold (attrib_font[0]->isChecked ());
-      if (attrib_font[1])
-        new_font.setItalic (attrib_font[1]->isChecked ());
-      if (attrib_font[2])
-        new_font.setUnderline (attrib_font[2]->isChecked ());
-      lexer->setFont (new_font, styles[i]);
-      if (styles[i] == 0)
-        lexer->setDefaultFont (new_font);
-      if (color)
-        lexer->setColor (color->color (), styles[i]);
-      if (bg_color)
-        {
-          if (styles[i] == 0)
-            {
-              default_color = bg_color->color ();
-              lexer->setPaper (default_color, styles[i]);
-              lexer->setDefaultPaper (default_color);
-            }
-          else
-            {
-              if (bg_color->color () == dummy_color)
-                lexer->setPaper (default_color, styles[i]);
-              else
-                lexer->setPaper (bg_color->color (), styles[i]);
-            }
-        }
-    }
-
-  lexer->writeSettings (*settings);
-
-  settings->setValue ("settings/last_editor_styles_tab",
-                      ui->tabs_editor_lexers->currentIndex ());
-  settings->sync ();
-}
+  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, const QString& desired_tab):
-  QDialog (p), ui (new Ui::settings_dialog)
-{
-  ui->setupUi (this);
+  settings_dialog::settings_dialog (QWidget *p, const QString& desired_tab)
+    : QDialog (p), Ui::settings_dialog ()
+  {
+    setupUi (this);
 
-  QSettings *settings = resource_manager::get_settings ();
+    QSettings *settings = resource_manager::get_settings ();
 
-  if (! settings)
-    {
-      QMessageBox msgBox
-        (QMessageBox::Warning, tr ("Octave Settings"),
-         tr ("Unable to save settings.  Missing settings file or unknown directory."));
+    if (! settings)
+      {
+        QMessageBox msgBox
+          (QMessageBox::Warning, tr ("Octave Preferences"),
+           tr ("Unable to save preferences.  Missing preferences file or unknown directory."));
 
-      msgBox.exec ();
+        msgBox.exec ();
 
-      return;
-    }
+        return;
+      }
 
-  // look for available language files and the actual settings
-  QString qm_dir_name = resource_manager::get_gui_translation_dir ();
-  QDir qm_dir (qm_dir_name);
-  QFileInfoList qm_files = qm_dir.entryInfoList (QStringList ("*.qm"), QDir::Files | QDir::Readable, QDir::Name);
+    // look for available language files and the actual settings
+    QString qm_dir_name = resource_manager::get_gui_translation_dir ();
+    QDir qm_dir (qm_dir_name);
+    QFileInfoList qm_files = qm_dir.entryInfoList (QStringList ("*.qm"), QDir::Files | QDir::Readable, QDir::Name);
 
-  for (int i = 0; i < qm_files.length (); i++)   // insert available languages
-    ui->comboBox_language->addItem (qm_files.at (i).baseName ());
-  // System at beginning
-  ui->comboBox_language->insertItem (0, tr ("System setting"));
-  ui->comboBox_language->insertSeparator (1);    // separator after System
-  QString language = settings->value ("language", "SYSTEM").toString ();
-  if (language == "SYSTEM")
-    language = tr ("System setting");
-  int selected = ui->comboBox_language->findText (language);
-  if (selected >= 0)
-    ui->comboBox_language->setCurrentIndex (selected);
-  else
-    ui->comboBox_language->setCurrentIndex (0);  // System is default
+    for (int i = 0; i < qm_files.length (); i++)   // insert available languages
+      comboBox_language->addItem (qm_files.at (i).baseName ());
+    // System at beginning
+    comboBox_language->insertItem (0, tr ("System setting"));
+    comboBox_language->insertSeparator (1);    // separator after System
+    QString language = settings->value ("language", "SYSTEM").toString ();
+    if (language == "SYSTEM")
+      language = tr ("System setting");
+    int selected = comboBox_language->findText (language);
+    if (selected >= 0)
+      comboBox_language->setCurrentIndex (selected);
+    else
+      comboBox_language->setCurrentIndex (0);  // System is default
 
-  // icon size
-  QButtonGroup *icon_size_group = new QButtonGroup (this);
-  icon_size_group->addButton (ui->icon_size_small);
-  icon_size_group->addButton (ui->icon_size_normal);
-  icon_size_group->addButton (ui->icon_size_large);
-  int icon_size = settings->value ("toolbar_icon_size", 0).toInt ();
-  ui->icon_size_normal->setChecked (true);  // the default
-  ui->icon_size_small->setChecked (icon_size == -1);
-  ui->icon_size_large->setChecked (icon_size == 1);
+    // Global style
+    QStringList styles = QStyleFactory::keys();
+    combo_styles->addItems (styles);
+    combo_styles->insertItem (0, global_style.def.toString ());
+    combo_styles->insertSeparator (1);
+    QString current_style = settings->value (global_style.key, global_style.def).toString ();
+    if (current_style == global_style.def.toString ())
+      current_style = global_style.def.toString ();
+    selected = combo_styles->findText (current_style);
+    if (selected >= 0)
+      combo_styles->setCurrentIndex (selected);
+    else
+      combo_styles->setCurrentIndex (0);
 
-  // which icon has to be selected
-  QButtonGroup *icon_group = new QButtonGroup (this);
-  icon_group->addButton (ui->general_icon_octave);
-  icon_group->addButton (ui->general_icon_graphic);
-  icon_group->addButton (ui->general_icon_letter);
-  QString widget_icon_set =
-    settings->value ("DockWidgets/widget_icon_set", "NONE").toString ();
-  ui->general_icon_octave->setChecked (true);  // the default (if invalid set)
-  ui->general_icon_octave->setChecked (widget_icon_set == "NONE");
-  ui->general_icon_graphic->setChecked (widget_icon_set == "GRAPHIC");
-  ui->general_icon_letter->setChecked (widget_icon_set == "LETTER");
+    // icon size and theme
+    QButtonGroup *icon_size_group = new QButtonGroup (this);
+    icon_size_group->addButton (icon_size_small);
+    icon_size_group->addButton (icon_size_normal);
+    icon_size_group->addButton (icon_size_large);
+    int icon_size = settings->value (global_icon_size.key, global_icon_size.def).toInt ();
+    icon_size_normal->setChecked (true);  // the default
+    icon_size_small->setChecked (icon_size < 0);
+    icon_size_large->setChecked (icon_size > 0);
+    cb_system_icon_theme->setChecked (settings->value (global_icon_theme.key, global_icon_theme.def).toBool ());
 
-  // custom title bar of dock widget
-  QVariant default_var = QColor (255, 255, 255);
-  QColor bg_color = settings->value ("DockWidgets/title_bg_color",
-                                     default_var).value<QColor> ();
-  m_widget_title_bg_color = new color_picker (bg_color);
-  m_widget_title_bg_color->setEnabled (false);
-  ui->layout_widget_bgtitle->addWidget (m_widget_title_bg_color, 0);
+    // which icon has to be selected
+    QButtonGroup *icon_group = new QButtonGroup (this);
+    icon_group->addButton (general_icon_octave);
+    icon_group->addButton (general_icon_graphic);
+    icon_group->addButton (general_icon_letter);
+    QString widget_icon_set =
+      settings->value ("DockWidgets/widget_icon_set", "NONE").toString ();
+    general_icon_octave->setChecked (true);  // the default (if invalid set)
+    general_icon_octave->setChecked (widget_icon_set == "NONE");
+    general_icon_graphic->setChecked (widget_icon_set == "GRAPHIC");
+    general_icon_letter->setChecked (widget_icon_set == "LETTER");
 
-  connect (ui->cb_widget_custom_style, SIGNAL (toggled (bool)),
-           m_widget_title_bg_color, SLOT (setEnabled (bool)));
+    // custom title bar of dock widget
+    QVariant default_var = QColor (255, 255, 255);
+    QColor bg_color = settings->value ("DockWidgets/title_bg_color",
+                                       default_var).value<QColor> ();
+    m_widget_title_bg_color = new color_picker (bg_color);
+    m_widget_title_bg_color->setEnabled (false);
+    layout_widget_bgtitle->addWidget (m_widget_title_bg_color, 0);
 
-  default_var = QColor (192, 192, 192);
-  QColor bg_color_active = settings->value ("DockWidgets/title_bg_color_active",
-                                            default_var).value<QColor> ();
-  m_widget_title_bg_color_active = new color_picker (bg_color_active);
-  m_widget_title_bg_color_active->setEnabled (false);
-  ui->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, SLOT (setEnabled (bool)));
 
-  connect (ui->cb_widget_custom_style, SIGNAL (toggled (bool)),
-           m_widget_title_bg_color_active, SLOT (setEnabled (bool)));
+    default_var = QColor (192, 192, 192);
+    QColor bg_color_active = settings->value ("DockWidgets/title_bg_color_active",
+                                              default_var).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)));
 
-  default_var = QColor (0, 0, 0);
-  QColor fg_color = settings->value ("DockWidgets/title_fg_color",
-                                     default_var).value<QColor> ();
-  m_widget_title_fg_color = new color_picker (fg_color);
-  m_widget_title_fg_color->setEnabled (false);
-  ui->layout_widget_fgtitle->addWidget (m_widget_title_fg_color, 0);
+    default_var = QColor (0, 0, 0);
+    QColor fg_color = settings->value ("DockWidgets/title_fg_color",
+                                       default_var).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 (ui->cb_widget_custom_style, SIGNAL (toggled (bool)),
-           m_widget_title_fg_color, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
+             m_widget_title_fg_color, SLOT (setEnabled (bool)));
 
-  default_var = QColor (0, 0, 0);
-  QColor fg_color_active = settings->value ("DockWidgets/title_fg_color_active",
-                                            default_var).value<QColor> ();
-  m_widget_title_fg_color_active = new color_picker (fg_color_active);
-  m_widget_title_fg_color_active->setEnabled (false);
-  ui->layout_widget_fgtitle_active->addWidget (m_widget_title_fg_color_active, 0);
+    default_var = QColor (0, 0, 0);
+    QColor fg_color_active = settings->value ("DockWidgets/title_fg_color_active",
+                                              default_var).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 (ui->cb_widget_custom_style, SIGNAL (toggled (bool)),
-           m_widget_title_fg_color_active, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
+             m_widget_title_fg_color_active, SLOT (setEnabled (bool)));
 
-  ui->sb_3d_title->setValue (settings->value ("DockWidgets/widget_title_3d", 50).toInt ());
-  ui->cb_widget_custom_style->setChecked (settings->value ("DockWidgets/widget_title_custom_style", false).toBool ());
+    sb_3d_title->setValue (settings->value ("DockWidgets/widget_title_3d", 50).toInt ());
+    cb_widget_custom_style->setChecked (settings->value ("DockWidgets/widget_title_custom_style", false).toBool ());
 
-  // Cursor blinking: consider old terminal related setting if not yet set
-  // TODO: This pref. can be deprecated / removed if Qt adds support for
-  //       getting the cursor blink preferences from all OS environments
-  if (settings->contains ("cursor_blinking"))
-    {
-      // Preference exists, read its value
-      ui->cb_cursor_blinking->setChecked (settings->value ("cursor_blinking", true).toBool ());
-    }
-  else
-    {
-      // Pref. does not exist, so take old terminal related pref.
-      ui->cb_cursor_blinking->setChecked (settings->value ("terminal/cursorBlinking", true).toBool ());
-    }
+    // Native file dialogs.
+    // FIXME: This preference can be deprecated / removed if all display
+    //       managers, especially KDE, run those dialogs without hangs or
+    //       delays from the start (bug #54607).
+    cb_use_native_file_dialogs->setChecked (settings->value ("use_native_file_dialogs", true).toBool ());
 
-  // prompt on exit
-  ui->cb_prompt_to_exit->setChecked (settings->value ("prompt_to_exit", false).toBool ());
+    // Cursor blinking: consider old terminal related setting if not yet set
+    // FIXME: This pref. can be deprecated / removed if Qt adds support for
+    //       getting the cursor blink preferences from all OS environments
+    if (settings->contains ("cursor_blinking"))
+      {
+        // Preference exists, read its value
+        cb_cursor_blinking->setChecked (settings->value ("cursor_blinking", true).toBool ());
+      }
+    else
+      {
+        // Pref. does not exist, so take old terminal related pref.
+        cb_cursor_blinking->setChecked (settings->value ("terminal/cursorBlinking", true).toBool ());
+      }
 
-  // Main status bar
-  ui->cb_status_bar->setChecked (settings->value ("show_status_bar", true).toBool ());
+    // prompt on exit
+    cb_prompt_to_exit->setChecked (settings->value ("prompt_to_exit", false).toBool ());
+
+    // Main status bar
+    cb_status_bar->setChecked (settings->value ("show_status_bar", true).toBool ());
 
-  // Octave startup
-  ui->cb_restore_octave_dir->setChecked (settings->value ("restore_octave_dir", false).toBool ());
-  ui->le_octave_dir->setText (settings->value ("octave_startup_dir").toString ());
+    // Octave startup
+    cb_restore_octave_dir->setChecked (settings->value ("restore_octave_dir", false).toBool ());
+    le_octave_dir->setText (settings->value ("octave_startup_dir").toString ());
 
-  connect (ui->pb_octave_dir, SIGNAL (pressed (void)),
-           this, SLOT (get_octave_dir (void)));
+    connect (pb_octave_dir, SIGNAL (pressed (void)),
+             this, SLOT (get_octave_dir (void)));
 
-  //
-  // editor
-  //
-  ui->useCustomFileEditor->setChecked (settings->value ("useCustomFileEditor", false).toBool ());
-  ui->customFileEditor->setText (settings->value ("customFileEditor").toString ());
-  ui->editor_showLineNumbers->setChecked (settings->value ("editor/showLineNumbers", true).toBool ());
-  ui->editor_linenr_size->setValue (settings->value ("editor/line_numbers_size", 0).toInt ());
+    //
+    // editor
+    //
+    useCustomFileEditor->setChecked (settings->value ("useCustomFileEditor", false).toBool ());
+    customFileEditor->setText (settings->value ("customFileEditor").toString ());
+    editor_showLineNumbers->setChecked (settings->value ("editor/showLineNumbers", true).toBool ());
+    editor_linenr_size->setValue (settings->value ("editor/line_numbers_size", 0).toInt ());
 
-  resource_manager::combo_encoding (ui->editor_combo_encoding);
+    resource_manager::combo_encoding (editor_combo_encoding);
 
-  default_var = QColor (240, 240, 240);
-  QColor setting_color = settings->value ("editor/highlight_current_line_color", default_var).value<QColor> ();
-  m_editor_current_line_color = new color_picker (setting_color);
-  ui->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);
+    default_var = QColor (240, 240, 240);
+    QColor setting_color = settings->value ("editor/highlight_current_line_color", default_var).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 (ui->editor_highlightCurrentLine, SIGNAL (toggled (bool)),
-           m_editor_current_line_color, SLOT (setEnabled (bool)));
+    connect (editor_highlightCurrentLine, SIGNAL (toggled (bool)),
+             m_editor_current_line_color, SLOT (setEnabled (bool)));
 
-  ui->editor_highlightCurrentLine->setChecked (settings->value ("editor/highlightCurrentLine", true).toBool ());
-  ui->editor_long_line_marker->setChecked (settings->value ("editor/long_line_marker", true).toBool ());
-  bool long_line =
-    settings->value ("editor/long_line_marker_line", true).toBool ();
-  ui->editor_long_line_marker_line->setChecked (long_line);
-  bool long_back =
-    settings->value ("editor/long_line_marker_background", false).toBool ();
-  ui->editor_long_line_marker_background->setChecked (long_back);
-  if (! (long_line || long_back))
-    ui->editor_long_line_marker_line->setChecked (true);
-  ui->editor_long_line_column->setValue (settings->value ("editor/long_line_column", 80).toInt ());
-  ui->editor_break_checkbox->setChecked (settings->value ("editor/break_lines", false).toBool ());
-  ui->editor_break_checkbox->setChecked (settings->value ("editor/break_lines_comments", false).toBool ());
-  ui->editor_wrap_checkbox->setChecked (settings->value ("editor/wrap_lines", false).toBool ());
-  ui->cb_edit_status_bar->setChecked (settings->value ("editor/show_edit_status_bar", true).toBool ());
-  ui->cb_edit_tool_bar->setChecked (settings->value ("editor/show_toolbar", true).toBool ());
-  ui->cb_code_folding->setChecked (settings->value ("editor/code_folding", true).toBool ());
-  ui->editor_highlight_all_occurrences->setChecked (settings->value ("editor/highlight_all_occurrences", true).toBool ());
+    editor_highlightCurrentLine->setChecked (settings->value ("editor/highlightCurrentLine", true).toBool ());
+    editor_long_line_marker->setChecked (settings->value ("editor/long_line_marker", true).toBool ());
+    bool long_line =
+      settings->value ("editor/long_line_marker_line", true).toBool ();
+    editor_long_line_marker_line->setChecked (long_line);
+    bool long_back =
+      settings->value ("editor/long_line_marker_background", false).toBool ();
+    editor_long_line_marker_background->setChecked (long_back);
+    if (! (long_line || long_back))
+      editor_long_line_marker_line->setChecked (true);
+    editor_long_line_column->setValue (settings->value ("editor/long_line_column", 80).toInt ());
+    editor_break_checkbox->setChecked (settings->value ("editor/break_lines", false).toBool ());
+    editor_break_checkbox->setChecked (settings->value ("editor/break_lines_comments", false).toBool ());
+    editor_wrap_checkbox->setChecked (settings->value ("editor/wrap_lines", false).toBool ());
+    cb_edit_status_bar->setChecked (settings->value ("editor/show_edit_status_bar", true).toBool ());
+    cb_edit_tool_bar->setChecked (settings->value ("editor/show_toolbar", true).toBool ());
+    cb_code_folding->setChecked (settings->value ("editor/code_folding", true).toBool ());
+    editor_highlight_all_occurrences->setChecked (settings->value ("editor/highlight_all_occurrences", true).toBool ());
 
-  ui->editor_auto_endif->setCurrentIndex (settings->value ("editor/auto_endif", 1).toInt () );
-  ui->editor_codeCompletion->setChecked (settings->value ("editor/codeCompletion", true).toBool ());
-  ui->editor_spinbox_ac_threshold->setValue (settings->value ("editor/codeCompletion_threshold", 2).toInt ());
-  ui->editor_checkbox_ac_keywords->setChecked (settings->value ("editor/codeCompletion_keywords", true).toBool ());
-  ui->editor_checkbox_ac_builtins->setEnabled (ui->editor_checkbox_ac_keywords->isChecked ());
-  ui->editor_checkbox_ac_functions->setEnabled (ui->editor_checkbox_ac_keywords->isChecked ());
-  ui->editor_checkbox_ac_builtins->setChecked (settings->value ("editor/codeCompletion_octave_builtins", true).toBool ());
-  ui->editor_checkbox_ac_functions->setChecked (settings->value ("editor/codeCompletion_octave_functions", true).toBool ());
-  ui->editor_checkbox_ac_document->setChecked (settings->value ("editor/codeCompletion_document", false).toBool ());
-  ui->editor_checkbox_ac_case->setChecked (settings->value ("editor/codeCompletion_case", true).toBool ());
-  ui->editor_checkbox_ac_replace->setChecked (settings->value ("editor/codeCompletion_replace", false).toBool ());
-  ui->editor_ws_checkbox->setChecked (settings->value ("editor/show_white_space", false).toBool ());
-  ui->editor_ws_indent_checkbox->setChecked (settings->value ("editor/show_white_space_indent", false).toBool ());
-  ui->cb_show_eol->setChecked (settings->value ("editor/show_eol_chars", false).toBool ());
-  ui->cb_show_hscrollbar->setChecked (settings->value ("editor/show_hscroll_bar", true).toBool ());
+    editor_auto_endif->setCurrentIndex (settings->value ("editor/auto_endif", 1).toInt () );
+    editor_codeCompletion->setChecked (settings->value ("editor/codeCompletion", true).toBool ());
+    editor_spinbox_ac_threshold->setValue (settings->value ("editor/codeCompletion_threshold", 2).toInt ());
+    editor_checkbox_ac_keywords->setChecked (settings->value ("editor/codeCompletion_keywords", true).toBool ());
+    editor_checkbox_ac_builtins->setEnabled (editor_checkbox_ac_keywords->isChecked ());
+    editor_checkbox_ac_functions->setEnabled (editor_checkbox_ac_keywords->isChecked ());
+    editor_checkbox_ac_builtins->setChecked (settings->value ("editor/codeCompletion_octave_builtins", true).toBool ());
+    editor_checkbox_ac_functions->setChecked (settings->value ("editor/codeCompletion_octave_functions", true).toBool ());
+    editor_checkbox_ac_document->setChecked (settings->value ("editor/codeCompletion_document", false).toBool ());
+    editor_checkbox_ac_case->setChecked (settings->value ("editor/codeCompletion_case", true).toBool ());
+    editor_checkbox_ac_replace->setChecked (settings->value ("editor/codeCompletion_replace", false).toBool ());
+    editor_ws_checkbox->setChecked (settings->value ("editor/show_white_space", false).toBool ());
+    editor_ws_indent_checkbox->setChecked (settings->value ("editor/show_white_space_indent", false).toBool ());
+    cb_show_eol->setChecked (settings->value ("editor/show_eol_chars", false).toBool ());
+    cb_show_hscrollbar->setChecked (settings->value ("editor/show_hscroll_bar", true).toBool ());
 
-  int selected_comment_string, selected_uncomment_string;
+    int selected_comment_string, selected_uncomment_string;
 
-  if (settings->contains (oct_comment_str))   // new version (radio buttons)
-    selected_comment_string = settings->value (oct_comment_str,
-                                               oct_comment_str_d).toInt ();
-  else                                         // old version (combo box)
-    selected_comment_string = settings->value (oct_comment_str_old,
-                                               oct_comment_str_d).toInt ();
+    if (settings->contains (ed_comment_str.key))   // new version (radio buttons)
+      selected_comment_string = settings->value (ed_comment_str.key,
+                                                 ed_comment_str.def).toInt ();
+    else                                         // old version (combo box)
+      selected_comment_string = settings->value (ed_comment_str_old.key,
+                                                 ed_comment_str.def).toInt ();
 
-  selected_uncomment_string = settings->value (oct_uncomment_str,
-                                               oct_uncomment_str_d).toInt ();
+    selected_uncomment_string = settings->value (ed_uncomment_str.key,
+                                                 ed_uncomment_str.def).toInt ();
 
-  for (int i = 0; i < oct_comment_strings_count; i++)
-    {
-      m_rb_comment_strings[i] = new QRadioButton ();
-      m_rb_uncomment_strings[i] = new QRadioButton ();
+    for (int i = 0; i < ed_comment_strings_count; i++)
+      {
+        m_rb_comment_strings[i] = new QRadioButton ();
+        m_rb_uncomment_strings[i] = new QRadioButton ();
 
-      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], 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)));
 
-      m_rb_comment_strings[i]->setText (oct_comment_strings.at(i));
-      m_rb_comment_strings[i]->setChecked (i == selected_comment_string);
-      ui->layout_comment_strings->addWidget (m_rb_comment_strings[i]);
+        m_rb_comment_strings[i]->setText (ed_comment_strings.at(i));
+        m_rb_comment_strings[i]->setChecked (i == selected_comment_string);
+        layout_comment_strings->addWidget (m_rb_comment_strings[i]);
 
-      m_rb_uncomment_strings[i]->setText (oct_comment_strings.at(i));
-      m_rb_uncomment_strings[i]->setAutoExclusive (false);
-      m_rb_uncomment_strings[i]->setChecked ( 1 << i & selected_uncomment_string);
-      ui->layout_uncomment_strings->addWidget (m_rb_uncomment_strings[i]);
-    }
+        m_rb_uncomment_strings[i]->setText (ed_comment_strings.at(i));
+        m_rb_uncomment_strings[i]->setAutoExclusive (false);
+        m_rb_uncomment_strings[i]->setChecked ( 1 << i & selected_uncomment_string);
+        layout_uncomment_strings->addWidget (m_rb_uncomment_strings[i]);
+      }
 
 
 #if defined (HAVE_QSCINTILLA)
 #  if defined (Q_OS_WIN32)
-  int eol_mode = QsciScintilla::EolWindows;
+    int eol_mode = QsciScintilla::EolWindows;
 #elif defined (Q_OS_MAC)
-  int eol_mode = QsciScintilla::EolMac;
+    int eol_mode = QsciScintilla::EolMac;
 #else
-  int eol_mode = QsciScintilla::EolUnix;
+    int eol_mode = QsciScintilla::EolUnix;
 #endif
 #else
-  int eol_mode = 2;
+    int eol_mode = 2;
 #endif
-  ui->combo_eol_mode->setCurrentIndex (settings->value ("editor/default_eol_mode", eol_mode).toInt ());
-  ui->editor_auto_ind_checkbox->setChecked (settings->value ("editor/auto_indent", true).toBool ());
-  ui->editor_tab_ind_checkbox->setChecked (settings->value ("editor/tab_indents_line", false).toBool ());
-  ui->editor_bs_unind_checkbox->setChecked (settings->value ("editor/backspace_unindents_line", false).toBool ());
-  ui->editor_ind_guides_checkbox->setChecked (settings->value ("editor/show_indent_guides", false).toBool ());
-  ui->editor_ind_width_spinbox->setValue (settings->value ("editor/indent_width", 2).toInt ());
-  ui->editor_ind_uses_tabs_checkbox->setChecked (settings->value ("editor/indent_uses_tabs", false).toBool ());
-  ui->editor_tab_width_spinbox->setValue (settings->value ("editor/tab_width", 2).toInt ());
-  ui->editor_longWindowTitle->setChecked (settings->value ("editor/longWindowTitle", false).toBool ());
-  ui->editor_notebook_tab_width_min->setValue (settings->value ("editor/notebook_tab_width_min", 160).toInt ());
-  ui->editor_notebook_tab_width_max->setValue (settings->value ("editor/notebook_tab_width_max", 300).toInt ());
-  ui->editor_restoreSession->setChecked (settings->value ("editor/restoreSession", true).toBool ());
-  ui->editor_create_new_file->setChecked (settings->value ("editor/create_new_file", false).toBool ());
-  ui->editor_reload_changed_files->setChecked (settings->value ("editor/always_reload_changed_files", false).toBool ());
-  ui->editor_hiding_closes_files->setChecked (settings->value ("editor/hiding_closes_files", false).toBool ());
+    combo_eol_mode->setCurrentIndex (settings->value ("editor/default_eol_mode", eol_mode).toInt ());
+    editor_auto_ind_checkbox->setChecked (settings->value ("editor/auto_indent", true).toBool ());
+    editor_tab_ind_checkbox->setChecked (settings->value ("editor/tab_indents_line", false).toBool ());
+    editor_bs_unind_checkbox->setChecked (settings->value ("editor/backspace_unindents_line", false).toBool ());
+    editor_ind_guides_checkbox->setChecked (settings->value ("editor/show_indent_guides", false).toBool ());
+    editor_ind_width_spinbox->setValue (settings->value ("editor/indent_width", 2).toInt ());
+    editor_ind_uses_tabs_checkbox->setChecked (settings->value ("editor/indent_uses_tabs", false).toBool ());
+    editor_tab_width_spinbox->setValue (settings->value ("editor/tab_width", 2).toInt ());
+    editor_longWindowTitle->setChecked (settings->value ("editor/longWindowTitle", false).toBool ());
+    editor_notebook_tab_width_min->setValue (settings->value ("editor/notebook_tab_width_min", 160).toInt ());
+    editor_notebook_tab_width_max->setValue (settings->value ("editor/notebook_tab_width_max", 300).toInt ());
+    editor_restoreSession->setChecked (settings->value ("editor/restoreSession", true).toBool ());
+    editor_create_new_file->setChecked (settings->value ("editor/create_new_file", false).toBool ());
+    editor_reload_changed_files->setChecked (settings->value ("editor/always_reload_changed_files", false).toBool ());
+    editor_hiding_closes_files->setChecked (settings->value ("editor/hiding_closes_files", false).toBool ());
+    editor_show_dbg_file->setChecked (settings->value (ed_show_dbg_file.key, ed_show_dbg_file.def).toBool ());
 
-  // terminal
-  ui->terminal_fontName->setCurrentFont (QFont (settings->value ("terminal/fontName", "Courier New").toString ()));
-  ui->terminal_fontSize->setValue (settings->value ("terminal/fontSize", 10).toInt ());
-  ui->terminal_history_buffer->setValue (settings->value ("terminal/history_buffer", 1000).toInt ());
-  ui->terminal_cursorUseForegroundColor->setChecked (settings->value ("terminal/cursorUseForegroundColor", true).toBool ());
-  ui->terminal_focus_command->setChecked (settings->value ("terminal/focus_after_command", false).toBool ());
-  ui->terminal_print_dbg_location->setChecked (settings->value ("terminal/print_debug_location", false).toBool ());
-
-  QString cursorType
-    = settings->value ("terminal/cursorType", "ibeam").toString ();
+    // terminal
+    QString default_font = settings->value (global_mono_font.key, global_mono_font.def).toString ();
+    terminal_fontName->setCurrentFont (QFont (settings->value (cs_font.key, default_font).toString ()));
+    terminal_fontSize->setValue (settings->value ("terminal/fontSize", 10).toInt ());
+    terminal_history_buffer->setValue (settings->value ("terminal/history_buffer", 1000).toInt ());
+    terminal_cursorUseForegroundColor->setChecked (settings->value ("terminal/cursorUseForegroundColor", true).toBool ());
+    terminal_focus_command->setChecked (settings->value ("terminal/focus_after_command", false).toBool ());
+    terminal_print_dbg_location->setChecked (settings->value ("terminal/print_debug_location", false).toBool ());
 
-  QStringList items;
-  items << QString ("0") << QString ("1") << QString ("2");
-  ui->terminal_cursorType->addItems (items);
-  ui->terminal_cursorType->setItemText (0, tr ("IBeam Cursor"));
-  ui->terminal_cursorType->setItemText (1, tr ("Block Cursor"));
-  ui->terminal_cursorType->setItemText (2, tr ("Underline Cursor"));
+    QString cursorType
+      = settings->value ("terminal/cursorType", "ibeam").toString ();
 
-  if (cursorType == "ibeam")
-    ui->terminal_cursorType->setCurrentIndex (0);
-  else if (cursorType == "block")
-    ui->terminal_cursorType->setCurrentIndex (1);
-  else if (cursorType == "underline")
-    ui->terminal_cursorType->setCurrentIndex (2);
+    QStringList items;
+    items << QString ("0") << QString ("1") << QString ("2");
+    terminal_cursorType->addItems (items);
+    terminal_cursorType->setItemText (0, tr ("IBeam Cursor"));
+    terminal_cursorType->setItemText (1, tr ("Block Cursor"));
+    terminal_cursorType->setItemText (2, tr ("Underline Cursor"));
 
-  // file browser
-  connect (ui->sync_octave_directory, SIGNAL (toggled (bool)),
-           this, SLOT (set_disabled_pref_file_browser_dir (bool)));
-
-  ui->sync_octave_directory->setChecked (settings->value ("filesdockwidget/sync_octave_directory", true).toBool ());
-  ui->cb_restore_file_browser_dir->setChecked (settings->value ("filesdockwidget/restore_last_dir", false).toBool ());
-  ui->le_file_browser_dir->setText (settings->value ("filesdockwidget/startup_dir").toString ());
+    if (cursorType == "ibeam")
+      terminal_cursorType->setCurrentIndex (0);
+    else if (cursorType == "block")
+      terminal_cursorType->setCurrentIndex (1);
+    else if (cursorType == "underline")
+      terminal_cursorType->setCurrentIndex (2);
 
-  connect (ui->pb_file_browser_dir, SIGNAL (pressed (void)),
-           this, SLOT (get_file_browser_dir (void)));
+    // file browser
+    connect (sync_octave_directory, SIGNAL (toggled (bool)),
+             this, SLOT (set_disabled_pref_file_browser_dir (bool)));
 
-  ui->le_file_browser_extensions->setText (settings->value ("filesdockwidget/txt_file_extensions", "m;c;cc;cpp;h;txt").toString ());
+    sync_octave_directory->setChecked (settings->value (fb_sync_octdir.key, fb_sync_octdir.def).toBool ());
+    cb_restore_file_browser_dir->setChecked (settings->value (fb_restore_last_dir.key, fb_restore_last_dir.def).toBool ());
+    le_file_browser_dir->setText (settings->value (fb_startup_dir.key).toString ());
 
-  ui->checkbox_allow_web_connect->setChecked (settings->value ("news/allow_web_connection", false).toBool ());
-  ui->useProxyServer->setChecked (settings->value ("useProxyServer", false).toBool ());
-  ui->proxyHostName->setText (settings->value ("proxyHostName").toString ());
+    connect (pb_file_browser_dir, SIGNAL (pressed (void)),
+             this, SLOT (get_file_browser_dir (void)));
+
+    le_file_browser_extensions->setText (settings->value (fb_txt_file_ext.key, fb_txt_file_ext.def).toString ());
 
-  int currentIndex = 0;
-  QString proxyTypeString = settings->value ("proxyType").toString ();
-  while ((currentIndex < ui->proxyType->count ())
-         && (ui->proxyType->currentText () != proxyTypeString))
-    {
-      currentIndex++;
-      ui->proxyType->setCurrentIndex (currentIndex);
-    }
+    checkbox_allow_web_connect->setChecked (settings->value ("news/allow_web_connection", false).toBool ());
+    useProxyServer->setChecked (settings->value ("useProxyServer", false).toBool ());
+    proxyHostName->setText (settings->value ("proxyHostName").toString ());
 
-  ui->proxyPort->setText (settings->value ("proxyPort").toString ());
-  ui->proxyUserName->setText (settings->value ("proxyUserName").toString ());
-  ui->proxyPassword->setText (settings->value ("proxyPassword").toString ());
+    int currentIndex = 0;
+    QString proxyTypeString = settings->value ("proxyType").toString ();
+    while ((currentIndex < proxyType->count ())
+           && (proxyType->currentText () != proxyTypeString))
+      {
+        currentIndex++;
+        proxyType->setCurrentIndex (currentIndex);
+      }
 
-  // Workspace
-  // colors
-  read_workspace_colors (settings);
-  // hide tool tips
-  ui->cb_hide_tool_tips->setChecked (settings->value ("workspaceview/hide_tool_tips", false).toBool ());
+    proxyPort->setText (settings->value ("proxyPort").toString ());
+    proxyUserName->setText (settings->value ("proxyUserName").toString ());
+    proxyPassword->setText (settings->value ("proxyPassword").toString ());
+
+    // Workspace
+    read_workspace_colors (settings);
 
-  // terminal colors
-  read_terminal_colors (settings);
+    // terminal colors
+    read_terminal_colors (settings);
 
-  // variable editor
-  ui->varedit_columnWidth->setValue (settings->value ("variable_editor/column_width", 100).toInt ());
-  ui->varedit_autoFitColumnWidth->setChecked (settings->value ("variable_editor/autofit_column_width", false).toBool ());
-  ui->varedit_autofitType->setCurrentIndex (settings->value ("autofit_type", 0).toInt ());
-  ui->varedit_rowHeight->setValue (settings->value ("variable_editor/row_height", 10).toInt ());
-  ui->varedit_rowAutofit->setChecked (settings->value ("variable_editor/autofit_row_height", true).toBool ());
+    // variable editor
+    varedit_columnWidth->setValue (settings->value ("variable_editor/column_width", 100).toInt ());
+    varedit_autoFitColumnWidth->setChecked (settings->value ("variable_editor/autofit_column_width", false).toBool ());
+    varedit_autofitType->setCurrentIndex (settings->value ("autofit_type", 0).toInt ());
+    varedit_rowHeight->setValue (settings->value ("variable_editor/row_height", 10).toInt ());
+    varedit_rowAutofit->setChecked (settings->value ("variable_editor/autofit_row_height", true).toBool ());
 
-  ui->varedit_font->setCurrentFont (QFont (settings->value ("variable_editor/font_name", settings->value ("terminal/fontName", "Courier New")).toString ()));
-  ui->varedit_fontSize->setValue (settings->value ("variable_editor/font_size", QVariant (10)).toInt ());
-  connect (ui->varedit_useTerminalFont, SIGNAL (toggled (bool)),
-           ui->varedit_font, SLOT (setDisabled (bool)));
-  connect (ui->varedit_useTerminalFont, SIGNAL (toggled (bool)),
-           ui->varedit_fontSize, SLOT (setDisabled (bool)));
-  ui->varedit_useTerminalFont->setChecked (settings->value ("variable_editor/use_terminal_font", false).toBool ());
-  ui->varedit_font->setDisabled (ui->varedit_useTerminalFont->isChecked ());
-  ui->varedit_fontSize->setDisabled (ui->varedit_useTerminalFont->isChecked ());
+    varedit_font->setCurrentFont (QFont (settings->value ("variable_editor/font_name", settings->value (cs_font.key, default_font)).toString ()));
+    varedit_fontSize->setValue (settings->value ("variable_editor/font_size", QVariant (10)).toInt ());
+    connect (varedit_useTerminalFont, SIGNAL (toggled (bool)),
+             varedit_font, SLOT (setDisabled (bool)));
+    connect (varedit_useTerminalFont, SIGNAL (toggled (bool)),
+             varedit_fontSize, SLOT (setDisabled (bool)));
+    varedit_useTerminalFont->setChecked (settings->value ("variable_editor/use_terminal_font", false).toBool ());
+    varedit_font->setDisabled (varedit_useTerminalFont->isChecked ());
+    varedit_fontSize->setDisabled (varedit_useTerminalFont->isChecked ());
 
-  ui->varedit_alternate->setChecked (settings->value ("variable_editor/alternate_rows", QVariant (false)).toBool ());
+    varedit_alternate->setChecked (settings->value ("variable_editor/alternate_rows", QVariant (false)).toBool ());
 
-  // variable editor colors
-  read_varedit_colors (settings);
+    // variable editor colors
+    read_varedit_colors (settings);
 
-  // shortcuts
+    // shortcuts
 
-  ui->cb_prevent_readline_conflicts->setChecked (settings->value ("shortcuts/prevent_readline_conflicts", true).toBool ());
+    cb_prevent_readline_conflicts->setChecked (settings->value ("shortcuts/prevent_readline_conflicts", true).toBool ());
 
-  // initialize the tree view with all shortcut data
-  shortcut_manager::fill_treewidget (ui->shortcuts_treewidget);
+    // initialize the tree view with all shortcut data
+    shortcut_manager::fill_treewidget (shortcuts_treewidget);
 
-  // connect the buttons for import/export of the shortcut sets
-  connect (ui->btn_import_shortcut_set, SIGNAL (clicked (void)),
-           this, SLOT (import_shortcut_set (void)));
+    // 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 (ui->btn_export_shortcut_set, SIGNAL (clicked (void)),
-           this, SLOT (export_shortcut_set (void)));
+    connect (btn_export_shortcut_set, SIGNAL (clicked (void)),
+             this, SLOT (export_shortcut_set (void)));
 
-  connect (ui->btn_default_shortcut_set, SIGNAL (clicked (void)),
-           this, SLOT (default_shortcut_set (void)));
+    connect (btn_default_shortcut_set, SIGNAL (clicked (void)),
+             this, SLOT (default_shortcut_set (void)));
 
 #if defined (HAVE_QSCINTILLA)
 
-  // editor styles: create lexer, read settings, and create dialog elements
-  QsciLexer *lexer;
+    // editor styles: create lexer, read settings, and create dialog elements
+    QsciLexer *lexer;
 
 #if defined (HAVE_LEXER_OCTAVE)
 
-  lexer = new QsciLexerOctave ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerOctave ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
 #elif defined (HAVE_LEXER_MATLAB)
 
-  lexer = new QsciLexerMatlab ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerMatlab ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
 #endif
 
-  lexer = new QsciLexerCPP ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerCPP ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerPerl ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerPerl ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerBatch ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerBatch ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerDiff ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerDiff ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerBash ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerBash ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new octave::octave_txt_lexer ();
-  read_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new octave::octave_txt_lexer ();
+    read_lexer_settings (lexer, settings);
+    delete lexer;
 
 #endif
 
-  // which tab is the desired one?
-  show_tab (desired_tab);
+    // which tab is the desired one?
+    show_tab (desired_tab);
+
+    // connect button box signal
+    connect (button_box, SIGNAL (clicked (QAbstractButton *)),
+             this, SLOT (button_clicked (QAbstractButton *)));
 
-  // connect button box signal
-  connect (ui->button_box, SIGNAL (clicked (QAbstractButton *)),
-           this, SLOT (button_clicked (QAbstractButton *)));
+    // restore last geometry
+    if (settings->contains ("settings/geometry"))
+      restoreGeometry (settings->value ("settings/geometry").toByteArray ());
+    else
+      setGeometry (QRect (10,50,1000,600));
+  }
 
-  // restore last geometry
-  if (settings->contains ("settings/geometry"))
-    restoreGeometry (settings->value ("settings/geometry").toByteArray ());
-  else
-    setGeometry (QRect (10,50,1000,600));
-}
+  void settings_dialog::show_tab (const QString& tab)
+  {
+    if (tab.isEmpty ())
+      {
+        QSettings *settings = resource_manager::get_settings ();
+        if (settings)
+          tabWidget->setCurrentIndex (settings->value ("settings/last_tab", 0).toInt ());
+      }
+    else
+      {
+        QHash <QString, QWidget*> tab_hash;
+        tab_hash["editor"] = tab_editor;
+        tab_hash["editor_styles"] = tab_editor;
+        tabWidget->setCurrentIndex (tabWidget->indexOf (tab_hash.value (tab)));
+        if (tab == "editor_styles")
+          tab_editor_scroll_area->ensureWidgetVisible (group_box_editor_styles);
+      }
+  }
 
-settings_dialog::~settings_dialog (void)
-{
-  delete ui;
-}
+  void settings_dialog::get_octave_dir (void)
+  {
+    get_dir (le_octave_dir, tr ("Set Octave Startup Directory"));
+  }
+
+  void settings_dialog::get_file_browser_dir (void)
+  {
+    get_dir (le_file_browser_dir, tr ("Set File Browser Startup Directory"));
+  }
+
+  void settings_dialog::get_dir (QLineEdit *line_edit, const QString& title)
+  {
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks;
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts |= QFileDialog::DontUseNativeDialog;
+
+    QString dir = QFileDialog::getExistingDirectory
+      (this, title, line_edit->text (), QFileDialog::Option (opts));
 
-void
-settings_dialog::show_tab (const QString& tab)
-{
-  if (tab.isEmpty ())
-    {
-      QSettings *settings = resource_manager::get_settings ();
-      if (settings)
-        ui->tabWidget->setCurrentIndex (settings->value ("settings/last_tab", 0).toInt ());
-    }
-  else
-    {
-      QHash <QString, QWidget*> tab_hash;
-      tab_hash["editor"] = ui->tab_editor;
-      tab_hash["editor_styles"] = ui->tab_editor_styles;
-      ui->tabWidget->setCurrentIndex (ui->tabWidget->indexOf (tab_hash.value (tab)));
-    }
-}
+    line_edit->setText (dir);
+  }
+
+  void settings_dialog::button_clicked (QAbstractButton *button)
+  {
+    QDialogButtonBox::ButtonRole button_role = button_box->buttonRole (button);
+
+    if (button_role == QDialogButtonBox::ApplyRole
+        || button_role == QDialogButtonBox::AcceptRole)
+      {
+        write_changed_settings (button_role == QDialogButtonBox::AcceptRole);
+        emit apply_new_settings ();
+      }
+
+    if (button_role == QDialogButtonBox::RejectRole
+        || button_role == QDialogButtonBox::AcceptRole)
+      close ();
+  }
+
+  void settings_dialog::set_disabled_pref_file_browser_dir (bool disable)
+  {
+    cb_restore_file_browser_dir->setDisabled (disable);
 
-void
-settings_dialog::get_octave_dir (void)
-{
-  get_dir (ui->le_octave_dir, tr ("Set Octave Startup Directory"));
-}
+    if (! disable)
+      {
+        le_file_browser_dir->setDisabled (cb_restore_file_browser_dir->isChecked ());
+        pb_file_browser_dir->setDisabled (cb_restore_file_browser_dir->isChecked ());
+      }
+    else
+      {
+        le_file_browser_dir->setDisabled (disable);
+        pb_file_browser_dir->setDisabled (disable);
+      }
+  }
+
+  // slots for import/export of shortcut sets
 
-void
-settings_dialog::get_file_browser_dir (void)
-{
-  get_dir (ui->le_file_browser_dir, tr ("Set File Browser Startup Directory"));
-}
+  void settings_dialog::import_shortcut_set (void)
+  {
+    shortcut_manager::import_export (shortcut_manager::OSC_IMPORT);
+  }
+
+  void settings_dialog::export_shortcut_set (void)
+  {
+    shortcut_manager::import_export (shortcut_manager::OSC_EXPORT);
+  }
 
-void
-settings_dialog::get_dir (QLineEdit *line_edit, const QString& title)
-{
-  QString dir = QFileDialog::getExistingDirectory
-    (this, title, line_edit->text (), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+  void settings_dialog::default_shortcut_set (void)
+  {
+    shortcut_manager::import_export (shortcut_manager::OSC_DEFAULT);
+  }
 
-  line_edit->setText (dir);
-}
+  void settings_dialog::read_lexer_settings (QsciLexer *lexer,
+                                             QSettings *settings)
+  {
+#if defined (HAVE_QSCINTILLA)
 
-void
-settings_dialog::button_clicked (QAbstractButton *button)
-{
-  QDialogButtonBox::ButtonRole button_role = ui->button_box->buttonRole (button);
-
-  if (button_role == QDialogButtonBox::ApplyRole
-      || button_role == QDialogButtonBox::AcceptRole)
-    {
-      write_changed_settings (button_role == QDialogButtonBox::AcceptRole);
-      emit apply_new_settings ();
-    }
-
-  if (button_role == QDialogButtonBox::RejectRole
-      || button_role == QDialogButtonBox::AcceptRole)
-    close ();
-}
-
-void
-settings_dialog::set_disabled_pref_file_browser_dir (bool disable)
-{
-  ui->cb_restore_file_browser_dir->setDisabled (disable);
+    lexer->readSettings (*settings);
+    int styles[MaxLexerStyles];  // array for saving valid styles
+    // (enum is not continuous)
+    int max_style = get_valid_lexer_styles (lexer, styles);
+    QGridLayout *style_grid = new QGridLayout ();
+    QVector<QLabel*> description (max_style);
+    QVector<QFontComboBox*> select_font (max_style);
+    QVector<QSpinBox*> font_size (max_style);
+    QVector<QCheckBox*> attrib_font (3 * max_style);
+    QVector<color_picker*> color (max_style);
+    QVector<color_picker*> bg_color (max_style);
+    int default_size = 10;
+    QFont default_font = QFont ();
+    int label_width;
+    QColor default_color = QColor ();
+    QColor dummy_color = QColor (255, 0, 255);
 
-  if (! disable)
-    {
-      ui->le_file_browser_dir->setDisabled (ui->cb_restore_file_browser_dir->isChecked ());
-      ui->pb_file_browser_dir->setDisabled (ui->cb_restore_file_browser_dir->isChecked ());
-    }
-  else
-    {
-      ui->le_file_browser_dir->setDisabled (disable);
-      ui->pb_file_browser_dir->setDisabled (disable);
-    }
-}
-
-// slots for import/export of shortcut sets
-void
-settings_dialog::import_shortcut_set (void)
-{
-  shortcut_manager::import_export (shortcut_manager::OSC_IMPORT);
-}
+    for (int i = 0; i < max_style; i++)  // create dialog elements for all styles
+      {
+        QString actual_name = lexer->description (styles[i]);
+        QFont   actual_font = lexer->font (styles[i]);
+        description[i] = new QLabel (actual_name);
+        description[i]->setWordWrap (true);
+        label_width = 24*description[i]->fontMetrics ().averageCharWidth ();
+        description[i]->setMaximumSize (label_width, QWIDGETSIZE_MAX);
+        description[i]->setMinimumSize (label_width, 1);
+        select_font[i] = new QFontComboBox ();
+        select_font[i]->setObjectName (actual_name + "_font");
+        select_font[i]->setMaximumSize (label_width, QWIDGETSIZE_MAX);
+        select_font[i]->setMinimumSize (label_width, 1);
+        font_size[i] = new QSpinBox ();
+        font_size[i]->setObjectName (actual_name + "_size");
+        if (styles[i] == 0) // the default
+          {
+            select_font[i]->setCurrentFont (actual_font);
+            default_font = actual_font;
+            font_size[i]->setRange (6, 24);
+            default_size = actual_font.pointSize ();
+            font_size[i]->setValue (default_size);
+            default_color = lexer->defaultPaper ();
+            bg_color[i] = new color_picker (default_color);
+          }
+        else   // other styles
+          {
+            select_font[i]->setCurrentFont (actual_font);
+            if (actual_font.family () == default_font.family ())
+              select_font[i]->setEditText (lexer->description (0));
+            font_size[i]->setRange (-4, 4);
+            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);
+            else
+              bg_color[i] = new color_picker (lexer->paper (styles[i]));
+            bg_color[i]->setToolTip
+              (QObject::tr ("Background color, pink (255, 0, 255) means default"));
+          }
+        attrib_font[0+3*i] = new QCheckBox (QObject::tr ("b", "short form for bold"));
+        attrib_font[1+3*i] = new QCheckBox (QObject::tr ("i", "short form for italic"));
+        attrib_font[2+3*i] = new QCheckBox (QObject::tr ("u", "short form for underlined"));
+        attrib_font[0+3*i]->setChecked (actual_font.bold ());
+        attrib_font[0+3*i]->setObjectName (actual_name + "_bold");
+        attrib_font[1+3*i]->setChecked (actual_font.italic ());
+        attrib_font[1+3*i]->setObjectName (actual_name + "_italic");
+        attrib_font[2+3*i]->setChecked (actual_font.underline ());
+        attrib_font[2+3*i]->setObjectName (actual_name + "_underline");
+        color[i] = new color_picker (lexer->color (styles[i]));
+        color[i]->setObjectName (actual_name + "_color");
+        bg_color[i]->setObjectName (actual_name + "_bg_color");
+        int column = 1;
+        style_grid->addWidget (description[i], i, column++);
+        style_grid->addWidget (select_font[i], i, column++);
+        style_grid->addWidget (font_size[i], i, column++);
+        style_grid->addWidget (attrib_font[0+3*i], i, column++);
+        style_grid->addWidget (attrib_font[1+3*i], i, column++);
+        style_grid->addWidget (attrib_font[2+3*i], i, column++);
+        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 ();
+    scroll_area_contents->setObjectName (QString (lexer->language ()) + "_styles");
+    scroll_area_contents->setLayout (style_grid);
+    scroll_area->setWidget (scroll_area_contents);
+    tabs_editor_lexers->addTab (scroll_area, lexer->language ());
 
-void
-settings_dialog::export_shortcut_set (void)
-{
-  shortcut_manager::import_export (shortcut_manager::OSC_EXPORT);
-}
+    tabs_editor_lexers->setCurrentIndex (settings->value ("settings/last_editor_styles_tab", 0).toInt ());
+
+#else
 
-void
-settings_dialog::default_shortcut_set (void)
-{
-  shortcut_manager::import_export (shortcut_manager::OSC_DEFAULT);
-}
+    octave_unused_parameter (lexer);
+    octave_unused_parameter (settings);
+
+#endif
+  }
 
-void
-settings_dialog::write_changed_settings (bool closing)
-{
-  QSettings *settings = resource_manager::get_settings ();
+  void settings_dialog::write_lexer_settings (QsciLexer *lexer,
+                                              QSettings *settings)
+  {
+#if defined (HAVE_QSCINTILLA)
 
-  // the icon set
-  QString widget_icon_set = "NONE";
-  if (ui->general_icon_letter->isChecked ())
-    widget_icon_set = "LETTER";
-  else if (ui->general_icon_graphic->isChecked ())
-    widget_icon_set = "GRAPHIC";
-  settings->setValue ("DockWidgets/widget_icon_set", widget_icon_set);
+    QWidget *tab = tabs_editor_lexers->
+      findChild <QWidget *> (QString (lexer->language ()) + "_styles");
+    int styles[MaxLexerStyles];  // array for saving valid styles
+    // (enum is not continuous)
+    int max_style = get_valid_lexer_styles (lexer, styles);
+    QFontComboBox *select_font;
+    QSpinBox *font_size;
+    QCheckBox *attrib_font[3];
+    color_picker *color;
+    color_picker *bg_color;
+    int default_size = 10;
 
-  // language
-  QString language = ui->comboBox_language->currentText ();
-  if (language == tr ("System setting"))
-    language = "SYSTEM";
-  settings->setValue ("language", language);
-
-  // dock widget title bar
-  settings->setValue ("DockWidgets/widget_title_custom_style", ui->cb_widget_custom_style->isChecked ());
-  settings->setValue ("DockWidgets/widget_title_3d", ui->sb_3d_title->value ());
-  settings->setValue ("DockWidgets/title_bg_color", m_widget_title_bg_color->color ());
-  settings->setValue ("DockWidgets/title_bg_color_active", m_widget_title_bg_color_active->color ());
-  settings->setValue ("DockWidgets/title_fg_color", m_widget_title_fg_color->color ());
-  settings->setValue ("DockWidgets/title_fg_color_active", m_widget_title_fg_color_active->color ());
+    QString default_font_name
+      = settings->value (global_mono_font.key, global_mono_font.def).toString ();
+    QFont default_font = QFont (default_font_name, 10, -1, 0);
+    QColor default_color = QColor ();
+    QColor dummy_color = QColor (255, 0, 255);
 
-  // icon size
-  int icon_size = 0;
-  if (ui->icon_size_small->isChecked ())
-    icon_size = -1;
-  else if (ui->icon_size_large->isChecked ())
-    icon_size = 1;
-  settings->setValue ("toolbar_icon_size", icon_size);
+    for (int i = 0; i < max_style; i++)  // get dialog elements and their contents
+      {
+        QString actual_name = lexer->description (styles[i]);
+        select_font = tab->findChild <QFontComboBox *> (actual_name + "_font");
+        font_size = tab->findChild <QSpinBox *> (actual_name + "_size");
+        attrib_font[0] = tab->findChild <QCheckBox *> (actual_name + "_bold");
+        attrib_font[1] = tab->findChild <QCheckBox *> (actual_name + "_italic");
+        attrib_font[2] = tab->findChild <QCheckBox *> (actual_name + "_underline");
+        color = tab->findChild <color_picker *> (actual_name + "_color");
+        bg_color = tab->findChild <color_picker *> (actual_name + "_bg_color");
+        QFont new_font = default_font;
+        if (select_font)
+          {
+            new_font = select_font->currentFont ();
+            if (styles[i] == 0)
+              default_font = new_font;
+            else if (select_font->currentText () == lexer->description (0))
+              new_font = default_font;
+          }
+        if (font_size)
+          {
+            if (styles[i] == 0)
+              {
+                default_size = font_size->value ();
+                new_font.setPointSize (font_size->value ());
+              }
+            else
+              new_font.setPointSize (font_size->value ()+default_size);
+          }
+        if (attrib_font[0])
+          new_font.setBold (attrib_font[0]->isChecked ());
+        if (attrib_font[1])
+          new_font.setItalic (attrib_font[1]->isChecked ());
+        if (attrib_font[2])
+          new_font.setUnderline (attrib_font[2]->isChecked ());
+        lexer->setFont (new_font, styles[i]);
+        if (styles[i] == 0)
+          lexer->setDefaultFont (new_font);
+        if (color)
+          lexer->setColor (color->color (), styles[i]);
+        if (bg_color)
+          {
+            if (styles[i] == 0)
+              {
+                default_color = bg_color->color ();
+                lexer->setPaper (default_color, styles[i]);
+                lexer->setDefaultPaper (default_color);
+              }
+            else
+              {
+                if (bg_color->color () == dummy_color)
+                  lexer->setPaper (default_color, styles[i]);
+                else
+                  lexer->setPaper (bg_color->color (), styles[i]);
+              }
+          }
+      }
 
-  // cursor blinking
-  settings->setValue ("cursor_blinking", ui->cb_cursor_blinking->isChecked ());
+    lexer->writeSettings (*settings);
+
+    settings->setValue ("settings/last_editor_styles_tab",
+                        tabs_editor_lexers->currentIndex ());
+    settings->sync ();
+
+#else
 
-  // promp to exit
-  settings->setValue ("prompt_to_exit", ui->cb_prompt_to_exit->isChecked ());
+    octave_unused_parameter (lexer);
+    octave_unused_parameter (settings);
+
+#endif
+  }
+
+  void settings_dialog::write_changed_settings (bool closing)
+  {
+    QSettings *settings = resource_manager::get_settings ();
 
-  // status bar
-  settings->setValue ("show_status_bar", ui->cb_status_bar->isChecked ());
+    // the icon set
+    QString widget_icon_set = "NONE";
+    if (general_icon_letter->isChecked ())
+      widget_icon_set = "LETTER";
+    else if (general_icon_graphic->isChecked ())
+      widget_icon_set = "GRAPHIC";
+    settings->setValue ("DockWidgets/widget_icon_set", widget_icon_set);
+
+    // language
+    QString language = comboBox_language->currentText ();
+    if (language == tr ("System setting"))
+      language = "SYSTEM";
+    settings->setValue ("language", language);
 
-  // Octave startup
-  settings->setValue ("restore_octave_dir", ui->cb_restore_octave_dir->isChecked ());
-  settings->setValue ("octave_startup_dir", ui->le_octave_dir->text ());
+    // style
+    QString selected_style = combo_styles->currentText ();
+    if (selected_style == global_style.def.toString ())
+      selected_style = global_style.def.toString ();
+    settings->setValue (global_style.key, selected_style);
+
+    // dock widget title bar
+    settings->setValue ("DockWidgets/widget_title_custom_style", cb_widget_custom_style->isChecked ());
+    settings->setValue ("DockWidgets/widget_title_3d", sb_3d_title->value ());
+    settings->setValue ("DockWidgets/title_bg_color", m_widget_title_bg_color->color ());
+    settings->setValue ("DockWidgets/title_bg_color_active", m_widget_title_bg_color_active->color ());
+    settings->setValue ("DockWidgets/title_fg_color", m_widget_title_fg_color->color ());
+    settings->setValue ("DockWidgets/title_fg_color_active", m_widget_title_fg_color_active->color ());
 
-  //editor
-  settings->setValue ("useCustomFileEditor", ui->useCustomFileEditor->isChecked ());
-  settings->setValue ("customFileEditor", ui->customFileEditor->text ());
-  settings->setValue ("editor/showLineNumbers", ui->editor_showLineNumbers->isChecked ());
-  settings->setValue ("editor/line_numbers_size", ui->editor_linenr_size->value ());
-  settings->setValue ("editor/highlightCurrentLine", ui->editor_highlightCurrentLine->isChecked ());
-  settings->setValue ("editor/highlight_current_line_color", m_editor_current_line_color->color ());
-  settings->setValue ("editor/long_line_marker", ui->editor_long_line_marker->isChecked ());
-  settings->setValue ("editor/long_line_marker_line", ui->editor_long_line_marker_line->isChecked ());
-  settings->setValue ("editor/long_line_marker_background", ui->editor_long_line_marker_background->isChecked ());
-  settings->setValue ("editor/long_line_column", ui->editor_long_line_column->value ());
-  settings->setValue ("editor/break_lines", ui->editor_break_checkbox->isChecked ());
-  settings->setValue ("editor/break_lines_comments", ui->editor_break_comments_checkbox->isChecked ());
-  settings->setValue ("editor/wrap_lines", ui->editor_wrap_checkbox->isChecked ());
-  settings->setValue ("editor/code_folding", ui->cb_code_folding->isChecked ());
-  settings->setValue ("editor/show_edit_status_bar", ui->cb_edit_status_bar->isChecked ());
-  settings->setValue ("editor/show_toolbar", ui->cb_edit_tool_bar->isChecked ());
-  settings->setValue ("editor/highlight_all_occurrences", ui->editor_highlight_all_occurrences->isChecked ());
-  settings->setValue ("editor/codeCompletion", ui->editor_codeCompletion->isChecked ());
-  settings->setValue ("editor/codeCompletion_threshold", ui->editor_spinbox_ac_threshold->value ());
-  settings->setValue ("editor/codeCompletion_keywords", ui->editor_checkbox_ac_keywords->isChecked ());
-  settings->setValue ("editor/codeCompletion_octave_builtins", ui->editor_checkbox_ac_builtins->isChecked ());
-  settings->setValue ("editor/codeCompletion_octave_functions", ui->editor_checkbox_ac_functions->isChecked ());
-  settings->setValue ("editor/codeCompletion_document", ui->editor_checkbox_ac_document->isChecked ());
-  settings->setValue ("editor/codeCompletion_case", ui->editor_checkbox_ac_case->isChecked ());
-  settings->setValue ("editor/codeCompletion_replace", ui->editor_checkbox_ac_replace->isChecked ());
-  settings->setValue ("editor/auto_endif", ui->editor_auto_endif->currentIndex ());
-  settings->setValue ("editor/show_white_space", ui->editor_ws_checkbox->isChecked ());
-  settings->setValue ("editor/show_white_space_indent", ui->editor_ws_indent_checkbox->isChecked ());
-  settings->setValue ("editor/show_eol_chars", ui->cb_show_eol->isChecked ());
-  settings->setValue ("editor/show_hscroll_bar", ui->cb_show_hscrollbar->isChecked ());
-  settings->setValue ("editor/default_eol_mode", ui->combo_eol_mode->currentIndex ());
+    // icon size and theme
+    int icon_size = icon_size_large->isChecked () - icon_size_small->isChecked ();
+    settings->setValue (global_icon_size.key, icon_size);
+    settings->setValue (global_icon_theme.key, cb_system_icon_theme->isChecked ());
+
+    // native file dialogs
+    settings->setValue ("use_native_file_dialogs", cb_use_native_file_dialogs->isChecked ());
+
+    // cursor blinking
+    settings->setValue ("cursor_blinking", cb_cursor_blinking->isChecked ());
+
+    // promp to exit
+    settings->setValue ("prompt_to_exit", cb_prompt_to_exit->isChecked ());
+
+    // status bar
+    settings->setValue ("show_status_bar", cb_status_bar->isChecked ());
+
+    // Octave startup
+    settings->setValue ("restore_octave_dir", cb_restore_octave_dir->isChecked ());
+    settings->setValue ("octave_startup_dir", le_octave_dir->text ());
+
+    //editor
+    settings->setValue ("useCustomFileEditor", useCustomFileEditor->isChecked ());
+    settings->setValue ("customFileEditor", customFileEditor->text ());
+    settings->setValue ("editor/showLineNumbers", editor_showLineNumbers->isChecked ());
+    settings->setValue ("editor/line_numbers_size", editor_linenr_size->value ());
+    settings->setValue ("editor/highlightCurrentLine", editor_highlightCurrentLine->isChecked ());
+    settings->setValue ("editor/highlight_current_line_color", m_editor_current_line_color->color ());
+    settings->setValue ("editor/long_line_marker", editor_long_line_marker->isChecked ());
+    settings->setValue ("editor/long_line_marker_line", editor_long_line_marker_line->isChecked ());
+    settings->setValue ("editor/long_line_marker_background", editor_long_line_marker_background->isChecked ());
+    settings->setValue ("editor/long_line_column", editor_long_line_column->value ());
+    settings->setValue ("editor/break_lines", editor_break_checkbox->isChecked ());
+    settings->setValue ("editor/break_lines_comments", editor_break_comments_checkbox->isChecked ());
+    settings->setValue ("editor/wrap_lines", editor_wrap_checkbox->isChecked ());
+    settings->setValue ("editor/code_folding", cb_code_folding->isChecked ());
+    settings->setValue ("editor/show_edit_status_bar", cb_edit_status_bar->isChecked ());
+    settings->setValue ("editor/show_toolbar", cb_edit_tool_bar->isChecked ());
+    settings->setValue ("editor/highlight_all_occurrences", editor_highlight_all_occurrences->isChecked ());
+    settings->setValue ("editor/codeCompletion", editor_codeCompletion->isChecked ());
+    settings->setValue ("editor/codeCompletion_threshold", editor_spinbox_ac_threshold->value ());
+    settings->setValue ("editor/codeCompletion_keywords", editor_checkbox_ac_keywords->isChecked ());
+    settings->setValue ("editor/codeCompletion_octave_builtins", editor_checkbox_ac_builtins->isChecked ());
+    settings->setValue ("editor/codeCompletion_octave_functions", editor_checkbox_ac_functions->isChecked ());
+    settings->setValue ("editor/codeCompletion_document", editor_checkbox_ac_document->isChecked ());
+    settings->setValue ("editor/codeCompletion_case", editor_checkbox_ac_case->isChecked ());
+    settings->setValue ("editor/codeCompletion_replace", editor_checkbox_ac_replace->isChecked ());
+    settings->setValue ("editor/auto_endif", editor_auto_endif->currentIndex ());
+    settings->setValue ("editor/show_white_space", editor_ws_checkbox->isChecked ());
+    settings->setValue ("editor/show_white_space_indent", editor_ws_indent_checkbox->isChecked ());
+    settings->setValue ("editor/show_eol_chars", cb_show_eol->isChecked ());
+    settings->setValue ("editor/show_hscroll_bar", cb_show_hscrollbar->isChecked ());
+    settings->setValue ("editor/default_eol_mode", combo_eol_mode->currentIndex ());
 
-  // Comment strings
-  int rb_uncomment = 0;
-  for (int i = 0; i < oct_comment_strings_count; i++)
-    {
-      if (m_rb_comment_strings[i]->isChecked ())
-        {
-          settings->setValue (oct_comment_str, i);
-          if (i < 3)
-            settings->setValue (oct_comment_str_old, i);
-          else
-            settings->setValue (oct_comment_str_old, oct_comment_str_d);
-        }
-      if (m_rb_uncomment_strings[i]->isChecked ())
-        rb_uncomment = rb_uncomment + (1 << i);
-    }
-  settings->setValue (oct_uncomment_str, rb_uncomment);
+    // Comment strings
+    int rb_uncomment = 0;
+    for (int i = 0; i < ed_comment_strings_count; i++)
+      {
+        if (m_rb_comment_strings[i]->isChecked ())
+          {
+            settings->setValue (ed_comment_str.key, i);
+            if (i < 3)
+              settings->setValue (ed_comment_str_old.key, i);
+            else
+              settings->setValue (ed_comment_str_old.key, ed_comment_str.def);
+          }
+        if (m_rb_uncomment_strings[i]->isChecked ())
+          rb_uncomment = rb_uncomment + (1 << i);
+      }
+    settings->setValue (ed_uncomment_str.key, rb_uncomment);
 
-  settings->setValue ("editor/default_encoding", ui->editor_combo_encoding->currentText ());
-  settings->setValue ("editor/auto_indent", ui->editor_auto_ind_checkbox->isChecked ());
-  settings->setValue ("editor/tab_indents_line", ui->editor_tab_ind_checkbox->isChecked ());
-  settings->setValue ("editor/backspace_unindents_line", ui->editor_bs_unind_checkbox->isChecked ());
-  settings->setValue ("editor/show_indent_guides", ui->editor_ind_guides_checkbox->isChecked ());
-  settings->setValue ("editor/indent_width", ui->editor_ind_width_spinbox->value ());
-  settings->setValue ("editor/indent_uses_tabs", ui->editor_ind_uses_tabs_checkbox->isChecked ());
-  settings->setValue ("editor/tab_width", ui->editor_tab_width_spinbox->value ());
-  settings->setValue ("editor/longWindowTitle", ui->editor_longWindowTitle->isChecked ());
-  settings->setValue ("editor/notebook_tab_width_min", ui->editor_notebook_tab_width_min->value ());
-  settings->setValue ("editor/notebook_tab_width_max", ui->editor_notebook_tab_width_max->value ());
-  settings->setValue ("editor/restoreSession", ui->editor_restoreSession->isChecked ());
-  settings->setValue ("editor/create_new_file", ui->editor_create_new_file->isChecked ());
-  settings->setValue ("editor/hiding_closes_files", ui->editor_hiding_closes_files->isChecked ());
-  settings->setValue ("editor/always_reload_changed_files", ui->editor_reload_changed_files->isChecked ());
-  settings->setValue ("terminal/fontSize", ui->terminal_fontSize->value ());
-  settings->setValue ("terminal/fontName", ui->terminal_fontName->currentFont ().family ());
+    settings->setValue ("editor/default_encoding", editor_combo_encoding->currentText ());
+    settings->setValue ("editor/auto_indent", editor_auto_ind_checkbox->isChecked ());
+    settings->setValue ("editor/tab_indents_line", editor_tab_ind_checkbox->isChecked ());
+    settings->setValue ("editor/backspace_unindents_line", editor_bs_unind_checkbox->isChecked ());
+    settings->setValue ("editor/show_indent_guides", editor_ind_guides_checkbox->isChecked ());
+    settings->setValue ("editor/indent_width", editor_ind_width_spinbox->value ());
+    settings->setValue ("editor/indent_uses_tabs", editor_ind_uses_tabs_checkbox->isChecked ());
+    settings->setValue ("editor/tab_width", editor_tab_width_spinbox->value ());
+    settings->setValue ("editor/longWindowTitle", editor_longWindowTitle->isChecked ());
+    settings->setValue ("editor/notebook_tab_width_min", editor_notebook_tab_width_min->value ());
+    settings->setValue ("editor/notebook_tab_width_max", editor_notebook_tab_width_max->value ());
+    settings->setValue ("editor/restoreSession", editor_restoreSession->isChecked ());
+    settings->setValue ("editor/create_new_file", editor_create_new_file->isChecked ());
+    settings->setValue ("editor/hiding_closes_files", editor_hiding_closes_files->isChecked ());
+    settings->setValue ("editor/always_reload_changed_files", editor_reload_changed_files->isChecked ());
+    settings->setValue (ed_show_dbg_file.key, editor_show_dbg_file->isChecked ());
+
+    settings->setValue ("terminal/fontSize", terminal_fontSize->value ());
+    settings->setValue ("terminal/fontName", terminal_fontName->currentFont ().family ());
 
-  // file browser
-  settings->setValue ("filesdockwidget/sync_octave_directory", ui->sync_octave_directory->isChecked ());
-  settings->setValue ("filesdockwidget/restore_last_dir", ui->cb_restore_file_browser_dir->isChecked ());
-  settings->setValue ("filesdockwidget/startup_dir", ui->le_file_browser_dir->text ());
-  settings->setValue ("filesdockwidget/txt_file_extensions", ui->le_file_browser_extensions->text ());
+    // 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 ());
 
-  settings->setValue ("news/allow_web_connection", ui->checkbox_allow_web_connect->isChecked ());
-  settings->setValue ("useProxyServer", ui->useProxyServer->isChecked ());
-  settings->setValue ("proxyType", ui->proxyType->currentText ());
-  settings->setValue ("proxyHostName", ui->proxyHostName->text ());
-  settings->setValue ("proxyPort", ui->proxyPort->text ());
-  settings->setValue ("proxyUserName", ui->proxyUserName->text ());
-  settings->setValue ("proxyPassword", ui->proxyPassword->text ());
-  settings->setValue ("terminal/cursorUseForegroundColor", ui->terminal_cursorUseForegroundColor->isChecked ());
-  settings->setValue ("terminal/focus_after_command", ui->terminal_focus_command->isChecked ());
-  settings->setValue ("terminal/print_debug_location", ui->terminal_print_dbg_location->isChecked ());
-  settings->setValue ("terminal/history_buffer", ui->terminal_history_buffer->value ());
+    settings->setValue ("news/allow_web_connection", checkbox_allow_web_connect->isChecked ());
+    settings->setValue ("useProxyServer", useProxyServer->isChecked ());
+    settings->setValue ("proxyType", proxyType->currentText ());
+    settings->setValue ("proxyHostName", proxyHostName->text ());
+    settings->setValue ("proxyPort", proxyPort->text ());
+    settings->setValue ("proxyUserName", proxyUserName->text ());
+    settings->setValue ("proxyPassword", proxyPassword->text ());
+    settings->setValue ("terminal/cursorUseForegroundColor", terminal_cursorUseForegroundColor->isChecked ());
+    settings->setValue ("terminal/focus_after_command", terminal_focus_command->isChecked ());
+    settings->setValue ("terminal/print_debug_location", terminal_print_dbg_location->isChecked ());
+    settings->setValue ("terminal/history_buffer", terminal_history_buffer->value ());
 
-  // the cursor
-  QString cursorType;
-  switch (ui->terminal_cursorType->currentIndex ())
-    {
-    case 0: cursorType = "ibeam"; break;
-    case 1: cursorType = "block"; break;
-    case 2: cursorType = "underline";  break;
-    }
-  settings->setValue ("terminal/cursorType", cursorType);
+    // the cursor
+    QString cursorType;
+    switch (terminal_cursorType->currentIndex ())
+      {
+      case 0: cursorType = "ibeam"; break;
+      case 1: cursorType = "block"; break;
+      case 2: cursorType = "underline";  break;
+      }
+    settings->setValue ("terminal/cursorType", cursorType);
 
 #if defined (HAVE_QSCINTILLA)
-  // editor styles: create lexer, get dialog contents, and write settings
-  QsciLexer *lexer;
+    // editor styles: create lexer, get dialog contents, and write settings
+    QsciLexer *lexer;
 
 #if defined (HAVE_LEXER_OCTAVE)
 
-  lexer = new QsciLexerOctave ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerOctave ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
 #elif defined (HAVE_LEXER_MATLAB)
 
-  lexer = new QsciLexerMatlab ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerMatlab ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
 #endif
 
-  lexer = new QsciLexerCPP ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerCPP ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerPerl ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerPerl ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerBatch ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerBatch ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerDiff ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerDiff ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new QsciLexerBash ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new QsciLexerBash ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
-  lexer = new octave::octave_txt_lexer ();
-  write_lexer_settings (ui, lexer, settings);
-  delete lexer;
+    lexer = new octave::octave_txt_lexer ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
 
 #endif
 
-  // Workspace
-  write_workspace_colors (settings);
-  // hide tool tips
-  settings->setValue ("workspaceview/hide_tool_tips", ui->cb_hide_tool_tips->isChecked ());
+    // Workspace
+    write_workspace_colors (settings);
 
-  // Terminal
-  write_terminal_colors (settings);
+    // Terminal
+    write_terminal_colors (settings);
 
-  // Variable editor
-  settings->setValue ("variable_editor/autofit_column_width", ui->varedit_autoFitColumnWidth->isChecked ());
-  settings->setValue ("variable_editor/autofit_type", ui->varedit_autofitType->currentIndex ());
-  settings->setValue ("variable_editor/column_width", ui->varedit_columnWidth->value ());
-  settings->setValue ("variable_editor/row_height", ui->varedit_rowHeight->value ());
-  settings->setValue ("variable_editor/autofit_row_height", ui->varedit_rowAutofit->isChecked ());
-  settings->setValue ("variable_editor/use_terminal_font", ui->varedit_useTerminalFont->isChecked ());
-  settings->setValue ("variable_editor/alternate_rows", ui->varedit_alternate->isChecked ());
-  settings->setValue ("variable_editor/font_name", ui->varedit_font->currentFont ().family ());
-  settings->setValue ("variable_editor/font_size", ui->varedit_fontSize->value ());
-  write_varedit_colors (settings);
+    // Variable editor
+    settings->setValue ("variable_editor/autofit_column_width", varedit_autoFitColumnWidth->isChecked ());
+    settings->setValue ("variable_editor/autofit_type", varedit_autofitType->currentIndex ());
+    settings->setValue ("variable_editor/column_width", varedit_columnWidth->value ());
+    settings->setValue ("variable_editor/row_height", varedit_rowHeight->value ());
+    settings->setValue ("variable_editor/autofit_row_height", varedit_rowAutofit->isChecked ());
+    settings->setValue ("variable_editor/use_terminal_font", varedit_useTerminalFont->isChecked ());
+    settings->setValue ("variable_editor/alternate_rows", varedit_alternate->isChecked ());
+    settings->setValue ("variable_editor/font_name", varedit_font->currentFont ().family ());
+    settings->setValue ("variable_editor/font_size", varedit_fontSize->value ());
+    write_varedit_colors (settings);
+
+    // shortcuts
+    settings->setValue ("shortcuts/prevent_readline_conflicts", cb_prevent_readline_conflicts->isChecked ());
+    shortcut_manager::write_shortcuts (settings, closing);
 
-  // shortcuts
-  settings->setValue ("shortcuts/prevent_readline_conflicts", ui->cb_prevent_readline_conflicts->isChecked ());
-  shortcut_manager::write_shortcuts (settings, closing);
+    // settings dialog's geometry
+    settings->setValue ("settings/last_tab", tabWidget->currentIndex ());
+    settings->setValue ("settings/geometry", saveGeometry ());
 
-  // settings dialog's geometry
-  settings->setValue ("settings/last_tab", ui->tabWidget->currentIndex ());
-  settings->setValue ("settings/geometry", saveGeometry ());
-
-  settings->sync ();
-}
+    settings->sync ();
+  }
 
-void
-settings_dialog::read_workspace_colors (QSettings *settings)
-{
+  void settings_dialog::read_workspace_colors (QSettings *settings)
+  {
+    // Construct the grid with all color related settings
+    QList<QColor> default_colors =
+      resource_manager::storage_class_default_colors ();
+    QStringList class_names = resource_manager::storage_class_names ();
+    QString class_chars = resource_manager::storage_class_chars ();
+    int nr_of_classes = class_chars.length ();
 
-  QList<QColor> default_colors =
-    resource_manager::storage_class_default_colors ();
-  QStringList class_names = resource_manager::storage_class_names ();
-  QString class_chars = resource_manager::storage_class_chars ();
-  int nr_of_classes = class_chars.length ();
+    QGridLayout *style_grid = new QGridLayout ();
+    QVector<QLabel*> description (nr_of_classes);
+    QVector<color_picker*> color (nr_of_classes);
 
-  QGridLayout *style_grid = new QGridLayout ();
-  QVector<QLabel*> description (nr_of_classes);
-  QVector<color_picker*> color (nr_of_classes);
+    int column = 0;
+    int row = 0;
+
+    m_ws_enable_colors = new QCheckBox (tr ("Enable attribute colors"));
+    style_grid->addWidget (m_ws_enable_colors, row++, column, 1, 4);
 
-  int column = 0;
-  int row = 0;
-  for (int i = 0; i < nr_of_classes; i++)
-    {
-      description[i] = new QLabel ("    " + class_names.at (i));
-      description[i]->setAlignment (Qt::AlignRight);
-      QVariant default_var = default_colors.at (i);
-      QColor setting_color = settings->value ("workspaceview/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
-      color[i] = new color_picker (setting_color);
-      color[i]->setObjectName ("color_" + class_chars.mid (i, 1));
-      color[i]->setMinimumSize (30, 10);
-      style_grid->addWidget (description[i], row, 3*column);
-      style_grid->addWidget (color[i], row, 3*column+1);
-      if (++column == 3)
-        {
-          style_grid->setColumnStretch (4*column, 10);
-          row++;
-          column = 0;
-        }
-    }
+    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)));
+    m_ws_hide_tool_tips->setChecked (
+      settings->value (ws_hide_tool_tips.key, ws_hide_tool_tips.def).toBool ());
 
-  // place grid with elements into the tab
-  ui->workspace_colors_box->setLayout (style_grid);
-}
+    for (int i = 0; i < nr_of_classes; i++)
+      {
+        description[i] = new QLabel ("    " + class_names.at (i));
+        description[i]->setAlignment (Qt::AlignRight);
+        connect (m_ws_enable_colors, SIGNAL (toggled (bool)),
+                 description[i], SLOT(setEnabled (bool)));
+
+        QVariant default_var = default_colors.at (i);
+        QColor setting_color = settings->value ("workspaceview/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
+        color[i] = new color_picker (setting_color);
+        color[i]->setObjectName ("color_" + class_chars.mid (i, 1));
+        color[i]->setMinimumSize (30, 10);
+        connect (m_ws_enable_colors, SIGNAL (toggled (bool)),
+                 color[i], SLOT(setEnabled (bool)));
 
-void
-settings_dialog::write_workspace_colors (QSettings *settings)
-{
-
-  QString class_chars = resource_manager::storage_class_chars ();
-  color_picker *color;
+        style_grid->addWidget (description[i], row, 3*column);
+        style_grid->addWidget (color[i], row, 3*column+1);
+        if (++column == 3)
+          {
+            style_grid->setColumnStretch (4*column, 10);
+            row++;
+            column = 0;
+          }
+      }
 
-  for (int i = 0; i < class_chars.length (); i++)
-    {
-      color = ui->workspace_colors_box->findChild <color_picker *> ("color_" + class_chars.mid (i, 1));
-      if (color)
-        settings->setValue ("workspaceview/color_" + class_chars.mid (i, 1), color->color ());
-    }
-  settings->sync ();
-}
+    // Load enable settings at the end for having signals already connected
+    bool colors_enabled =
+        settings->value (ws_enable_colors.key, ws_enable_colors.def).toBool ();
+    m_ws_enable_colors->setChecked (colors_enabled);
+    m_ws_hide_tool_tips->setEnabled (colors_enabled);
 
-void
-settings_dialog::read_terminal_colors (QSettings *settings)
-{
+    // place grid with elements into the tab
+    workspace_colors_box->setLayout (style_grid);
+  }
 
-  QList<QColor> default_colors = resource_manager::terminal_default_colors ();
-  QStringList class_names = resource_manager::terminal_color_names ();
-  QString class_chars = resource_manager::terminal_color_chars ();
-  int nr_of_classes = class_chars.length ();
+  void settings_dialog::write_workspace_colors (QSettings *settings)
+  {
+    settings->setValue (ws_enable_colors.key, m_ws_enable_colors->isChecked ());
+    settings->setValue (ws_hide_tool_tips.key, m_ws_hide_tool_tips->isChecked ());
+
+    QString class_chars = resource_manager::storage_class_chars ();
+    color_picker *color;
 
-  QGridLayout *style_grid = new QGridLayout ();
-  QVector<QLabel*> description (nr_of_classes);
-  QVector<color_picker*> color (nr_of_classes);
+    for (int i = 0; i < class_chars.length (); i++)
+      {
+        color = workspace_colors_box->findChild <color_picker *> ("color_" + class_chars.mid (i, 1));
+        if (color)
+          settings->setValue ("workspaceview/color_" + class_chars.mid (i, 1), color->color ());
+      }
+    settings->sync ();
+  }
+
+  void settings_dialog::read_terminal_colors (QSettings *settings)
+  {
+
+    QList<QColor> default_colors = resource_manager::terminal_default_colors ();
+    QStringList class_names = resource_manager::terminal_color_names ();
+    QString class_chars = resource_manager::terminal_color_chars ();
+    int nr_of_classes = class_chars.length ();
+
+    QGridLayout *style_grid = new QGridLayout ();
+    QVector<QLabel*> description (nr_of_classes);
+    QVector<color_picker*> color (nr_of_classes);
 
-  int column = 0;
-  int row = 0;
-  for (int i = 0; i < nr_of_classes; i++)
-    {
-      description[i] = new QLabel ("    " + class_names.at (i));
-      description[i]->setAlignment (Qt::AlignRight);
-      QVariant default_var = default_colors.at (i);
-      QColor setting_color = settings->value ("terminal/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
-      color[i] = new color_picker (setting_color);
-      color[i]->setObjectName ("terminal_color_" + class_chars.mid (i, 1));
-      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)
-        {
-          style_grid->setColumnStretch (3*column, 10);
-          row++;
-          column = 0;
-        }
-    }
+    int column = 0;
+    int row = 0;
+    for (int i = 0; i < nr_of_classes; i++)
+      {
+        description[i] = new QLabel ("    " + class_names.at (i));
+        description[i]->setAlignment (Qt::AlignRight);
+        QVariant default_var = default_colors.at (i);
+        QColor setting_color = settings->value ("terminal/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
+        color[i] = new color_picker (setting_color);
+        color[i]->setObjectName ("terminal_color_" + class_chars.mid (i, 1));
+        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)
+          {
+            style_grid->setColumnStretch (3*column, 10);
+            row++;
+            column = 0;
+          }
+      }
 
-  // place grid with elements into the tab
-  ui->terminal_colors_box->setLayout (style_grid);
-}
-
-void
-settings_dialog::write_terminal_colors (QSettings *settings)
-{
-  QString class_chars = resource_manager::terminal_color_chars ();
-  color_picker *color;
+    // place grid with elements into the tab
+    terminal_colors_box->setLayout (style_grid);
+  }
 
-  for (int i = 0; i < class_chars.length (); i++)
-    {
-      color = ui->terminal_colors_box->findChild <color_picker *> ("terminal_color_" + class_chars.mid (i, 1));
-      if (color)
-        settings->setValue ("terminal/color_" + class_chars.mid (i, 1), color->color ());
-    }
-
-  settings->sync ();
-}
+  void settings_dialog::write_terminal_colors (QSettings *settings)
+  {
+    QString class_chars = resource_manager::terminal_color_chars ();
+    color_picker *color;
 
-void
-settings_dialog::read_varedit_colors (QSettings *settings)
-{
-  QList<QColor> default_colors = octave::variable_editor::default_colors ();
-  QStringList class_names = octave::variable_editor::color_names ();
-  QString class_chars = resource_manager::varedit_color_chars ();
-  int nr_of_classes = class_chars.length ();
+    for (int i = 0; i < class_chars.length (); i++)
+      {
+        color = terminal_colors_box->findChild <color_picker *> ("terminal_color_" + class_chars.mid (i, 1));
+        if (color)
+          settings->setValue ("terminal/color_" + class_chars.mid (i, 1), color->color ());
+      }
+
+    settings->sync ();
+  }
 
-  QGridLayout *style_grid = new QGridLayout ();
-  QVector<QLabel*> description (nr_of_classes);
-  QVector<color_picker*> color (nr_of_classes);
+  void settings_dialog::read_varedit_colors (QSettings *settings)
+  {
+    QList<QColor> default_colors = octave::variable_editor::default_colors ();
+    QStringList class_names = octave::variable_editor::color_names ();
+    QString class_chars = resource_manager::varedit_color_chars ();
+    int nr_of_classes = class_chars.length ();
+
+    QGridLayout *style_grid = new QGridLayout ();
+    QVector<QLabel*> description (nr_of_classes);
+    QVector<color_picker*> color (nr_of_classes);
 
-  int column = 0;
-  int row = 0;
-  for (int i = 0; i < nr_of_classes; i++)
-    {
-      description[i] = new QLabel ("    " + class_names.at (i));
-      description[i]->setAlignment (Qt::AlignRight);
-      QVariant default_var = default_colors.at (i);
-      QColor setting_color = settings->value ("variable_editor/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
-      color[i] = new color_picker (setting_color);
-      color[i]->setObjectName ("varedit_color_" + class_chars.mid (i, 1));
-      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)
-        {
-          style_grid->setColumnStretch (3*column, 10);
-          row++;
-          column = 0;
-        }
-    }
+    int column = 0;
+    int row = 0;
+    for (int i = 0; i < nr_of_classes; i++)
+      {
+        description[i] = new QLabel ("    " + class_names.at (i));
+        description[i]->setAlignment (Qt::AlignRight);
+        QVariant default_var = default_colors.at (i);
+        QColor setting_color = settings->value ("variable_editor/color_" + class_chars.mid (i, 1), default_var).value<QColor> ();
+        color[i] = new color_picker (setting_color);
+        color[i]->setObjectName ("varedit_color_" + class_chars.mid (i, 1));
+        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)
+          {
+            style_grid->setColumnStretch (3*column, 10);
+            row++;
+            column = 0;
+          }
+      }
 
-  // place grid with elements into the tab
-  ui->varedit_colors_box->setLayout (style_grid);
-}
+    // place grid with elements into the tab
+    varedit_colors_box->setLayout (style_grid);
+  }
 
-void
-settings_dialog::write_varedit_colors (QSettings *settings)
-{
-  QString class_chars = resource_manager::varedit_color_chars ();
-  color_picker *color;
+  void settings_dialog::write_varedit_colors (QSettings *settings)
+  {
+    QString class_chars = resource_manager::varedit_color_chars ();
+    color_picker *color;
 
-  for (int i = 0; i < class_chars.length (); i++)
-    {
-      color = ui->varedit_colors_box->findChild <color_picker *> ("varedit_color_" + class_chars.mid (i, 1));
-      if (color)
-        settings->setValue ("variable_editor/color_" + class_chars.mid (i, 1), color->color ());
-    }
+    for (int i = 0; i < class_chars.length (); i++)
+      {
+        color = varedit_colors_box->findChild <color_picker *> ("varedit_color_" + class_chars.mid (i, 1));
+        if (color)
+          settings->setValue ("variable_editor/color_" + class_chars.mid (i, 1), color->color ());
+      }
 
-  settings->sync ();
+    settings->sync ();
+  }
 }
--- a/libgui/src/settings-dialog.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/settings-dialog.h	Thu Dec 20 17:18:56 2018 -0500
@@ -23,71 +23,80 @@
 #if ! defined (octave_settings_dialog_h)
 #define octave_settings_dialog_h 1
 
+#include <QCheckBox>
 #include <QDialog>
 #include <QSettings>
 #include <QLineEdit>
 #include <QRadioButton>
 
 #include "color-picker.h"
-#include "octave-settings.h"
+#include "gui-preferences.h"
+#include "ui-settings-dialog.h"
+
+class QsciLexer;
+
+namespace octave
+{
+  // Ui::settings_dialog is a generated class.
+
+  class settings_dialog : public QDialog, private Ui::settings_dialog
+  {
+    Q_OBJECT public:
+
+    explicit settings_dialog (QWidget *parent,
+                              const QString& desired_tab = QString ());
+
+    ~settings_dialog (void) = default;
+
+    void show_tab (const QString&);
+
+  signals:
+
+    void apply_new_settings (void);
+
+  private slots:
+
+    void get_octave_dir (void);
+    void get_file_browser_dir (void);
+    void get_dir (QLineEdit*, const QString&);
+    void set_disabled_pref_file_browser_dir (bool disable);
+
+    // slots for dialog's buttons
+    void button_clicked (QAbstractButton *button);
 
-namespace Ui
-{
-  class settings_dialog;
+    // slots for import/export-buttons of shortcut sets
+    void import_shortcut_set (void);
+    void export_shortcut_set (void);
+    void default_shortcut_set (void);
+
+  private:
+
+    void read_lexer_settings (QsciLexer *lexer, QSettings *settings);
+    void write_lexer_settings (QsciLexer *lexer, QSettings *settings);
+
+    void write_changed_settings (bool closing);
+
+    void read_workspace_colors (QSettings *settings);
+    void write_workspace_colors (QSettings *settings);
+
+    void read_terminal_colors (QSettings *settings);
+    void write_terminal_colors (QSettings *settings);
+
+    void read_varedit_colors (QSettings *settings);
+    void write_varedit_colors (QSettings *settings);
+
+    color_picker *m_widget_title_bg_color;
+    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];
+    QRadioButton *m_rb_uncomment_strings[ed_comment_strings_count];
+
+    QCheckBox *m_ws_enable_colors;
+    QCheckBox *m_ws_hide_tool_tips;
+  };
 }
 
-class settings_dialog:public QDialog
-{
-  Q_OBJECT public:
-
-  explicit settings_dialog (QWidget *parent,
-                            const QString& desired_tab = QString ());
-  ~settings_dialog (void);
-
-  void show_tab (const QString&);
-
-signals:
-
-  void apply_new_settings (void);
-
-private slots:
-
-  void get_octave_dir (void);
-  void get_file_browser_dir (void);
-  void get_dir (QLineEdit*, const QString&);
-  void set_disabled_pref_file_browser_dir (bool disable);
-
-  // slots for dialog's buttons
-  void button_clicked (QAbstractButton *button);
-
-  // slots for import/export-buttons of shortcut sets
-  void import_shortcut_set (void);
-  void export_shortcut_set (void);
-  void default_shortcut_set (void);
-
-private:
-
-  Ui::settings_dialog *ui;
-
-  void write_changed_settings (bool closing);
-
-  void read_workspace_colors (QSettings *settings);
-  void write_workspace_colors (QSettings *settings);
-
-  void read_terminal_colors (QSettings *settings);
-  void write_terminal_colors (QSettings *settings);
-
-  void read_varedit_colors (QSettings *settings);
-  void write_varedit_colors (QSettings *settings);
-
-  color_picker *m_widget_title_bg_color;
-  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[oct_comment_strings_count];
-  QRadioButton *m_rb_uncomment_strings[oct_comment_strings_count];
-};
-
 #endif
--- a/libgui/src/settings-dialog.ui	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/settings-dialog.ui	Thu Dec 20 17:18:56 2018 -0500
@@ -20,7 +20,7 @@
    </size>
   </property>
   <property name="windowTitle">
-   <string>Settings</string>
+   <string>Preferences</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
@@ -32,7 +32,7 @@
       </size>
      </property>
      <property name="currentIndex">
-      <number>8</number>
+      <number>0</number>
      </property>
      <widget class="QWidget" name="tab_general">
       <property name="enabled">
@@ -53,7 +53,7 @@
             <x>0</x>
             <y>0</y>
             <width>658</width>
-            <height>573</height>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_17">
@@ -65,47 +65,6 @@
              <layout class="QVBoxLayout" name="verticalLayout_21">
               <item>
                <layout class="QGridLayout" name="gridLayout">
-                <item row="2" column="1">
-                 <layout class="QHBoxLayout" name="horizontalLayout_6">
-                  <item>
-                   <widget class="QRadioButton" name="icon_size_small">
-                    <property name="text">
-                     <string>Small</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QRadioButton" name="icon_size_normal">
-                    <property name="text">
-                     <string>Normal</string>
-                    </property>
-                    <property name="checked">
-                     <bool>true</bool>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QRadioButton" name="icon_size_large">
-                    <property name="text">
-                     <string>Large</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <spacer name="horizontalSpacer_4">
-                    <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>
                 <item row="1" column="1">
                  <layout class="QHBoxLayout" name="horizontalLayout_8">
                   <item>
@@ -116,6 +75,13 @@
                    </widget>
                   </item>
                   <item>
+                   <widget class="QLabel" name="label_10">
+                    <property name="text">
+                     <string>(requires restart)</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
                    <spacer name="horizontalSpacer_3">
                     <property name="orientation">
                      <enum>Qt::Horizontal</enum>
@@ -130,31 +96,157 @@
                   </item>
                  </layout>
                 </item>
-                <item row="2" column="0">
-                 <widget class="QLabel" name="label_8">
+                <item row="7" column="0">
+                 <widget class="QLabel" name="label_15">
                   <property name="text">
-                   <string>Icon size</string>
+                   <string>Dock widget title bar</string>
                   </property>
                   <property name="alignment">
                    <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
                   </property>
                  </widget>
                 </item>
-                <item row="7" column="0">
-                 <widget class="QCheckBox" name="cb_prompt_to_exit">
+                <item row="8" column="0">
+                 <widget class="QCheckBox" name="cb_use_native_file_dialogs">
                   <property name="text">
-                   <string>Confirm before exiting</string>
+                   <string>Use native file dialogs</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
                   </property>
                  </widget>
                 </item>
-                <item row="1" column="0">
-                 <widget class="QLabel" name="label_2">
+                <item row="3" column="1">
+                 <layout class="QVBoxLayout" name="verticalLayout_5">
+                  <item>
+                   <layout class="QHBoxLayout" name="horizontalLayout_6">
+                    <item>
+                     <widget class="QRadioButton" name="icon_size_small">
+                      <property name="text">
+                       <string>Small</string>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="QRadioButton" name="icon_size_normal">
+                      <property name="text">
+                       <string>Normal</string>
+                      </property>
+                      <property name="checked">
+                       <bool>true</bool>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="QRadioButton" name="icon_size_large">
+                      <property name="text">
+                       <string>Large</string>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <spacer name="horizontalSpacer_4">
+                      <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>
+                  <item>
+                   <widget class="QCheckBox" name="cb_system_icon_theme">
+                    <property name="text">
+                     <string>Use system icon theme if available (requires restart)</string>
+                    </property>
+                   </widget>
+                  </item>
+                 </layout>
+                </item>
+                <item row="9" column="0">
+                 <widget class="QCheckBox" name="cb_cursor_blinking">
                   <property name="text">
-                   <string>Language (requires restart)</string>
+                   <string>Cursor blinking</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
                   </property>
                  </widget>
                 </item>
-                <item row="4" column="1">
+                <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>
+                   <widget class="QRadioButton" name="general_icon_octave">
+                    <property name="text">
+                     <string>Octave logo only</string>
+                    </property>
+                    <property name="checked">
+                     <bool>true</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QRadioButton" name="general_icon_letter">
+                    <property name="text">
+                     <string>Letter icons</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QRadioButton" name="general_icon_graphic">
+                    <property name="text">
+                     <string>Graphic icons</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <spacer name="horizontalSpacer_6">
+                    <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>
+                <item row="3" column="0">
+                 <widget class="QLabel" name="label_8">
+                  <property name="text">
+                   <string>Toolbar Icons</string>
+                  </property>
+                  <property name="alignment">
+                   <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+                  </property>
+                 </widget>
+                </item>
+                <item row="5" column="0">
+                 <widget class="QLabel" name="label_9">
+                  <property name="text">
+                   <string>Icon set for dock widgets</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="7" column="1">
                  <layout class="QHBoxLayout" name="horizontalLayout_4">
                   <item>
                    <layout class="QGridLayout" name="gridLayout_13">
@@ -316,44 +408,27 @@
                   </item>
                  </layout>
                 </item>
-                <item row="4" column="0">
-                 <widget class="QLabel" name="label_15">
+                <item row="11" column="0">
+                 <widget class="QCheckBox" name="cb_prompt_to_exit">
                   <property name="text">
-                   <string>Dock widget title bar</string>
-                  </property>
-                  <property name="alignment">
-                   <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+                   <string>Confirm before exiting</string>
                   </property>
                  </widget>
                 </item>
-                <item row="3" column="1">
-                 <layout class="QHBoxLayout" name="horizontalLayout_9">
+                <item row="1" column="0">
+                 <widget class="QLabel" name="label_2">
+                  <property name="text">
+                   <string>Language</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="1">
+                 <layout class="QHBoxLayout" name="horizontalLayout_17">
                   <item>
-                   <widget class="QRadioButton" name="general_icon_octave">
-                    <property name="text">
-                     <string>Octave logo only</string>
-                    </property>
-                    <property name="checked">
-                     <bool>true</bool>
-                    </property>
-                   </widget>
+                   <widget class="QComboBox" name="combo_styles"/>
                   </item>
                   <item>
-                   <widget class="QRadioButton" name="general_icon_letter">
-                    <property name="text">
-                     <string>Letter icons</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QRadioButton" name="general_icon_graphic">
-                    <property name="text">
-                     <string>Graphic icons</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <spacer name="horizontalSpacer_6">
+                   <spacer name="horizontalSpacer">
                     <property name="orientation">
                      <enum>Qt::Horizontal</enum>
                     </property>
@@ -367,30 +442,10 @@
                   </item>
                  </layout>
                 </item>
-                <item row="3" column="0">
-                 <widget class="QLabel" name="label_9">
-                  <property name="text">
-                   <string>Icon set for dock widgets</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="6" column="0">
-                 <widget class="QCheckBox" name="cb_status_bar">
+                <item row="2" column="0">
+                 <widget class="QLabel" name="label_29">
                   <property name="text">
-                   <string>Show status bar</string>
-                  </property>
-                  <property name="checked">
-                   <bool>true</bool>
-                  </property>
-                 </widget>
-                </item>
-                <item row="5" column="0">
-                 <widget class="QCheckBox" name="cb_cursor_blinking">
-                  <property name="text">
-                   <string>Cursor blinking</string>
-                  </property>
-                  <property name="checked">
-                   <bool>true</bool>
+                   <string>Style</string>
                   </property>
                  </widget>
                 </item>
@@ -414,61 +469,45 @@
               </item>
               <item>
                <layout class="QGridLayout" name="gridLayout_9">
-                <item row="0" column="5">
-                 <spacer name="horizontalSpacer">
-                  <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="1" column="5">
-                 <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>
                 <item row="0" column="0">
                  <widget class="QLabel" name="label_17">
                   <property name="text">
-                   <string>Startup path</string>
+                   <string>Initial working directory of Octave interpreter</string>
                   </property>
-                 </widget>
-                </item>
-                <item row="1" column="3">
-                 <widget class="QPushButton" name="pb_octave_dir">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
+                  <property name="alignment">
+                   <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
                   </property>
-                  <property name="text">
-                   <string>Browse</string>
+                  <property name="wordWrap">
+                   <bool>true</bool>
                   </property>
                  </widget>
                 </item>
                 <item row="0" column="1">
-                 <widget class="QCheckBox" name="cb_restore_octave_dir">
-                  <property name="text">
-                   <string>Restore working directory of previous session</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="1">
-                 <widget class="QLineEdit" name="le_octave_dir"/>
+                 <layout class="QGridLayout" name="gridLayout_20">
+                  <item row="1" column="0">
+                   <widget class="QLineEdit" name="le_octave_dir"/>
+                  </item>
+                  <item row="0" column="0">
+                   <widget class="QCheckBox" name="cb_restore_octave_dir">
+                    <property name="text">
+                     <string>Restore last working directory of previous session</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="1">
+                   <widget class="QPushButton" name="pb_octave_dir">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+                      <horstretch>0</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="text">
+                     <string>Browse</string>
+                    </property>
+                   </widget>
+                  </item>
+                 </layout>
                 </item>
                </layout>
               </item>
@@ -494,13 +533,294 @@
        </item>
       </layout>
      </widget>
+     <widget class="QWidget" name="tab_terminal">
+      <attribute name="title">
+       <string>Command</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_14">
+       <item>
+        <widget class="QScrollArea" name="scrollArea_3">
+         <property name="widgetResizable">
+          <bool>true</bool>
+         </property>
+         <widget class="QWidget" name="scrollAreaWidgetContents_4">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>658</width>
+            <height>571</height>
+           </rect>
+          </property>
+          <layout class="QVBoxLayout" name="verticalLayout_7">
+           <item>
+            <layout class="QVBoxLayout" name="verticalLayout_8">
+             <item>
+              <layout class="QGridLayout" name="gridLayout_7">
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+               <item row="1" column="2">
+                <layout class="QHBoxLayout" name="horizontalLayout_13">
+                 <item>
+                  <widget class="QCheckBox" name="terminal_cursorUseForegroundColor">
+                   <property name="text">
+                    <string>Use foreground color</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </item>
+               <item row="1" column="0">
+                <layout class="QHBoxLayout" name="horizontalLayout_7">
+                 <item>
+                  <widget class="QLabel" name="label">
+                   <property name="text">
+                    <string>Cursor type:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QComboBox" name="terminal_cursorType"/>
+                 </item>
+                </layout>
+               </item>
+               <item row="0" column="0">
+                <layout class="QHBoxLayout" name="horizontalLayout_11">
+                 <item>
+                  <widget class="QLabel" name="label_11">
+                   <property name="text">
+                    <string>Font</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QFontComboBox" name="terminal_fontName">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="editable">
+                    <bool>false</bool>
+                   </property>
+                   <property name="fontFilters">
+                    <set>QFontComboBox::MonospacedFonts</set>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </item>
+               <item row="0" column="2">
+                <layout class="QHBoxLayout" name="horizontalLayout_12">
+                 <item>
+                  <widget class="QLabel" name="label_12">
+                   <property name="text">
+                    <string>Font size</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QSpinBox" name="terminal_fontSize">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="minimum">
+                    <number>2</number>
+                   </property>
+                   <property name="maximum">
+                    <number>96</number>
+                   </property>
+                   <property name="value">
+                    <number>10</number>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <spacer name="horizontalSpacer_27">
+                   <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>
+               <item row="2" column="2">
+                <layout class="QHBoxLayout" name="horizontalLayout_5">
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <item>
+                  <widget class="QSpinBox" name="terminal_history_buffer">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="minimum">
+                    <number>0</number>
+                   </property>
+                   <property name="maximum">
+                    <number>5000</number>
+                   </property>
+                   <property name="singleStep">
+                    <number>20</number>
+                   </property>
+                   <property name="value">
+                    <number>1000</number>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QLabel" name="label_20">
+                   <property name="text">
+                    <string>(Changing buffer size clears history)</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <spacer name="horizontalSpacer_16">
+                   <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>
+               <item row="2" column="0">
+                <widget class="QLabel" name="label_19">
+                 <property name="minimumSize">
+                  <size>
+                   <width>100</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>History buffer Size</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="1">
+                <spacer name="horizontalSpacer_28">
+                 <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>
+             <item>
+              <layout class="QGridLayout" name="gridLayout_15">
+               <item row="0" column="0">
+                <widget class="QCheckBox" name="terminal_focus_command">
+                 <property name="text">
+                  <string>Set focus to Command Window when running a command from within another widget</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="0">
+                <widget class="QCheckBox" name="terminal_print_dbg_location">
+                 <property name="text">
+                  <string>Print debug location in Command Window in addition to the marker in the editor</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <widget class="Line" name="line_7">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QGroupBox" name="terminal_colors_box">
+               <property name="title">
+                <string>Command Window Colors</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="Line" name="line_5">
+               <property name="minimumSize">
+                <size>
+                 <width>0</width>
+                 <height>0</height>
+                </size>
+               </property>
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="Line" name="line_6">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_3">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeType">
+              <enum>QSizePolicy::Expanding</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
      <widget class="QWidget" name="tab_editor">
       <attribute name="title">
        <string>Editor</string>
       </attribute>
       <layout class="QVBoxLayout" name="verticalLayout_6">
        <item>
-        <widget class="QScrollArea" name="scrollArea">
+        <widget class="QScrollArea" name="tab_editor_scroll_area">
          <property name="widgetResizable">
           <bool>true</bool>
          </property>
@@ -510,7 +830,7 @@
             <x>0</x>
             <y>0</y>
             <width>645</width>
-            <height>1012</height>
+            <height>1213</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -1584,6 +1904,32 @@
             </widget>
            </item>
            <item>
+            <widget class="QGroupBox" name="groupBox_10">
+             <property name="enabled">
+              <bool>true</bool>
+             </property>
+             <property name="title">
+              <string>Debugging</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_12">
+              <item>
+               <layout class="QGridLayout" name="gridLayout_19">
+                <item row="0" column="0">
+                 <widget class="QCheckBox" name="editor_show_dbg_file">
+                  <property name="text">
+                   <string>Always show debug breakpoints and pointers (opens related file if closed)</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
             <widget class="QGroupBox" name="groupBox_8">
              <property name="title">
               <string>File handling</string>
@@ -1635,7 +1981,7 @@
                     </property>
                    </widget>
                   </item>
-                  <item row="6" column="0">
+                  <item row="8" column="0">
                    <layout class="QHBoxLayout" name="horizontalLayout_2">
                     <property name="topMargin">
                      <number>0</number>
@@ -1693,7 +2039,7 @@
                     </item>
                    </layout>
                   </item>
-                  <item row="8" column="0">
+                  <item row="10" column="0">
                    <layout class="QHBoxLayout" name="horizontalLayout_16">
                     <item>
                      <widget class="QLabel" name="label_16">
@@ -1720,11 +2066,14 @@
                     </item>
                    </layout>
                   </item>
-                  <item row="5" column="0">
+                  <item row="7" 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>
                     </property>
+                    <property name="checked">
+                     <bool>true</bool>
+                    </property>
                    </widget>
                   </item>
                  </layout>
@@ -1735,6 +2084,44 @@
             </widget>
            </item>
            <item>
+            <widget class="QGroupBox" name="group_box_editor_styles">
+             <property name="enabled">
+              <bool>true</bool>
+             </property>
+             <property name="autoFillBackground">
+              <bool>false</bool>
+             </property>
+             <property name="title">
+              <string>Editor Styles</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_31">
+              <item>
+               <widget class="QLabel" name="label_23">
+                <property name="text">
+                 <string>&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;</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QTabWidget" name="tabs_editor_lexers">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
             <spacer name="verticalSpacer_7">
              <property name="orientation">
               <enum>Qt::Vertical</enum>
@@ -1742,343 +2129,7 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>20</width>
-               <height>40</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-          </layout>
-         </widget>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="tab_editor_styles">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-        <horstretch>0</horstretch>
-        <verstretch>0</verstretch>
-       </sizepolicy>
-      </property>
-      <attribute name="title">
-       <string>Editor Styles</string>
-      </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout_12">
-       <item>
-        <layout class="QVBoxLayout" name="verticalLayout_5">
-         <item>
-          <widget class="QLabel" name="label_10">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="frameShape">
-            <enum>QFrame::NoFrame</enum>
-           </property>
-           <property name="text">
-            <string>&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;</string>
-           </property>
-           <property name="scaledContents">
-            <bool>false</bool>
-           </property>
-           <property name="alignment">
-            <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-           </property>
-           <property name="wordWrap">
-            <bool>true</bool>
-           </property>
-           <property name="margin">
-            <number>4</number>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QTabWidget" name="tabs_editor_lexers">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="tab_terminal">
-      <attribute name="title">
-       <string>Terminal</string>
-      </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout_14">
-       <item>
-        <widget class="QScrollArea" name="scrollArea_3">
-         <property name="widgetResizable">
-          <bool>true</bool>
-         </property>
-         <widget class="QWidget" name="scrollAreaWidgetContents_4">
-          <property name="geometry">
-           <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>658</width>
-            <height>573</height>
-           </rect>
-          </property>
-          <layout class="QVBoxLayout" name="verticalLayout_7">
-           <item>
-            <layout class="QVBoxLayout" name="verticalLayout_8">
-             <item>
-              <layout class="QGridLayout" name="gridLayout_7">
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>40</width>
-                 <height>20</height>
-                </size>
-               </property>
-               <item row="1" column="2">
-                <layout class="QHBoxLayout" name="horizontalLayout_13">
-                 <item>
-                  <widget class="QCheckBox" name="terminal_cursorUseForegroundColor">
-                   <property name="text">
-                    <string>Use foreground color</string>
-                   </property>
-                  </widget>
-                 </item>
-                </layout>
-               </item>
-               <item row="1" column="0">
-                <layout class="QHBoxLayout" name="horizontalLayout_7">
-                 <item>
-                  <widget class="QLabel" name="label">
-                   <property name="text">
-                    <string>Cursor type:</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <widget class="QComboBox" name="terminal_cursorType"/>
-                 </item>
-                </layout>
-               </item>
-               <item row="0" column="0">
-                <layout class="QHBoxLayout" name="horizontalLayout_11">
-                 <item>
-                  <widget class="QLabel" name="label_11">
-                   <property name="text">
-                    <string>Font</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <widget class="QFontComboBox" name="terminal_fontName">
-                   <property name="sizePolicy">
-                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                     <horstretch>0</horstretch>
-                     <verstretch>0</verstretch>
-                    </sizepolicy>
-                   </property>
-                   <property name="editable">
-                    <bool>false</bool>
-                   </property>
-                   <property name="fontFilters">
-                    <set>QFontComboBox::MonospacedFonts</set>
-                   </property>
-                  </widget>
-                 </item>
-                </layout>
-               </item>
-               <item row="0" column="2">
-                <layout class="QHBoxLayout" name="horizontalLayout_12">
-                 <item>
-                  <widget class="QLabel" name="label_12">
-                   <property name="text">
-                    <string>Font size</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <widget class="QSpinBox" name="terminal_fontSize">
-                   <property name="sizePolicy">
-                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                     <horstretch>0</horstretch>
-                     <verstretch>0</verstretch>
-                    </sizepolicy>
-                   </property>
-                   <property name="minimum">
-                    <number>2</number>
-                   </property>
-                   <property name="maximum">
-                    <number>96</number>
-                   </property>
-                   <property name="value">
-                    <number>10</number>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <spacer name="horizontalSpacer_27">
-                   <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>
-               <item row="2" column="2">
-                <layout class="QHBoxLayout" name="horizontalLayout_5">
-                 <property name="topMargin">
-                  <number>0</number>
-                 </property>
-                 <item>
-                  <widget class="QSpinBox" name="terminal_history_buffer">
-                   <property name="sizePolicy">
-                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                     <horstretch>0</horstretch>
-                     <verstretch>0</verstretch>
-                    </sizepolicy>
-                   </property>
-                   <property name="minimum">
-                    <number>0</number>
-                   </property>
-                   <property name="maximum">
-                    <number>5000</number>
-                   </property>
-                   <property name="singleStep">
-                    <number>20</number>
-                   </property>
-                   <property name="value">
-                    <number>1000</number>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <widget class="QLabel" name="label_20">
-                   <property name="text">
-                    <string>(Changing buffer size clears history)</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item>
-                  <spacer name="horizontalSpacer_16">
-                   <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>
-               <item row="2" column="0">
-                <widget class="QLabel" name="label_19">
-                 <property name="minimumSize">
-                  <size>
-                   <width>100</width>
-                   <height>20</height>
-                  </size>
-                 </property>
-                 <property name="text">
-                  <string>History buffer Size</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1">
-                <spacer name="horizontalSpacer_28">
-                 <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>
-             <item>
-              <layout class="QGridLayout" name="gridLayout_15">
-               <item row="0" column="0">
-                <widget class="QCheckBox" name="terminal_focus_command">
-                 <property name="text">
-                  <string>Set focus to terminal when running a command from within another widget</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="0">
-                <widget class="QCheckBox" name="terminal_print_dbg_location">
-                 <property name="text">
-                  <string>Print debug location in terminal window in addition to the marker in the editor</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-             <item>
-              <widget class="Line" name="line_7">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QGroupBox" name="terminal_colors_box">
-               <property name="title">
-                <string>Terminal Colors</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="Line" name="line_5">
-               <property name="minimumSize">
-                <size>
-                 <width>0</width>
-                 <height>0</height>
-                </size>
-               </property>
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="Line" name="line_6">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <spacer name="verticalSpacer_3">
-             <property name="orientation">
-              <enum>Qt::Vertical</enum>
-             </property>
-             <property name="sizeType">
-              <enum>QSizePolicy::Expanding</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>20</width>
-               <height>40</height>
+               <height>20</height>
               </size>
              </property>
             </spacer>
@@ -2105,7 +2156,7 @@
             <x>0</x>
             <y>0</y>
             <width>658</width>
-            <height>573</height>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QGridLayout" name="gridLayout_8">
@@ -2126,23 +2177,53 @@
                 </item>
                 <item>
                  <layout class="QGridLayout" name="lo_file_browser_startup">
-                  <item row="1" column="3">
-                   <spacer name="horizontalSpacer_30">
-                    <property name="orientation">
-                     <enum>Qt::Horizontal</enum>
+                  <item row="0" column="1">
+                   <layout class="QGridLayout" name="gridLayout_22">
+                    <property name="topMargin">
+                     <number>0</number>
                     </property>
-                    <property name="sizeHint" stdset="0">
-                     <size>
-                      <width>40</width>
-                      <height>20</height>
-                     </size>
+                    <item row="0" column="0">
+                     <widget class="QCheckBox" name="cb_restore_file_browser_dir">
+                      <property name="text">
+                       <string>Restore last directory of previous session</string>
+                      </property>
+                     </widget>
+                    </item>
+                    <item row="1" column="0">
+                     <widget class="QLineEdit" name="le_file_browser_dir">
+                      <property name="sizePolicy">
+                       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                        <horstretch>0</horstretch>
+                        <verstretch>0</verstretch>
+                       </sizepolicy>
+                      </property>
+                     </widget>
+                    </item>
+                    <item row="1" column="1">
+                     <widget class="QPushButton" name="pb_file_browser_dir">
+                      <property name="sizePolicy">
+                       <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                        <horstretch>0</horstretch>
+                        <verstretch>0</verstretch>
+                       </sizepolicy>
+                      </property>
+                      <property name="text">
+                       <string>Browse</string>
+                      </property>
+                     </widget>
+                    </item>
+                   </layout>
+                  </item>
+                  <item row="0" column="0">
+                   <widget class="QLabel" name="lbl_file_browser_dir">
+                    <property name="text">
+                     <string>Initial file browser directory (only if not synchronized with initial working directoy of Octave)</string>
                     </property>
-                   </spacer>
-                  </item>
-                  <item row="0" column="1">
-                   <widget class="QCheckBox" name="cb_restore_file_browser_dir">
-                    <property name="text">
-                     <string>Restore last directory of previous session</string>
+                    <property name="alignment">
+                     <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+                    </property>
+                    <property name="wordWrap">
+                     <bool>true</bool>
                     </property>
                    </widget>
                   </item>
@@ -2153,49 +2234,25 @@
                     </property>
                     <property name="sizeHint" stdset="0">
                      <size>
-                      <width>40</width>
+                      <width>20</width>
                       <height>20</height>
                      </size>
                     </property>
                    </spacer>
                   </item>
-                  <item row="1" column="2">
-                   <widget class="QPushButton" name="pb_file_browser_dir">
+                 </layout>
+                </item>
+                <item>
+                 <layout class="QVBoxLayout" name="verticalLayout_9">
+                  <item alignment="Qt::AlignTop">
+                   <widget class="QLabel" name="lbl_file_browser_extensions">
                     <property name="sizePolicy">
-                     <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                     <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
                       <horstretch>0</horstretch>
                       <verstretch>0</verstretch>
                      </sizepolicy>
                     </property>
                     <property name="text">
-                     <string>Browse</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="0" column="0">
-                   <widget class="QLabel" name="lbl_file_browser_dir">
-                    <property name="text">
-                     <string>Startup path</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="1" column="1">
-                   <widget class="QLineEdit" name="le_file_browser_dir">
-                    <property name="sizePolicy">
-                     <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-                      <horstretch>0</horstretch>
-                      <verstretch>0</verstretch>
-                     </sizepolicy>
-                    </property>
-                   </widget>
-                  </item>
-                 </layout>
-                </item>
-                <item>
-                 <layout class="QVBoxLayout" name="verticalLayout_9">
-                  <item>
-                   <widget class="QLabel" name="lbl_file_browser_extensions">
-                    <property name="text">
                      <string>Extensions of files to be opened in the default text editor (separated by &quot;;&quot;):</string>
                     </property>
                    </widget>
@@ -2222,7 +2279,7 @@
              <property name="sizeHint" stdset="0">
               <size>
                <width>20</width>
-               <height>360</height>
+               <height>100</height>
               </size>
              </property>
             </spacer>
@@ -2249,7 +2306,7 @@
             <x>0</x>
             <y>0</y>
             <width>658</width>
-            <height>573</height>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_19">
@@ -2274,17 +2331,212 @@
                </property>
               </widget>
              </item>
-             <item row="1" column="0">
-              <widget class="QCheckBox" name="cb_hide_tool_tips">
-               <property name="text">
-                <string>Hide tool tips</string>
+            </layout>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_6">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="tab_varedit">
+      <attribute name="title">
+       <string>Variable Editor</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_ve_manual">
+       <item>
+        <widget class="QScrollArea" name="scrollArea_8">
+         <property name="widgetResizable">
+          <bool>true</bool>
+         </property>
+         <widget class="QWidget" name="scrollAreaWidgetContents_3">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>669</width>
+            <height>558</height>
+           </rect>
+          </property>
+          <layout class="QVBoxLayout" name="verticalLayout_vesc_manual">
+           <property name="geometry" stdset="0">
+            <rect>
+             <x>0</x>
+             <y>0</y>
+             <width>678</width>
+             <height>384</height>
+            </rect>
+           </property>
+           <item>
+            <layout class="QVBoxLayout" name="verticalLayout_ve">
+             <item>
+              <layout class="QGridLayout" name="gridLayout_ve">
+               <item row="0" column="3">
+                <widget class="QLabel" name="label_26">
+                 <property name="text">
+                  <string>Font size</string>
+                 </property>
+                 <property name="alignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                 </property>
+                </widget>
+               </item>
+               <item row="2" column="2" colspan="2">
+                <widget class="QCheckBox" name="varedit_rowAutofit">
+                 <property name="text">
+                  <string>Plus font height</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item row="2" column="0">
+                <widget class="QLabel" name="label_27">
+                 <property name="text">
+                  <string>Default row height</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="0">
+                <widget class="QLabel" name="label_25">
+                 <property name="text">
+                  <string>Font</string>
+                 </property>
+                 <property name="alignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="0">
+                <widget class="QLabel" name="label_ve_colwidth">
+                 <property name="text">
+                  <string>Default column width</string>
+                 </property>
+                 <property name="alignment">
+                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="5">
+                <widget class="QCheckBox" name="varedit_useTerminalFont">
+                 <property name="text">
+                  <string>Use Command Window Font</string>
+                 </property>
+                 <property name="checked">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="4">
+                <widget class="QSpinBox" name="varedit_fontSize">
+                 <property name="value">
+                  <number>10</number>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="1" colspan="2">
+                <widget class="QFontComboBox" name="varedit_font">
+                 <property name="currentFont">
+                  <font>
+                   <family>Liberation Mono</family>
+                  </font>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="2">
+                <widget class="QCheckBox" name="varedit_autoFitColumnWidth">
+                 <property name="text">
+                  <string>Autofit</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="3" colspan="2">
+                <widget class="QComboBox" name="varedit_autofitType">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="currentIndex">
+                  <number>0</number>
+                 </property>
+                 <item>
+                  <property name="text">
+                   <string>By Column</string>
+                  </property>
+                 </item>
+                 <item>
+                  <property name="text">
+                   <string>Uniform</string>
+                  </property>
+                 </item>
+                </widget>
+               </item>
+               <item row="2" column="6">
+                <spacer name="horizontalSpacer_ve">
+                 <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="2" column="1">
+                <widget class="QSpinBox" name="varedit_rowHeight">
+                 <property name="value">
+                  <number>10</number>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="1">
+                <widget class="QSpinBox" name="varedit_columnWidth">
+                 <property name="maximum">
+                  <number>500</number>
+                 </property>
+                 <property name="value">
+                  <number>100</number>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <widget class="QGroupBox" name="varedit_colors_box">
+               <property name="title">
+                <string>Variable Editor Colors</string>
                </property>
               </widget>
              </item>
             </layout>
            </item>
            <item>
-            <spacer name="verticalSpacer_6">
+            <widget class="QCheckBox" name="varedit_alternate">
+             <property name="enabled">
+              <bool>true</bool>
+             </property>
+             <property name="text">
+              <string>Use alternating row colors</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_4">
              <property name="orientation">
               <enum>Qt::Vertical</enum>
              </property>
@@ -2318,7 +2570,7 @@
             <x>0</x>
             <y>0</y>
             <width>658</width>
-            <height>573</height>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_25">
@@ -2338,7 +2590,7 @@
                   <string>Select this option to prevent conflicts with readline shortcuts</string>
                  </property>
                  <property name="text">
-                  <string>Disable global shortcuts when terminal window has focus</string>
+                  <string>Disable global shortcuts when Command Window has focus</string>
                  </property>
                  <property name="checked">
                   <bool>true</bool>
@@ -2517,7 +2769,7 @@
             <x>0</x>
             <y>0</y>
             <width>658</width>
-            <height>573</height>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_20">
@@ -2660,208 +2912,6 @@
        </item>
       </layout>
      </widget>
-     <widget class="QWidget" name="tab_varedit">
-      <attribute name="title">
-       <string>Variable Editor</string>
-      </attribute>
-      <layout class="QVBoxLayout" name="verticalLayout_ve_manual">
-       <item>
-        <widget class="QScrollArea" name="scrollArea_8">
-         <property name="widgetResizable">
-          <bool>true</bool>
-         </property>
-         <widget class="QWidget" name="scrollAreaWidgetContents_3">
-          <property name="geometry">
-           <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>658</width>
-            <height>573</height>
-           </rect>
-          </property>
-          <layout class="QVBoxLayout" name="verticalLayout_vesc_manual">
-           <property name="geometry" stdset="0">
-            <rect>
-             <x>0</x>
-             <y>0</y>
-             <width>678</width>
-             <height>384</height>
-            </rect>
-           </property>
-           <item>
-            <layout class="QVBoxLayout" name="verticalLayout_ve">
-             <item>
-              <layout class="QGridLayout" name="gridLayout_ve">
-               <item row="0" column="3">
-                <widget class="QLabel" name="label_26">
-                 <property name="text">
-                  <string>Font size</string>
-                 </property>
-                 <property name="alignment">
-                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="2" colspan="2">
-                <widget class="QCheckBox" name="varedit_rowAutofit">
-                 <property name="text">
-                  <string>Plus font height</string>
-                 </property>
-                 <property name="checked">
-                  <bool>true</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="0">
-                <widget class="QLabel" name="label_27">
-                 <property name="text">
-                  <string>Default row height</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="0">
-                <widget class="QLabel" name="label_25">
-                 <property name="text">
-                  <string>Font</string>
-                 </property>
-                 <property name="alignment">
-                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="0">
-                <widget class="QLabel" name="label_ve_colwidth">
-                 <property name="text">
-                  <string>Default column width</string>
-                 </property>
-                 <property name="alignment">
-                  <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="5">
-                <widget class="QCheckBox" name="varedit_useTerminalFont">
-                 <property name="text">
-                  <string>Use Terminal Font</string>
-                 </property>
-                 <property name="checked">
-                  <bool>true</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="4">
-                <widget class="QSpinBox" name="varedit_fontSize">
-                 <property name="value">
-                  <number>10</number>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1" colspan="2">
-                <widget class="QFontComboBox" name="varedit_font">
-                 <property name="currentFont">
-                  <font>
-                   <family>Liberation Mono</family>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="2">
-                <widget class="QCheckBox" name="varedit_autoFitColumnWidth">
-                 <property name="text">
-                  <string>Autofit</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="3" colspan="2">
-                <widget class="QComboBox" name="varedit_autofitType">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="currentIndex">
-                  <number>0</number>
-                 </property>
-                 <item>
-                  <property name="text">
-                   <string>By Column</string>
-                  </property>
-                 </item>
-                 <item>
-                  <property name="text">
-                   <string>Uniform</string>
-                  </property>
-                 </item>
-                </widget>
-               </item>
-               <item row="2" column="6">
-                <spacer name="horizontalSpacer_ve">
-                 <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="2" column="1">
-                <widget class="QSpinBox" name="varedit_rowHeight">
-                 <property name="value">
-                  <number>10</number>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="1">
-                <widget class="QSpinBox" name="varedit_columnWidth">
-                 <property name="maximum">
-                  <number>500</number>
-                 </property>
-                 <property name="value">
-                  <number>100</number>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-             <item>
-              <widget class="QGroupBox" name="varedit_colors_box">
-               <property name="title">
-                <string>Variable Editor Colors</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <widget class="QCheckBox" name="varedit_alternate">
-             <property name="enabled">
-              <bool>true</bool>
-             </property>
-             <property name="text">
-              <string>Use alternating row colors</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <spacer name="verticalSpacer_4">
-             <property name="orientation">
-              <enum>Qt::Vertical</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>20</width>
-               <height>40</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-          </layout>
-         </widget>
-        </widget>
-       </item>
-      </layout>
-     </widget>
     </widget>
    </item>
    <item>
@@ -2910,6 +2960,22 @@
   <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>
@@ -2942,22 +3008,6 @@
   <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>proxyPort</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
@@ -3006,7 +3056,7 @@
   <connection>
    <sender>useProxyServer</sender>
    <signal>toggled(bool)</signal>
-   <receiver>proxyUserName</receiver>
+   <receiver>label_6</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
@@ -3014,8 +3064,8 @@
      <y>59</y>
     </hint>
     <hint type="destinationlabel">
-     <x>364</x>
-     <y>184</y>
+     <x>68</x>
+     <y>182</y>
     </hint>
    </hints>
   </connection>
@@ -3038,7 +3088,7 @@
   <connection>
    <sender>useProxyServer</sender>
    <signal>toggled(bool)</signal>
-   <receiver>label_6</receiver>
+   <receiver>proxyUserName</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
@@ -3046,8 +3096,8 @@
      <y>59</y>
     </hint>
     <hint type="destinationlabel">
-     <x>68</x>
-     <y>182</y>
+     <x>364</x>
+     <y>184</y>
     </hint>
    </hints>
   </connection>
@@ -3068,54 +3118,6 @@
    </hints>
   </connection>
   <connection>
-   <sender>editor_codeCompletion</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_label_ac_threshold</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>83</x>
-     <y>223</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>288</x>
-     <y>223</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>editor_codeCompletion</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_spinbox_ac_threshold</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>83</x>
-     <y>223</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>412</x>
-     <y>223</y>
-    </hint>
-   </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_ws_checkbox</sender>
    <signal>toggled(bool)</signal>
    <receiver>editor_ws_indent_checkbox</receiver>
@@ -3148,6 +3150,54 @@
    </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>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>83</x>
+     <y>223</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>412</x>
+     <y>223</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>editor_codeCompletion</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>editor_label_ac_threshold</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>83</x>
+     <y>223</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>288</x>
+     <y>223</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
    <sender>cb_widget_custom_style</sender>
    <signal>toggled(bool)</signal>
    <receiver>label_fgtitle</receiver>
@@ -3326,16 +3376,16 @@
   <connection>
    <sender>cb_widget_custom_style</sender>
    <signal>toggled(bool)</signal>
-   <receiver>label_bgtitle_active</receiver>
+   <receiver>label_3d_title</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
      <x>260</x>
-     <y>190</y>
+     <y>186</y>
     </hint>
     <hint type="destinationlabel">
-     <x>525</x>
-     <y>190</y>
+     <x>419</x>
+     <y>236</y>
     </hint>
    </hints>
   </connection>
@@ -3358,16 +3408,16 @@
   <connection>
    <sender>cb_widget_custom_style</sender>
    <signal>toggled(bool)</signal>
-   <receiver>label_3d_title</receiver>
+   <receiver>label_bgtitle_active</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
      <x>260</x>
-     <y>186</y>
+     <y>190</y>
     </hint>
     <hint type="destinationlabel">
-     <x>419</x>
-     <y>236</y>
+     <x>525</x>
+     <y>190</y>
     </hint>
    </hints>
   </connection>
--- a/libgui/src/shortcut-manager.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/shortcut-manager.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -329,6 +329,17 @@
     init (tr ("Move Tab Right"), "editor_tabs:move_tab_right",
           QKeySequence (Qt::AltModifier + Qt::Key_PageDown));
 
+    // Zooming
+    init (tr ("Zoom In"), "editor_view:zoom_in", QKeySequence::ZoomIn);
+    init (tr ("Zoom Out"), "editor_view:zoom_out", QKeySequence::ZoomOut);
+#if defined (Q_OS_MAC)
+    init (tr ("Zoom Normal"), "editor_view:zoom_normal",
+          QKeySequence (ctrl + Qt::Key_Underscore));
+#else
+    init (tr ("Zoom Normal"), "editor_view:zoom_normal",
+          QKeySequence (ctrl + Qt::Key_Period));
+#endif
+
     // actions of the editor
 
     // file
@@ -435,15 +446,6 @@
           QKeySequence ());
     init (tr ("Show Horizontal Scrollbar"), "editor_view:show_hscrollbar",
           QKeySequence ());
-    init (tr ("Zoom In"), "editor_view:zoom_in", QKeySequence::ZoomIn);
-    init (tr ("Zoom Out"), "editor_view:zoom_out", QKeySequence::ZoomOut);
-#if defined (Q_OS_MAC)
-    init (tr ("Zoom Normal"), "editor_view:zoom_normal",
-          QKeySequence (ctrl + Qt::Key_Underscore));
-#else
-    init (tr ("Zoom Normal"), "editor_view:zoom_normal",
-          QKeySequence (ctrl + Qt::Key_Period));
-#endif
 
     // debug
     init (tr ("Toggle Breakpoint"), "editor_debug:toggle_breakpoint",
@@ -467,6 +469,12 @@
     init (tr ("Document on Keyword"), "editor_help:doc_keyword",
           QKeySequence (Qt::SHIFT + Qt::Key_F1));
 
+
+    // Documentation browser
+    init (tr ("Go to Homepage"), "doc_browser:go_home",
+              QKeySequence (Qt::AltModifier + Qt::Key_Home));
+    init (tr ("Go Back one Page"), "doc_browser:go_back", QKeySequence::Back);
+    init (tr ("Go Forward one Page"), "doc_browser:go_next", QKeySequence::Forward);
   }
 
   // write one or all actual shortcut set(s) into a settings file
@@ -509,6 +517,19 @@
       qDebug () << "Key: " << key << " not found in m_action_hash";
   }
 
+  void shortcut_manager::do_shortcut (QShortcut *sc, const QString& key)
+  {
+    int index;
+
+    index = m_action_hash[key] - 1;
+
+    if (index > -1 && index < m_sc.count ())
+      sc->setKey (QKeySequence (m_settings->value ("shortcuts/" + key,
+                                m_sc.at (index).m_default_sc).toString ()));
+    else
+      qDebug () << "Key: " << key << " not found in m_action_hash";
+  }
+
   void shortcut_manager::do_fill_treewidget (QTreeWidget *tree_view)
   {
     m_dialog = nullptr;
@@ -537,6 +558,10 @@
     main_news->setText (0, tr ("News Menu"));
     QTreeWidgetItem *main_tabs = new QTreeWidgetItem (main);
     main_tabs->setText (0, tr ("Tab Handling in Dock Widgets"));
+    QTreeWidgetItem *main_find = new QTreeWidgetItem (main);
+    main_find->setText (0, tr ("Find & Replace in Dock Widgets"));
+    QTreeWidgetItem *main_zoom = new QTreeWidgetItem (main);
+    main_zoom->setText (0, tr ("Zooming in Editor and Documentation"));
 
     m_level_hash["main_file"]   = main_file;
     m_level_hash["main_edit"]   = main_edit;
@@ -546,6 +571,8 @@
     m_level_hash["main_news"]   = main_news;
     m_level_hash["main_tabs"]   = main_tabs;
     m_level_hash["editor_tabs"]   = main_tabs;
+    m_level_hash["editor_find"]   = main_find;
+    m_level_hash["editor_zoom"]   = main_zoom;
 
     QTreeWidgetItem *editor = new QTreeWidgetItem (tree_view);
     editor->setText (0, tr ("Editor"));
@@ -570,6 +597,15 @@
     m_level_hash["editor_run"] = editor_run;
     m_level_hash["editor_help"] = editor_help;
 
+    QTreeWidgetItem *doc = new QTreeWidgetItem (tree_view);
+    doc->setText (0, tr ("Documentation Viewer"));
+    doc->setExpanded (true);
+
+    QTreeWidgetItem *doc_browser = new QTreeWidgetItem (doc);
+    doc_browser->setText (0, tr ("Browser"));
+
+    m_level_hash["doc_browser"] = doc_browser;
+
     connect (tree_view, SIGNAL (itemDoubleClicked (QTreeWidgetItem*, int)),
              this, SLOT (handle_double_clicked (QTreeWidgetItem*, int)));
 
@@ -587,6 +623,18 @@
             if (sc.m_settings_key.contains ("editor_file:close"))
               section = main_tabs;
           }
+        if (section == editor_edit)
+          {
+            // Find & replace now in global file & replace handling section
+            if (sc.m_settings_key.contains ("editor_edit:find"))
+              section = main_find;
+          }
+        if (section == editor_view)
+          {
+            // Zooming now in global zoom handling section
+            if (sc.m_settings_key.contains ("editor_view:zoom"))
+              section = main_zoom;
+          }
 
         QTreeWidgetItem *tree_item = new QTreeWidgetItem (section);
 
@@ -625,16 +673,22 @@
       {
         QString file;
 
+        // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+        int opts = 0;  // No options by default.
+        if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                        true).toBool ())
+          opts = QFileDialog::DontUseNativeDialog;
+
         if (action == OSC_IMPORT)
           file = QFileDialog::getOpenFileName (this,
-                                               tr ("Import shortcuts from file ..."), QString (),
+                                               tr ("Import shortcuts from file..."), QString (),
                                                tr ("Octave Shortcut Files (*.osc);;All Files (*)"),
-                                               nullptr, QFileDialog::DontUseNativeDialog);
+                                               nullptr, QFileDialog::Option (opts));
         else if (action == OSC_EXPORT)
           file = QFileDialog::getSaveFileName (this,
-                                               tr ("Export shortcuts into file ..."), QString (),
+                                               tr ("Export shortcuts to file..."), QString (),
                                                tr ("Octave Shortcut Files (*.osc);;All Files (*)"),
-                                               nullptr, QFileDialog::DontUseNativeDialog);
+                                               nullptr, QFileDialog::Option (opts));
 
         if (file.isEmpty ())
           return false;
@@ -643,7 +697,7 @@
 
         if (! osc_settings)
           {
-            qWarning () << tr ("Failed to open %1 as octave shortcut file")
+            qWarning () << tr ("Failed to open %1 as Octave shortcut file")
                         .arg (file);
             return false;
           }
--- a/libgui/src/shortcut-manager.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/shortcut-manager.h	Thu Dec 20 17:18:56 2018 -0500
@@ -29,6 +29,7 @@
 #include <QKeyEvent>
 #include <QLabel>
 #include <QSettings>
+#include <QShortcut>
 
 namespace octave
 {
@@ -95,6 +96,12 @@
         instance->do_set_shortcut (action, key);
     }
 
+    static void shortcut (QShortcut *sc, const QString& key)
+    {
+      if (instance_ok () && sc)
+        instance->do_shortcut (sc, key);
+    }
+
     static void fill_treewidget (QTreeWidget *tree_view)
     {
       if (instance_ok ())
@@ -127,6 +134,7 @@
     void do_init_data ();
     void do_write_shortcuts (QSettings *settings, bool closing);
     void do_set_shortcut (QAction *action, const QString& key);
+    void do_shortcut (QShortcut *sc, const QString& key);
     void do_fill_treewidget (QTreeWidget *tree_view);
     bool do_import_export (int action);
     void shortcut_dialog (int);
@@ -193,8 +201,4 @@
   };
 }
 
-// FIXME: This is temporary and should be removed when all classes that
-// use the shortcut_manager class are also inside the octave namespace.
-using octave::shortcut_manager;
-
 #endif
--- a/libgui/src/tab-bar.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/tab-bar.h	Thu Dec 20 17:18:56 2018 -0500
@@ -69,8 +69,4 @@
   };
 }
 
-// FIXME: This is temporary and should be removed when all classes that
-// use the tab_bar class are also inside the octave namespace.
-using octave::tab_bar;
-
 #endif
--- a/libgui/src/terminal-dock-widget.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/terminal-dock-widget.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -34,16 +34,17 @@
 
 #include "terminal-dock-widget.h"
 #include "resource-manager.h"
+#include "gui-preferences.h"
 
 namespace octave
 {
   terminal_dock_widget::terminal_dock_widget (QWidget *p)
-    : octave_dock_widget (p), m_terminal (QTerminal::create (p))
+    : octave_dock_widget ("TerminalDockWidget", p),
+      m_terminal (QTerminal::create (p))
   {
     m_terminal->setObjectName ("OctaveTerminal");
     m_terminal->setFocusPolicy (Qt::StrongFocus);
 
-    setObjectName ("TerminalDockWidget");
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
     set_title (tr ("Command Window"));
 
@@ -63,8 +64,9 @@
 
     QFont font = QFont ();
     font.setStyleHint (QFont::TypeWriter);
+    QString default_font = settings->value (global_mono_font.key, global_mono_font.def).toString ();
     font.setFamily
-      (settings->value ("terminal/fontName", "Courier New").toString ());
+      (settings->value (cs_font.key, default_font).toString ());
     font.setPointSize (settings->value ("terminal/fontSize", 10).toInt ());
 
     QFontMetrics metrics(font);
--- a/libgui/src/variable-editor-model.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/variable-editor-model.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -7,14 +7,14 @@
 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.
+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.
+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
@@ -38,6 +38,8 @@
 #include "octave-qt-link.h"
 #include "variable-editor-model.h"
 
+#include "interpreter.h"
+#include "interpreter-private.h"
 #include "ov.h"
 #include "parse.h"
 #include "pr-flt-fmt.h"
@@ -222,17 +224,6 @@
       case Qt::EditRole:
         return edit_display (idx, role);
         return edit_display (idx, role);
-
-#if 0
-      case Qt::StatusTipRole:
-        return elem (idx).m_status_tip;
-
-      case Qt::ToolTipRole:
-        return elem (idx).m_tool_tip;
-
-      case Qt::BackgroundRole:
-        return elem (idx).m_background;
-#endif
       }
 
     // Invalid.
@@ -1020,7 +1011,7 @@
 
     std::string expr = os.str ();
 
-    octave_link::post_event<variable_editor_model, std::string, std::string, QModelIndex>
+    octave_link::post_event
       (this, &variable_editor_model::set_data_oct, nm, expr, idx);
 
     return true;
@@ -1057,7 +1048,7 @@
   {
     // FIXME: cells?
 
-    octave_link::post_event <variable_editor_model, std::string, std::string>
+    octave_link::post_event
       (this, &variable_editor_model::eval_oct, name (),
        QString ("%1 = [ %1(1:%2,:) ; zeros(%3, columns(%1)) ; %1(%2+%3:end,:) ]")
        .arg (QString::fromStdString (name ()))
@@ -1079,7 +1070,7 @@
         return false;
       }
 
-    octave_link::post_event <variable_editor_model, std::string, std::string>
+    octave_link::post_event
       (this, &variable_editor_model::eval_oct, name (),
        QString ("%1(%2:%3, :) = []")
        .arg (QString::fromStdString (name ()))
@@ -1093,7 +1084,7 @@
   bool
   variable_editor_model::insertColumns (int col, int count, const QModelIndex&)
   {
-    octave_link::post_event <variable_editor_model, std::string, std::string>
+    octave_link::post_event
       (this, &variable_editor_model::eval_oct, name (),
        QString ("%1 = [ %1(:,1:%2) ; zeros(rows(%1), %3) %1(:,%2+%3:end) ]")
        .arg (QString::fromStdString (name ()))
@@ -1115,7 +1106,7 @@
         return false;
       }
 
-    octave_link::post_event <variable_editor_model, std::string, std::string>
+    octave_link::post_event
       (this, &variable_editor_model::eval_oct, name (),
        QString ("%1(:, %2:%3) = []")
        .arg (QString::fromStdString (name ()))
@@ -1135,9 +1126,11 @@
 
     try
       {
-        int parse_status = 0;
+        interpreter& interp
+          = __get_interpreter__ ("variable_editor_model::set_data_oct");
 
-        eval_string (expr, true, parse_status);
+        int parse_status = 0;
+        interp.eval_string (expr, true, parse_status);
 
         octave_value val = retrieve_variable (name);
 
@@ -1184,9 +1177,11 @@
 
     try
       {
-        int parse_status = 0;
+        interpreter& interp
+          = __get_interpreter__ ("variable_editor_model::eval_oct");
 
-        eval_string (expr, true, parse_status);
+        int parse_status = 0;
+        interp.eval_string (expr, true, parse_status);
 
         init_from_oct (name);
       }
@@ -1218,9 +1213,11 @@
 
     if (symbol_exist (name, "var") > 0)
       {
-        int parse_status = 0;
+        interpreter& interp
+          = __get_interpreter__ ("variable_editor_model::retrieve_variable");
 
-        return eval_string (x, true, parse_status);
+        int parse_status = 0;
+        return interp.eval_string (x, true, parse_status);
       }
 
     return octave_value ();
--- a/libgui/src/variable-editor-model.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/variable-editor-model.h	Thu Dec 20 17:18:56 2018 -0500
@@ -7,14 +7,14 @@
 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.
+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.
+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
--- a/libgui/src/variable-editor.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/variable-editor.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -7,14 +7,14 @@
 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.
+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.
+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
@@ -47,10 +47,12 @@
 #include <QToolButton>
 #include <QVBoxLayout>
 
+#include "dw-main-window.h"
 #include "resource-manager.h"
 #include "shortcut-manager.h"
 #include "variable-editor.h"
 #include "variable-editor-model.h"
+#include "gui-preferences.h"
 
 // Code reuse functions
 
@@ -86,6 +88,11 @@
 
   variable_dock_widget::variable_dock_widget (QWidget *p)
     : label_dock_widget (p)
+// See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
+      , m_waiting_for_mouse_move (false)
+      , m_waiting_for_mouse_button_release (false)
+#endif
   {
     setFocusPolicy (Qt::StrongFocus);
     setAttribute (Qt::WA_DeleteOnClose);
@@ -109,28 +116,25 @@
     m_prev_floating = false;
     m_prev_geom = QRect (0, 0, 0, 0);
 
-    QHBoxLayout *h_layout = findChild<QHBoxLayout *> ();
-    if (h_layout != nullptr && titleBarWidget () != nullptr)
-      {
-        m_fullscreen_action = new QAction
-          (resource_manager::icon ("view-fullscreen", false), "", this);
-        m_fullscreen_action->setToolTip (tr (DOCKED_FULLSCREEN_BUTTON_TOOLTIP));
-        QToolButton *fullscreen_button = new QToolButton (titleBarWidget ());
-        fullscreen_button->setDefaultAction (m_fullscreen_action);
-        fullscreen_button->setFocusPolicy (Qt::NoFocus);
-        fullscreen_button->setIconSize (QSize (m_icon_size,m_icon_size));
-        QString css_button = QString ("QToolButton {background: transparent; border: 0px;}");
-        fullscreen_button->setStyleSheet (css_button);
+    QHBoxLayout *h_layout = m_title_widget->findChild<QHBoxLayout *> ();
+    m_fullscreen_action = new QAction
+      (resource_manager::icon ("view-fullscreen", false), "", this);
+    m_fullscreen_action->setToolTip (tr (DOCKED_FULLSCREEN_BUTTON_TOOLTIP));
+    QToolButton *fullscreen_button = new QToolButton (m_title_widget);
+    fullscreen_button->setDefaultAction (m_fullscreen_action);
+    fullscreen_button->setFocusPolicy (Qt::NoFocus);
+    fullscreen_button->setIconSize (QSize (m_icon_size,m_icon_size));
+    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, SIGNAL (triggered ()),
+             this, SLOT (change_fullscreen ()));
 
-        int index = -1;
-        QToolButton *first = titleBarWidget ()->findChild<QToolButton *> ();
-        if (first != nullptr)
-          index = h_layout->indexOf (first);
-        h_layout->insertWidget (index, fullscreen_button);
-      }
+    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
@@ -176,15 +180,26 @@
         m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock.png"));
         m_dock_action->setToolTip (tr ("Dock widget"));
 
-        activateWindow();
-        setFocus (Qt::OtherFocusReason);
+        activateWindow ();
+        setFocus ();
+
+// See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
+        m_waiting_for_mouse_move = true;
+#endif
       }
     else
       {
         m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock.png"));
         m_dock_action->setToolTip (tr ("Undock widget"));
 
-        setFocus (Qt::OtherFocusReason);
+        setFocus ();
+
+// See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
+        m_waiting_for_mouse_move = false;
+        m_waiting_for_mouse_button_release = false;
+#endif
       }
   }
 
@@ -195,8 +210,6 @@
     if (! m_full_screen)
       {
         m_prev_floating = isFloating ();
-        m_prev_geom = geometry ();
-
         m_fullscreen_action->setIcon (resource_manager::icon ("view-restore", false));
         if (m_prev_floating)
           m_fullscreen_action->setToolTip (tr ("Restore geometry"));
@@ -205,6 +218,7 @@
             m_fullscreen_action->setToolTip (tr ("Redock"));
             setFloating (true);
           }
+        m_prev_geom = geometry ();
 
         // showFullscreen() and setWindowState() only work for QWindow objects.
         QScreen *pscreen = QGuiApplication::primaryScreen ();
@@ -244,23 +258,35 @@
   {
     octave_unused_parameter (now);
 
-    // The is a proxied test
+    // This is a proxied test
     if (hasFocus ())
       {
-        QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
-        if (label != nullptr)
+        if (old == this)
+          return;
+
+        if (titleBarWidget () != nullptr)
           {
-            label->setBackgroundRole (QPalette::Highlight);
-            label->setAutoFillBackground (true);
+            QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
+            if (label != nullptr)
+              {
+                label->setBackgroundRole (QPalette::Highlight);
+                label->setStyleSheet ("background-color: palette(highlight); color: palette(highlightedText);");
+              }
           }
 
         emit variable_focused_signal (objectName ());
       }
     else if (old == focusWidget())
       {
-        QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
-        if (label != NULL)
-          label->setBackgroundRole (QPalette::NoRole);
+        if (titleBarWidget () != nullptr)
+          {
+            QLabel *label = titleBarWidget ()->findChild<QLabel *> ();
+            if (label != nullptr)
+              {
+                label->setBackgroundRole (QPalette::NoRole);
+                label->setStyleSheet (";");
+              }
+          }
       }
   }
 
@@ -270,6 +296,69 @@
       m_frame->resize (size ());
   }
 
+// See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
+
+  bool
+  variable_dock_widget::event (QEvent *event)
+  {
+    // low-level check of whether docked-widget became a window via
+    // via drag-and-drop
+    if (event->type () == QEvent::MouseButtonPress)
+      {
+        m_waiting_for_mouse_move = false;
+        m_waiting_for_mouse_button_release = false;
+      }
+    if (event->type () == QEvent::MouseMove && m_waiting_for_mouse_move)
+      {
+        m_waiting_for_mouse_move = false;
+        m_waiting_for_mouse_button_release = true;
+      }
+    if (event->type () == QEvent::MouseButtonRelease && m_waiting_for_mouse_button_release)
+      {
+        m_waiting_for_mouse_button_release = false;
+        bool retval = QDockWidget::event (event);
+        if (isFloating ())
+          emit queue_unfloat_float ();
+        return retval;
+      }
+
+    return QDockWidget::event (event);
+  }
+
+  void
+  variable_dock_widget::unfloat_float (void)
+  {
+    hide ();
+    setFloating (false);
+    // Avoid a Ubunty Unity issue by queuing this rather than direct.
+    emit queue_float ();
+    m_waiting_for_mouse_move = false;
+    m_waiting_for_mouse_button_release = false;
+  }
+
+  void
+  variable_dock_widget::refloat (void)
+  {
+    setFloating (true);
+    m_waiting_for_mouse_move = false;
+    m_waiting_for_mouse_button_release = false;
+    show ();
+    activateWindow ();
+    setFocus ();
+  }
+
+#else
+
+  void
+  variable_dock_widget::unfloat_float (void)
+  {}
+
+  void
+  variable_dock_widget::refloat (void)
+  {}
+
+#endif
 
   // Variable editor stack
 
@@ -355,14 +444,19 @@
     if (! hasFocus ())
       return;
 
+    // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
+    int opts = 0;  // No options by default.
+    if (! resource_manager::get_settings ()->value ("use_native_file_dialogs",
+                                                    true).toBool ())
+      opts = QFileDialog::DontUseNativeDialog;
+
     QString name = objectName ();
     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),
-                                      0, 0,
-                                      QFileDialog::DontUseNativeDialog);
+                                      0, 0, QFileDialog::Option (opts));
 
     // FIXME: Type? binary, float-binary, ascii, text, hdf5, matlab format?
     // FIXME: Call octave_value::save_* directly?
@@ -495,12 +589,6 @@
                      tr ("Paste"),
                      this, SLOT (pasteClipboard ()));
 
-    // FIXME: Different icon for Paste Table?
-
-    menu->addAction (resource_manager::icon ("edit-paste"),
-                     tr ("Paste Table"),
-                     this, SLOT (pasteTableClipboard ()));
-
     menu->addSeparator ();
 
     menu->addAction (resource_manager::icon ("edit-delete"),
@@ -771,38 +859,6 @@
     QClipboard *clipboard = QApplication::clipboard ();
     QString text = clipboard->text ();
 
-    if (indices.isEmpty ())
-      {
-        if (size () == QSize (1,1))
-          mod->setData (mod->index (0,0), text.toDouble ());
-        else if (size () == QSize (0,0))
-          {
-            mod->insertColumn (0);
-            mod->insertRow (0);
-            mod->setData (mod->index (0,0), text.toDouble ());
-          }
-      }
-    else
-      {
-        QStringList cells = text.split(QRegExp("\n|\r\n|\r"));
-        int clen = cells.size ();
-        for (int i = 0; i < indices.size (); i++)
-          mod->setData (indices[i], cells.at (i % clen).toDouble ());
-      }
-  }
-
-  void variable_editor_view::pasteTableClipboard (void)
-  {
-    if (! hasFocus ())
-      return;
-
-    QAbstractItemModel *mod = model ();
-    QItemSelectionModel *sel = selectionModel ();
-    QList<QModelIndex> indices = sel->selectedIndexes ();
-
-    QClipboard *clipboard = QApplication::clipboard ();
-    QString text = clipboard->text ();
-
     QPoint start, end;
 
     QPoint tabsize = QPoint (mod->rowCount (), mod->columnCount ());
@@ -927,8 +983,7 @@
   {
     if (ev->type () == QEvent::HoverEnter)
       emit hovered_signal ();
-    else if (ev->type () == QEvent::MouseButtonPress
-             || ev->type () == QEvent::MouseButtonPress)
+    else if (ev->type () == QEvent::MouseButtonPress)
       emit popup_shown_signal ();
 
     return QToolButton::eventFilter (obj, ev);
@@ -977,8 +1032,8 @@
   // Variable editor.
 
   variable_editor::variable_editor (QWidget *p)
-    : octave_dock_widget (p),
-      m_main (new QMainWindow ()),
+    : octave_dock_widget ("VariableEditor", p),
+      m_main (new dw_main_window ()),
       m_tool_bar (new QToolBar (m_main)),
       m_default_width (30),
       m_default_height (100),
@@ -991,9 +1046,9 @@
       m_table_colors (),
       m_current_focus_vname (""),
       m_hovered_focus_vname (""),
-      m_variable_focus_widget (nullptr)
+      m_focus_widget (nullptr),
+      m_focus_widget_vdw (nullptr)
   {
-    setObjectName ("VariableEditor");
     set_title (tr ("Variable Editor"));
     setStatusTip (tr ("Edit variables."));
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
@@ -1040,19 +1095,33 @@
     octave_dock_widget::focusInEvent (ev);
 
     // set focus to the current variable or most recent if still valid
-    QWidget *fw = m_main->focusWidget ();
-    if (fw != nullptr)
-      fw->setFocus ();
-    else if (m_main->isAncestorOf (m_variable_focus_widget))
-      m_variable_focus_widget->setFocus ();
-  }
-
-  void variable_editor::focusOutEvent (QFocusEvent *ev)
-  {
-    // focusWidget() appears lost in transition to/from main window
-    m_variable_focus_widget = m_main->focusWidget ();
-
-    octave_dock_widget::focusOutEvent (ev);
+    if (m_focus_widget != nullptr)
+      {
+        // Activating a floating window causes problems.
+        if (! m_focus_widget_vdw->isFloating ())
+            activateWindow ();
+        m_focus_widget->setFocus ();
+      }
+    else
+      {
+        QWidget *fw = m_main->focusWidget ();
+        if (fw != nullptr)
+          {
+            activateWindow ();
+            fw->setFocus ();
+          }
+        else
+          {
+            QDockWidget *any_qdw = m_main->findChild<QDockWidget *> ();
+            if (any_qdw != nullptr)
+              {
+                activateWindow ();
+                any_qdw->setFocus ();
+              }
+            else
+              setFocus();
+          }
+      }
   }
 
   // Add an action to a menu or the widget itself.
@@ -1120,6 +1189,13 @@
              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
+#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);
+#endif
 
     variable_editor_stack *stack = new variable_editor_stack (page);
     stack->setObjectName (name);
@@ -1154,8 +1230,6 @@
              edit_view, SLOT (copyClipboard ()));
     connect (this, SIGNAL (paste_clipboard_signal ()),
              edit_view, SLOT (pasteClipboard ()));
-    connect (this, SIGNAL (paste_table_clipboard_signal ()),
-             edit_view, SLOT (pasteTableClipboard ()));
     connect (this, SIGNAL (selected_command_signal (const QString&)),
              edit_view, SLOT (selected_command_requested (const QString&)));
     connect (edit_view->horizontalHeader (),
@@ -1192,10 +1266,13 @@
     // to always supply a QLabl (initially empty) and then simply update its
     // contents.
     page->set_title (name);
-    QLabel *existing_ql = page->titleBarWidget ()->findChild<QLabel *> ();
-    connect (model, SIGNAL (update_label_signal (const QString&)),
-             existing_ql, SLOT (setText (const QString&)));
-    existing_ql->setMargin (2);
+    if (page->titleBarWidget () != nullptr)
+      {
+        QLabel *existing_ql = page->titleBarWidget ()->findChild<QLabel *> ();
+        connect (model, SIGNAL (update_label_signal (const QString&)),
+                 existing_ql, SLOT (setText (const QString&)));
+        existing_ql->setMargin (2);
+      }
 
     model->update_data (val);
 
@@ -1272,7 +1349,7 @@
   void
   variable_editor::notice_settings (const QSettings *settings)
   {
-    // FIXME: Why use object->tostring->toint?  Why not just 100?
+    m_main->notice_settings (settings); // update settings in parent main win
 
     m_default_width = settings->value ("variable_editor/column_width",
                                        100).toInt ();
@@ -1292,18 +1369,17 @@
 
     QString font_name;
     int font_size;
+    QString default_font = settings->value (global_mono_font.key,
+                                            global_mono_font.def).toString ();
 
     if (m_use_terminal_font)
       {
-        font_name = settings->value ("terminal/fontName", "Courier New").toString ();
+        font_name = settings->value (cs_font.key, default_font).toString ();
         font_size = settings->value ("terminal/fontSize", 10).toInt ();
       }
     else
       {
-        font_name = settings->value ("variable_editor/font_name",
-                                     settings->value ("terminal/fontName",
-                                                      "Courier New")).toString ();
-
+        font_name = settings->value (ve_font.key, default_font).toString ();
         font_size = settings->value ("variable_editor/font_size", 10).toInt ();
       }
 
@@ -1333,17 +1409,12 @@
 
     // Icon size in the toolbar.
 
-    int icon_size_settings = settings->value ("toolbar_icon_size", 0).toInt ();
-    QStyle *st = style ();
-    int icon_size = st->pixelMetric (QStyle::PM_ToolBarIconSize);
-
-    // FIXME: Magic numbers.  Use enum?
+    int size_idx = settings->value (global_icon_size.key,
+                                    global_icon_size.def).toInt ();
+    size_idx = (size_idx > 0) - (size_idx < 0) + 1;  // Make valid index from 0 to 2
 
-    if (icon_size_settings == 1)
-      icon_size = st->pixelMetric (QStyle::PM_LargeIconSize);
-    else if (icon_size_settings == -1)
-      icon_size = st->pixelMetric (QStyle::PM_SmallIconSize);
-
+    QStyle *st = style ();
+    int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
     m_tool_bar->setIconSize (QSize (icon_size, icon_size));
   }
 
@@ -1356,17 +1427,49 @@
   }
 
   void
-  variable_editor::variable_destroyed (QObject *)
+  variable_editor::variable_destroyed (QObject *obj)
   {
+    // Invalidate the focus-restoring widget pointer if currently active.
+    if (m_focus_widget_vdw == obj)
+      {
+        m_focus_widget = nullptr;
+        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);
+
+    QFocusEvent ev (QEvent::FocusIn);
+    focusInEvent (&ev);
   }
 
   void
   variable_editor::variable_focused (const QString &name)
   {
     m_current_focus_vname = name;
+
+    // focusWidget() appears lost in transition to/from main window
+    // so keep a record of the widget.
+
+    QWidget *current = QApplication::focusWidget ();
+    m_focus_widget = nullptr;
+    m_focus_widget_vdw = nullptr;
+    if (current != nullptr)
+      {
+        QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
+        for (int i = 0; i < vdwlist.size (); i++)
+          {
+            variable_dock_widget *vdw = vdwlist.at (i);
+            if (vdw->isAncestorOf (current))
+              {
+                m_focus_widget = current;
+                m_focus_widget_vdw = vdw;
+                break;
+              }
+          }
+      }
   }
 
   void
@@ -1421,14 +1524,6 @@
   }
 
   void
-  variable_editor::pasteTableClipboard (void)
-  {
-    emit paste_table_clipboard_signal ();
-
-    emit updated ();
-  }
-
-  void
   variable_editor::levelUp (void)
   {
     emit level_up_signal ();
@@ -1535,13 +1630,6 @@
                                   tr ("Paste"), this, SLOT (pasteClipboard ()));
     action->setStatusTip(tr("Paste clipboard into variable data"));
 
-    // FIXME: Different icon for Paste Table?
-
-    action = add_tool_bar_button (resource_manager::icon ("edit-paste"),
-                                  tr ("Paste Table"),
-                                  this, SLOT (pasteTableClipboard ()));
-    action->setStatusTip(tr("Another paste clipboard into variable data"));
-
     m_tool_bar->addSeparator ();
 
     // FIXME: Add a print item?
--- a/libgui/src/variable-editor.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/variable-editor.h	Thu Dec 20 17:18:56 2018 -0500
@@ -7,14 +7,14 @@
 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.
+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.
+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
@@ -32,6 +32,8 @@
 
 #include "octave-dock-widget.h"
 #include "tab-bar.h"
+#include "dw-main-window.h"
+
 
 class octave_value;
 
@@ -44,6 +46,7 @@
   class variable_editor_model;
   class variable_editor_view;
 
+
   // The individual variable subwindow class
 
   class variable_dock_widget : public label_dock_widget
@@ -93,6 +96,32 @@
     QRect m_prev_geom;
 
 #endif
+
+// See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+#define QTBUG_44813_FIX_VERSION 0x999999
+  signals:
+
+    void queue_unfloat_float (void);
+
+    void queue_float (void);
+
+  protected slots:
+
+    void unfloat_float (void);
+
+    void refloat (void);
+
+#if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
+  protected:
+
+    bool event (QEvent *event);
+
+  private:
+
+    bool m_waiting_for_mouse_move;
+
+    bool m_waiting_for_mouse_button_release;
+#endif
   };
 
   class variable_editor_stack : public QStackedWidget
@@ -165,8 +194,6 @@
 
     void pasteClipboard (void);
 
-    void pasteTableClipboard (void);
-
     void handle_horizontal_scroll_action (int action);
 
     void handle_vertical_scroll_action (int action);
@@ -300,8 +327,6 @@
 
     void pasteClipboard (void);
 
-    void pasteTableClipboard (void);
-
     void levelUp (void);
 
     // Send command to Octave interpreter.
@@ -324,8 +349,6 @@
 
     void paste_clipboard_signal (void);
 
-    void paste_table_clipboard_signal (void);
-
     void level_up_signal (void);
 
     void save_signal (void);
@@ -338,14 +361,12 @@
 
     void focusInEvent (QFocusEvent *ev);
 
-    void focusOutEvent (QFocusEvent *ev);
-
   private:
 
     QAction * add_action (QMenu *menu, const QIcon& icon, const QString& text,
                           const char *member);
 
-    QMainWindow *m_main;
+    dw_main_window *m_main;
 
     QToolBar *m_tool_bar;
 
@@ -380,7 +401,9 @@
 
     QString m_hovered_focus_vname;
 
-    QWidget *m_variable_focus_widget;
+    QWidget *m_focus_widget;
+
+    variable_dock_widget *m_focus_widget_vdw;
   };
 }
 
--- a/libgui/src/workspace-model.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/workspace-model.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,13 +25,16 @@
 #  include "config.h"
 #endif
 
+#include <iostream>
+
 #include <QTreeWidget>
 #include <QSettings>
 
-#include "symscope.h"
+#include "syminfo.h"
 #include "utils.h"
 
 #include "resource-manager.h"
+#include "gui-preferences.h"
 #include "workspace-model.h"
 
 namespace octave
@@ -131,7 +134,7 @@
 
     if (idx.isValid ())
       {
-        if (role == Qt::BackgroundColorRole)
+        if (role == Qt::BackgroundColorRole && m_enable_colors)
           {
             QString class_chars = resource_manager::storage_class_chars ();
             int actual_class
@@ -230,12 +233,12 @@
 
   void
   workspace_model::set_workspace (bool top_level, bool /* debug */,
-                                  const symbol_scope& scope)
+                                  const symbol_info_list& syminfo)
   {
     clear_data ();
 
     m_top_level = top_level;
-    m_scope = scope;
+    m_syminfo_list = syminfo;
 
     update_table ();
   }
@@ -254,6 +257,9 @@
       resource_manager::storage_class_default_colors ();
     QString class_chars = resource_manager::storage_class_chars ();
 
+    m_enable_colors =
+        settings->value (ws_enable_colors.key, ws_enable_colors.key).toBool ();
+
     for (int i = 0; i < class_chars.length (); i++)
       {
         QVariant default_var = default_colors.at (i);
@@ -268,7 +274,7 @@
   workspace_model::clear_data (void)
   {
     m_top_level = false;
-    m_scope = symbol_scope ();
+    m_syminfo_list = symbol_info_list ();
     m_scopes = QString ();
     m_symbols = QStringList ();
     m_class_names = QStringList ();
@@ -282,37 +288,27 @@
   {
     beginResetModel ();
 
-    std::list<symbol_record> sr_list = m_scope.all_variables ();
-
-    symbol_record::context_id context = m_scope.current_context ();
-
-    for (const auto& sr : sr_list)
+    for (const auto& syminfo : m_syminfo_list)
       {
-        std::string nm = sr.name ();
-
-        octave_value val = sr.varval (context);
+        std::string nm = syminfo.name ();
 
-        // FIXME: fix size for objects, see kluge in variables.cc
-        //dim_vector dv = val.dims ();
-        octave_value tmp = val;
-        Matrix sz = tmp.size ();
+        octave_value val = syminfo.value ();
+
+        // FIXME: fix size for objects, see kluge in ov.cc
+        Matrix sz = val.size ();
         dim_vector dv = dim_vector::alloc (sz.numel ());
         for (octave_idx_type i = 0; i < dv.ndims (); i++)
           dv(i) = sz(i);
 
         char storage = ' ';
-        if (sr.is_global ())
+        if (syminfo.is_global ())
           storage = 'g';
-        else if (sr.is_persistent ())
+        else if (syminfo.is_persistent ())
           storage = 'p';
-        else if (sr.is_automatic ())
+        else if (syminfo.is_automatic ())
           storage = 'a';
-        else if (sr.is_formal ())
+        else if (syminfo.is_formal ())
           storage = 'f';
-        else if (sr.is_hidden ())
-          storage = 'h';
-        else if (sr.is_inherited ())
-          storage = 'i';
 
         std::ostringstream buf;
         val.short_disp (buf);
--- a/libgui/src/workspace-model.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/workspace-model.h	Thu Dec 20 17:18:56 2018 -0500
@@ -33,7 +33,7 @@
 #include <QColor>
 #include <QSettings>
 
-#include "symscope.h"
+#include "syminfo.h"
 
 // Defined for purposes of sending QList<int> as part of signal.
 typedef QList<int> QIntList;
@@ -76,12 +76,12 @@
       return m_storage_class_colors.at (s_class);
     }
 
-    symbol_scope scope (void) const { return m_scope; }
+    symbol_info_list get_symbol_info (void) const { return m_syminfo_list; }
 
   public slots:
 
     void set_workspace (bool top_level, bool debug,
-                        const symbol_scope& scope);
+                        const symbol_info_list& syminfo);
 
     void clear_workspace (void);
 
@@ -100,7 +100,7 @@
     void update_table (void);
 
     bool m_top_level;
-    symbol_scope m_scope;
+    symbol_info_list m_syminfo_list;
     QString m_scopes;
     QStringList m_symbols;
     QStringList m_class_names;
@@ -111,6 +111,7 @@
     QStringList m_columnNames;
 
     QList<QColor>  m_storage_class_colors;
+    bool m_enable_colors;
 
   };
 }
--- a/libgui/src/workspace-view.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/workspace-view.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -39,18 +39,18 @@
 #include <QCompleter>
 #include <QSignalMapper>
 
+#include "gui-preferences.h"
 #include "workspace-view.h"
 #include "resource-manager.h"
 
 #include "interpreter-private.h"
-#include "symscope.h"
+#include "syminfo.h"
 
 namespace octave
 {
   workspace_view::workspace_view (QWidget *p)
-    : octave_dock_widget (p), m_view (new QTableView (this))
+    : octave_dock_widget ("WorkspaceView", p), m_view (new QTableView (this))
   {
-    setObjectName ("WorkspaceView");
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
     set_title (tr ("Workspace"));
     setStatusTip (tr ("View the variables in the active workspace."));
@@ -193,7 +193,8 @@
 
     QString tool_tip;
 
-    if (! settings->value ("workspaceview/hide_tool_tips",false).toBool ())
+    if (settings->value (ws_enable_colors.key, ws_enable_colors.def).toBool ()
+        && ! settings->value (ws_hide_tool_tips.key, ws_hide_tool_tips.def).toBool ())
       {
         tool_tip  = QString (tr ("View the variables in the active workspace.<br>"));
         tool_tip += QString (tr ("Colors for variable attributes:"));
@@ -257,13 +258,6 @@
   }
 
   void
-  workspace_view::closeEvent (QCloseEvent *e)
-  {
-    emit active_changed (false);
-    QDockWidget::closeEvent (e);
-  }
-
-  void
   workspace_view::filter_update (const QString& expression)
   {
     m_filter_model.setFilterWildcard (expression);
@@ -469,11 +463,9 @@
       {
         QString var_name = get_var_name (index);
 
-        symbol_scope scope = m_model->scope ();
+        symbol_info_list syminfo = m_model->get_symbol_info ();
 
-        octave_value val;
-        if (scope)
-          val = scope.varval (var_name.toStdString ());
+        octave_value val = syminfo.varval (var_name.toStdString ());
 
         emit edit_variable_signal (var_name, val);
       }
--- a/libgui/src/workspace-view.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libgui/src/workspace-view.h	Thu Dec 20 17:18:56 2018 -0500
@@ -67,10 +67,6 @@
 
     void edit_variable_signal (const QString&, const octave_value&);
 
-  protected:
-
-    void closeEvent (QCloseEvent *event);
-
   protected slots:
 
     void filter_update (const QString& expression);
--- a/libinterp/build-env.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/build-env.h	Thu Dec 20 17:18:56 2018 -0500
@@ -150,10 +150,10 @@
     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 *SED;
     extern const char *SHARED_LIBS;
     extern const char *SH_LD;
     extern const char *SH_LDFLAGS;
--- a/libinterp/build-env.in.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/build-env.in.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -265,14 +265,14 @@
 
     const char *QT_LIBS = %OCTAVE_CONF_QT_LIBS%;
 
+    const char *QT_OPENGL_LIBS = %OCTAVE_CONF_QT_OPENGL_LIBS%;
+
     const char *RANLIB = %OCTAVE_CONF_RANLIB%;
 
     const char *RDYNAMIC_FLAG = %OCTAVE_CONF_RDYNAMIC_FLAG%;
 
     const char *READLINE_LIBS = %OCTAVE_CONF_READLINE_LIBS%;
 
-    const char *SED = %OCTAVE_CONF_SED%;
-
     const char *SHARED_LIBS = %OCTAVE_CONF_SHARED_LIBS%;
 
     const char *SH_LD = %OCTAVE_CONF_SH_LD%;
--- a/libinterp/corefcn/__dsearchn__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/__dsearchn__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,8 +26,6 @@
 
 #include <cmath>
 
-#include <iostream>
-#include <fstream>
 #include <string>
 
 #include "defun.h"
@@ -82,7 +80,7 @@
           if (d < d0)
             {
               d0 = d;
-              *pidx = static_cast<double>(j + 1);
+              *pidx = static_cast<double> (j + 1);
             }
           octave_quit ();
         }
--- a/libinterp/corefcn/__magick_read__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/__magick_read__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -877,7 +877,8 @@
         if (nRows != imvec[frameidx(frame)].rows ()
             || nCols != imvec[frameidx(frame)].columns ())
           {
-            error ("imread: all frames must have the same size but frame %i is different",
+            error ("imread: all frames must have the same size but frame "
+                   "%" OCTAVE_IDX_TYPE_FORMAT " is different",
                    frameidx(frame) +1);
           }
       }
@@ -910,8 +911,8 @@
       else if (depth <= 32)
         output = read_images<FloatNDArray>  (imvec, frameidx, nargout, options);
       else
-        error ("imread: reading of images with %i-bit depth is not supported",
-               depth);
+        error ("imread: reading of images with %" OCTAVE_IDX_TYPE_FORMAT
+               "-bit depth is not supported", depth);
     }
 
   return output;
@@ -1161,7 +1162,7 @@
   // From GM documentation:
   //  Color arguments are must be scaled to fit the Quantum size according to
   //  the range of MaxRGB
-  const double divisor = static_cast<double>((uint64_t (1) << bitdepth) - 1)
+  const double divisor = static_cast<double> ((uint64_t (1) << bitdepth) - 1)
                          / MaxRGB;
 
   const P *img_fvec = img.fortran_vec ();
--- a/libinterp/corefcn/base-text-renderer.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/base-text-renderer.h	Thu Dec 20 17:18:56 2018 -0500
@@ -32,8 +32,8 @@
 #include "dMatrix.h"
 #include "uint8NDArray.h"
 
+#include "text-engine.h"
 #include "text-renderer.h"
-#include "txt-eng.h"
 
 namespace octave
 {
--- a/libinterp/corefcn/bitfcns.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/bitfcns.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -660,13 +660,27 @@
 @deftypefn  {} {} flintmax ()
 @deftypefnx {} {} flintmax ("double")
 @deftypefnx {} {} flintmax ("single")
+@deftypefnx {} {} flintmax (@var{var})
 Return the largest integer that can be represented consecutively in a
 floating point value.
 
-The default class is @qcode{"double"}, but @qcode{"single"} is a valid
-option.  On IEEE 754 compatible systems, @code{flintmax} is
-@w{@math{2^{53}}} for @qcode{"double"} and @w{@math{2^{24}}} for
-@qcode{"single"}.
+The input is either a string specifying a floating point type, or it is an
+existing floating point variable @var{var}.
+
+The default type is @qcode{"double"}, but @qcode{"single"} is a valid option.
+On IEEE 754 compatible systems, @code{flintmax} is @w{@math{2^{53}}} for
+@qcode{"double"} and @w{@math{2^{24}}} for @qcode{"single"}.
+
+Example Code - query an existing variable
+
+@example
+@group
+x = single (1);
+flintmax (x)
+  @result{} 16777216
+@end group
+@end example
+
 @seealso{intmax, realmax, realmin}
 @end deftypefn */)
 {
@@ -677,7 +691,14 @@
 
   std::string cname = "double";
   if (nargin == 1)
-    cname = args(0).xstring_value ("flintmax: argument must be a string");
+    {
+      if (args(0).is_string ())
+        cname = args(0).string_value ();
+      else if (args(0).isfloat ())
+        cname = args(0).class_name ();
+      else
+        error ("intmin: argument must be a string or floating point variable");
+    }
 
   if (cname == "double")
     return ovl (static_cast<double> (max_mantissa_value<double> () + 1));
@@ -692,19 +713,27 @@
 %!assert (flintmax ("double"), 2^53)
 %!assert (flintmax ("single"), single (2^24))
 
-%!error flintmax (0)
+%!test
+%! x = single (1);
+%! assert (flintmax (x), single (16777216));
+
 %!error flintmax ("double", 0)
-%!error flintmax ("int32")
-%!error flintmax ("char")
+%!error <must be a string or floating point variable> flintmax (int8 (1))
+%!error <not defined for class 'int8'> flintmax ("int8")
+%!error <not defined for class 'char'> flintmax ("char")
 */
 
 DEFUN (intmax, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} intmax ()
 @deftypefnx {} {} intmax ("@var{type}")
-Return the largest integer that can be represented in an integer type.
+@deftypefnx {} {} intmax (@var{var})
+Return the largest integer that can be represented by a specific integer type.
 
-The variable @var{type} is a string which can be
+The input is either a string @qcode{"@var{type}"} specifying an integer type,
+or it is an existing integer variable @var{var}.
+
+Possible values for @var{type} are
 
 @table @asis
 @item @qcode{"int8"}
@@ -733,6 +762,17 @@
 @end table
 
 The default for @var{type} is @qcode{"int32"}.
+
+Example Code - query an existing variable
+
+@example
+@group
+x = int8 (1);
+intmax (x)
+  @result{} 127
+@end group
+@end example
+
 @seealso{intmin, flintmax}
 @end deftypefn */)
 {
@@ -743,7 +783,14 @@
 
   std::string cname = "int32";
   if (nargin == 1)
-    cname = args(0).xstring_value ("intmax: argument must be a string");
+    {
+      if (args(0).is_string ())
+        cname = args(0).string_value ();
+      else if (args(0).isinteger ())
+        cname = args(0).class_name ();
+      else
+        error ("intmax: argument must be a string or integer variable");
+    }
 
   octave_value retval;
 
@@ -780,19 +827,27 @@
 %!assert (intmax ("int64"),   int64 (2^63 - 1))
 %!assert (intmax ("uint64"), uint64 (2^64 - 1))
 
-%!error intmax (0)
+%!test
+%! x = int8 (1);
+%! assert (intmax (x), int8 (127));
+
 %!error intmax ("int32", 0)
-%!error intmax ("double")
-%!error intmax ("char")
+%!error <must be a string or integer variable> intmax (1.0)
+%!error <not defined for 'double' objects> intmax ("double")
+%!error <not defined for 'char' objects> intmax ("char")
 */
 
 DEFUN (intmin, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} intmin ()
 @deftypefnx {} {} intmin ("@var{type}")
-Return the smallest integer that can be represented in an integer type.
+@deftypefnx {} {} intmin (@var{var})
+Return the smallest integer that can be represented by a specific integer type.
 
-The variable @var{type} is a string which can be
+The input is either a string @qcode{"@var{type}"} specifying an integer type,
+or it is an existing integer variable @var{var}.
+
+Possible values for @var{type} are
 
 @table @asis
 @item @qcode{"int8"}
@@ -821,6 +876,17 @@
 @end table
 
 The default for @var{type} is @qcode{"int32"}.
+
+Example Code - query an existing variable
+
+@example
+@group
+x = int8 (1);
+intmin (x)
+  @result{} -128
+@end group
+@end example
+
 @seealso{intmax, flintmax}
 @end deftypefn */)
 {
@@ -831,7 +897,14 @@
 
   std::string cname = "int32";
   if (nargin == 1)
-    cname = args(0).xstring_value ("intmin: argument must be a string");
+    {
+      if (args(0).is_string ())
+        cname = args(0).string_value ();
+      else if (args(0).isinteger ())
+        cname = args(0).class_name ();
+      else
+        error ("intmin: argument must be a string or integer variable");
+    }
 
   octave_value retval;
 
@@ -868,10 +941,14 @@
 %!assert (intmin ("int64"),   int64 (-2^63))
 %!assert (intmin ("uint64"), uint64 (-2^64))
 
-%!error intmin (0)
+%!test
+%! x = int8 (1);
+%! assert (intmin (x), int8 (-128));
+
 %!error intmin ("int32", 0)
-%!error intmin ("double")
-%!error intmin ("char")
+%!error <must be a string or integer variable> intmin (1.0)
+%!error <not defined for 'double' objects> intmin ("double")
+%!error <not defined for 'char' objects> intmin ("char")
 */
 
 DEFUN (sizemax, args, ,
--- a/libinterp/corefcn/c-file-ptr-stream.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/c-file-ptr-stream.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <iomanip>
 
 #include "filepos-wrappers.h"
 
--- a/libinterp/corefcn/c-file-ptr-stream.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/c-file-ptr-stream.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,9 +26,7 @@
 #include "octave-config.h"
 
 #include <cstdio>
-
-#include <iostream>
-#include <streambuf>
+#include <istream>
 
 class
 c_file_ptr_buf : public std::streambuf
--- a/libinterp/corefcn/call-stack.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/call-stack.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,9 @@
 #  include "config.h"
 #endif
 
+#include "lo-regexp.h"
+#include "str-vec.h"
+
 #include "call-stack.h"
 #include "defun.h"
 #include "interpreter.h"
@@ -33,6 +36,10 @@
 #include "ov-fcn-handle.h"
 #include "ov-usr-fcn.h"
 #include "pager.h"
+#include "parse.h"
+#include "syminfo.h"
+#include "symrec.h"
+#include "symscope.h"
 #include "variables.h"
 
 // Use static fields for the best efficiency.
@@ -87,12 +94,52 @@
       return true;
   }
 
+  symbol_info_list
+  call_stack::stack_frame::make_symbol_info_list
+    (const std::list<symbol_record>& symrec_list) const
+  {
+    symbol_info_list symbol_stats;
+
+    for (const auto& sr : symrec_list)
+      {
+        octave_value value = sr.varval (m_context);
+
+        if (value.is_defined ())
+          {
+            symbol_info syminf (sr.name (), value, sr.is_automatic (),
+                                value.iscomplex (), sr.is_formal (),
+                                sr.is_global (), sr.is_persistent ());
+
+            symbol_stats.append (syminf);
+          }
+      }
+
+    return symbol_stats;
+  }
+
+  symbol_info_list
+  call_stack::stack_frame::glob_symbol_info (const std::string& pat) const
+  {
+    return make_symbol_info_list (m_scope.glob (pat, true));
+  }
+
+  symbol_info_list
+  call_stack::stack_frame::regexp_symbol_info (const std::string& pat) const
+  {
+    return make_symbol_info_list (m_scope.regexp (pat, true));
+  }
+
+  symbol_info_list call_stack::stack_frame::get_symbol_info (void) const
+  {
+    return make_symbol_info_list (m_scope.all_variables ());
+  }
+
   call_stack::call_stack (interpreter& interp)
     : cs (), curr_frame (0), m_max_stack_depth (1024), m_interpreter (interp)
   {
     symbol_table& symtab = m_interpreter.get_symbol_table ();
 
-    push (nullptr, symtab.top_scope (), 0);
+    push (nullptr, nullptr, symtab.top_scope (), 0);
   }
 
   int
@@ -137,7 +184,7 @@
 
     size_t k = cs.size ();
 
-    for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
+    for (auto p = cs.crbegin (); p != cs.crend (); p++)
       {
         octave_function *f = (*p).m_fcn;
 
@@ -165,9 +212,9 @@
   {
     octave_user_code *retval = nullptr;
 
-    const_iterator p = cs.end ();
+    auto p = cs.cend ();
 
-    while (p != cs.begin ())
+    while (p != cs.cbegin ())
       {
         const stack_frame& elt = *(--p);
 
@@ -193,9 +240,9 @@
   {
     int retval = -1;
 
-    const_iterator p = cs.end ();
+    auto p = cs.cend ();
 
-    while (p != cs.begin ())
+    while (p != cs.cbegin ())
       {
         const stack_frame& elt = *(--p);
 
@@ -214,14 +261,32 @@
     return retval;
   }
 
+  unwind_protect *
+  call_stack::curr_fcn_unwind_protect_frame (void) const
+  {
+    auto p = cs.cend ();
+
+    while (p != cs.cbegin ())
+      {
+        const stack_frame& elt = *(--p);
+
+        octave_function *f = elt.m_fcn;
+
+        if (f && f->is_user_code ())
+          return elt.m_unwind_protect_frame;
+      }
+
+    return nullptr;
+  }
+
   int
   call_stack::caller_user_code_column (void) const
   {
     int retval = -1;
 
-    const_iterator p = cs.end ();
+    auto p = cs.cend ();
 
-    while (p != cs.begin ())
+    while (p != cs.cbegin ())
       {
         const stack_frame& elt = *(--p);
 
@@ -335,9 +400,9 @@
   {
     bool retval = true;
 
-    const_iterator p = cs.end ();
+    auto p = cs.cend ();
 
-    while (p != cs.begin ())
+    while (p != cs.cbegin ())
       {
         const stack_frame& elt = *(--p);
 
@@ -354,15 +419,16 @@
   }
 
   void
-  call_stack::push (octave_function *fcn)
+  call_stack::push (octave_function *fcn, unwind_protect *up_frame)
   {
     symbol_table& symtab = m_interpreter.get_symbol_table ();
 
-    push (fcn, symtab.current_scope (), symtab.current_context ());
+    push (fcn, up_frame, symtab.current_scope (), symtab.current_context ());
   }
 
   void
-  call_stack::push (octave_function *fcn, const symbol_scope& scope,
+  call_stack::push (octave_function *fcn, unwind_protect *up_frame,
+                    const symbol_scope& scope,
                     symbol_record::context_id context)
   {
     size_t prev_frame = curr_frame;
@@ -372,7 +438,7 @@
     if (curr_frame > static_cast<size_t> (m_max_stack_depth))
       error ("max_stack_depth exceeded");
 
-    cs.push_back (stack_frame (fcn, scope, context, prev_frame));
+    cs.push_back (stack_frame (fcn, up_frame, scope, context, prev_frame));
 
     symbol_table& symtab = m_interpreter.get_symbol_table ();
 
@@ -550,7 +616,7 @@
 
     if (nframes > 0)
       {
-        for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
+        for (auto p = cs.crbegin (); p != cs.crend (); p++)
           {
             const stack_frame& elt = *p;
 
@@ -632,6 +698,28 @@
       }
   }
 
+  symbol_info_list
+  call_stack::glob_symbol_info (const std::string& pat) const
+  {
+    return cs[curr_frame].glob_symbol_info (pat);
+  }
+
+  symbol_info_list
+  call_stack::regexp_symbol_info (const std::string& pat) const
+  {
+    return cs[curr_frame].glob_symbol_info (pat);
+  }
+
+  symbol_info_list call_stack::get_symbol_info (void) const
+  {
+    return cs[curr_frame].get_symbol_info ();
+  }
+
+  symbol_info_list call_stack::top_scope_symbol_info (void) const
+  {
+    return cs[0].get_symbol_info ();
+  }
+
   octave_value
   call_stack::max_stack_depth (const octave_value_list& args, int nargout)
   {
@@ -675,3 +763,320 @@
 %!error (max_stack_depth (1, 2))
 */
 
+static octave_value
+do_who_two (octave::interpreter& interp, const string_vector& pats,
+            bool global_only, bool have_regexp, bool return_list,
+            bool verbose = false, std::string msg = "")
+{
+  octave::symbol_info_list symbol_stats;
+  std::list<std::string> symbol_names;
+
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+  octave::symbol_table& symtab = interp.get_symbol_table ();
+
+  octave::symbol_scope scope = symtab.current_scope ();
+
+  octave::symbol_record::context_id context = scope.current_context ();
+
+  octave_idx_type npats = pats.numel ();
+
+  for (octave_idx_type j = 0; j < npats; j++)
+    {
+      std::string pat = pats[j];
+
+      std::list<octave::symbol_record> tmp
+        = (have_regexp
+           ? (global_only
+              ? symtab.regexp_global_variables (pat)
+              : symtab.regexp_variables (pat))
+           : (global_only
+              ? symtab.glob_global_variables (pat)
+              : symtab.glob_variables (pat)));
+
+      for (const auto& sr : tmp)
+        {
+          octave_value value = sr.varval (context);
+
+          if (value.is_defined ())
+            {
+              if (verbose)
+                {
+                  octave::symbol_info
+                    syminf (sr.name (), value, sr.is_automatic (),
+                            value.iscomplex (), sr.is_formal (),
+                            sr.is_global (), sr.is_persistent ());
+
+                  symbol_stats.append (syminf);
+                }
+              else
+                symbol_names.push_back (sr.name ());
+            }
+        }
+    }
+
+  if (return_list)
+    {
+      if (verbose)
+        {
+          octave::call_stack& cs = interp.get_call_stack ();
+
+          std::string caller_function_name;
+          octave_function *caller = cs.caller ();
+          if (caller)
+            caller_function_name = caller->name ();
+
+          return symbol_stats.map_value (caller_function_name, 1);
+        }
+      else
+        return Cell (string_vector (symbol_names));
+    }
+  else if (! (symbol_stats.empty () && symbol_names.empty ()))
+    {
+      if (msg.empty ())
+        if (global_only)
+          octave_stdout << "Global variables:\n\n";
+        else
+          octave_stdout << "Variables in the current scope:\n\n";
+      else
+        octave_stdout << msg;
+
+      if (verbose)
+        symbol_stats.display (octave_stdout, tw.whos_line_format ());
+      else
+        {
+          string_vector names (symbol_names);
+
+          names.list_in_columns (octave_stdout);
+        }
+
+      octave_stdout << "\n";
+    }
+
+  return octave_value ();
+}
+
+static octave_value
+do_who (octave::interpreter& interp, int argc, const string_vector& argv,
+        bool return_list, bool verbose = false)
+{
+  octave_value retval;
+
+  octave::symbol_table& symtab = interp.get_symbol_table ();
+  octave::call_stack& cs = interp.get_call_stack ();
+
+  std::string my_name = argv[0];
+
+  std::string file_name;
+
+  bool from_file = false;
+  bool global_only = false;
+  bool have_regexp = false;
+
+  int i = 1;
+  while (i < argc)
+    {
+      if (argv[i] == "-file")
+        {
+          if (from_file)
+            error ("%s: -file option may only be specified once",
+                   my_name.c_str ());
+
+          from_file = true;
+
+          if (i == argc - 1)
+            error ("%s: -file argument must be followed by a filename",
+                   my_name.c_str ());
+
+          file_name = argv[++i];
+        }
+      else if (argv[i] == "-regexp")
+        {
+          have_regexp = true;
+        }
+      else if (argv[i] == "global")
+        global_only = true;
+      else if (argv[i][0] == '-')
+        warning ("%s: unrecognized option '%s'", my_name.c_str (),
+                 argv[i].c_str ());
+      else
+        break;
+
+      i++;
+    }
+
+  int npats = argc - i;
+  string_vector pats;
+  if (npats > 0)
+    {
+      pats.resize (npats);
+      for (int j = 0; j < npats; j++)
+        pats[j] = argv[i+j];
+    }
+  else
+    {
+      pats.resize (1);
+      pats[0] = "*";
+    }
+
+  if (from_file)
+    {
+      // FIXME: This is an inefficient manner to implement this as the
+      // variables are loaded in to a temporary context and then treated.
+      // It would be better to refactor symbol_info_list to not store the
+      // symbol records and then use it in load-save.cc (do_load) to
+      // implement this option there so that the variables are never
+      // stored at all.
+
+      octave::unwind_protect frame;
+
+      // Set up temporary scope.
+
+      octave::symbol_scope tmp_scope ("$dummy_scope$");
+
+      symtab.set_scope (tmp_scope);
+
+      cs.push (tmp_scope, 0);
+      frame.add_method (cs, &octave::call_stack::pop);
+
+      octave::feval ("load", octave_value (file_name), 0);
+
+      std::string newmsg = "Variables in the file " + file_name + ":\n\n";
+
+      return do_who_two (interp, pats, global_only, have_regexp,
+                         return_list, verbose, newmsg);
+    }
+  else
+    return do_who_two (interp, pats, global_only, have_regexp,
+                       return_list, verbose);
+}
+
+DEFMETHOD (who, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {} who
+@deftypefnx {} {} who pattern @dots{}
+@deftypefnx {} {} who option pattern @dots{}
+@deftypefnx {} {C =} who ("pattern", @dots{})
+List currently defined variables matching the given patterns.
+
+Valid pattern syntax is the same as described for the @code{clear} command.
+If no patterns are supplied, all variables are listed.
+
+By default, only variables visible in the local scope are displayed.
+
+The following are valid options, but may not be combined.
+
+@table @code
+@item global
+List variables in the global scope rather than the current scope.
+
+@item -regexp
+The patterns are considered to be regular expressions when matching the
+variables to display.  The same pattern syntax accepted by the @code{regexp}
+function is used.
+
+@item -file
+The next argument is treated as a filename.  All variables found within the
+specified file are listed.  No patterns are accepted when reading variables
+from a file.
+@end table
+
+If called as a function, return a cell array of defined variable names
+matching the given patterns.
+@seealso{whos, isglobal, isvarname, exist, regexp}
+@end deftypefn */)
+{
+  int argc = args.length () + 1;
+
+  string_vector argv = args.make_argv ("who");
+
+  return do_who (interp, argc, argv, nargout == 1);
+}
+
+/*
+%!test
+%! avar = magic (4);
+%! ftmp = [tempname() ".mat"];
+%! unwind_protect
+%!   save (ftmp, "avar");
+%!   vars = whos ("-file", ftmp);
+%!   assert (numel (vars), 1);
+%!   assert (isstruct (vars));
+%!   assert (vars.name, "avar");
+%!   assert (vars.size, [4, 4]);
+%!   assert (vars.class, "double");
+%!   assert (vars.bytes, 128);
+%! unwind_protect_cleanup
+%!   unlink (ftmp);
+%! end_unwind_protect
+*/
+
+DEFMETHOD (whos, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {} whos
+@deftypefnx {} {} whos pattern @dots{}
+@deftypefnx {} {} whos option pattern @dots{}
+@deftypefnx {} {S =} whos ("pattern", @dots{})
+Provide detailed information on currently defined variables matching the
+given patterns.
+
+Options and pattern syntax are the same as for the @code{who} command.
+
+Extended information about each variable is summarized in a table with the
+following default entries.
+
+@table @asis
+@item Attr
+Attributes of the listed variable.  Possible attributes are:
+
+@table @asis
+@item blank
+Variable in local scope
+
+@item @code{a}
+Automatic variable.  An automatic variable is one created by the
+interpreter, for example @code{argn}.
+
+@item @code{c}
+Variable of complex type.
+
+@item @code{f}
+Formal parameter (function argument).
+
+@item @code{g}
+Variable with global scope.
+
+@item @code{p}
+Persistent variable.
+@end table
+
+@item Name
+The name of the variable.
+
+@item Size
+The logical size of the variable.  A scalar is 1x1, a vector is
+@nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.
+
+@item Bytes
+The amount of memory currently used to store the variable.
+
+@item Class
+The class of the variable.  Examples include double, single, char, uint16,
+cell, and struct.
+@end table
+
+The table can be customized to display more or less information through
+the function @code{whos_line_format}.
+
+If @code{whos} is called as a function, return a struct array of defined
+variable names matching the given patterns.  Fields in the structure
+describing each variable are: name, size, bytes, class, global, sparse,
+complex, nesting, persistent.
+@seealso{who, whos_line_format}
+@end deftypefn */)
+{
+  int argc = args.length () + 1;
+
+  string_vector argv = args.make_argv ("whos");
+
+  return do_who (interp, argc, argv, nargout == 1, true);
+}
--- a/libinterp/corefcn/call-stack.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/call-stack.h	Thu Dec 20 17:18:56 2018 -0500
@@ -40,6 +40,8 @@
 namespace octave
 {
   class interpreter;
+  class symbol_info_list;
+  class unwind_protect;
 
   class
   OCTINTERP_API
@@ -54,15 +56,20 @@
       friend class call_stack;
 
       stack_frame (octave_function *fcn = nullptr,
+                   unwind_protect *up_frame = nullptr,
                    const symbol_scope& scope = symbol_scope (),
                    symbol_record::context_id context = 0, size_t prev = 0)
-        : m_fcn (fcn), m_line (-1), m_column (-1), m_scope (scope),
+        : m_fcn (fcn), m_unwind_protect_frame (up_frame),
+          m_line (-1), m_column (-1), m_scope (scope),
           m_context (context), m_prev (prev)
       { }
 
       stack_frame (const stack_frame& elt)
-        : m_fcn (elt.m_fcn), m_line (elt.m_line), m_column (elt.m_column),
-          m_scope (elt.m_scope), m_context (elt.m_context), m_prev (elt.m_prev)
+        : m_fcn (elt.m_fcn),
+          m_unwind_protect_frame (elt.m_unwind_protect_frame),
+          m_line (elt.m_line), m_column (elt.m_column),
+          m_scope (elt.m_scope), m_context (elt.m_context),
+          m_prev (elt.m_prev)
       { }
 
       int line (void) const { return m_line; }
@@ -75,9 +82,19 @@
 
       bool operator == (const stack_frame& rhs) const;
 
+      symbol_info_list
+      make_symbol_info_list (const std::list<symbol_record>& srl) const;
+
+      symbol_info_list glob_symbol_info (const std::string& pat) const;
+
+      symbol_info_list regexp_symbol_info (const std::string& pat) const;
+
+      symbol_info_list get_symbol_info (void) const;
+
     private:
 
       octave_function *m_fcn;
+      unwind_protect *m_unwind_protect_frame;
       int m_line;
       int m_column;
       symbol_scope m_scope;
@@ -156,6 +173,8 @@
     // User code caller.
     octave_user_code * caller_user_code (size_t nskip = 0) const;
 
+    unwind_protect *curr_fcn_unwind_protect_frame (void) const;
+
     // Line in user code caller.
     int caller_user_code_line (void) const;
 
@@ -174,18 +193,15 @@
     // Return TRUE if all elements on the call stack are scripts.
     bool all_scripts (void) const;
 
-    void push (octave_function *fcn);
-    void push (octave_function *fcn, const symbol_scope& scope,
-               symbol_record::context_id context);
+    void push (octave_function *fcn = nullptr,
+               unwind_protect *up_frame = nullptr);
 
-    void push (void)
-    {
-      push (nullptr);
-    }
+    void push (octave_function *fcn, unwind_protect *up_frame,
+               const symbol_scope& scope, symbol_record::context_id context);
 
     void push (const symbol_scope& scope, symbol_record::context_id context)
     {
-      push (nullptr, scope, context);
+      push (nullptr, nullptr, scope, context);
     }
 
     void set_location (int l, int c)
@@ -254,6 +270,14 @@
 
     void clear (void) { cs.clear (); }
 
+    symbol_info_list glob_symbol_info (const std::string& pat) const;
+
+    symbol_info_list regexp_symbol_info (const std::string& pat) const;
+
+    symbol_info_list get_symbol_info (void) const;
+
+    symbol_info_list top_scope_symbol_info (void) const;
+
     octave_value max_stack_depth (const octave_value_list& args, int nargout);
 
   private:
--- a/libinterp/corefcn/cellfun.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/cellfun.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -99,7 +99,7 @@
           msg.assign ("message", last_error_message ());
           msg.assign ("index",
                       static_cast<double> (count
-                                           + static_cast<octave_idx_type>(1)));
+                                           + static_cast<octave_idx_type> (1)));
 
           octave_value_list errlist = inputlist;
           errlist.prepend (msg);
@@ -425,7 +425,7 @@
 
       std::string name = args(0).string_value ();
 
-      if (! valid_identifier (name))
+      if (! octave::valid_identifier (name))
         {
           std::string fcn_name = unique_symbol_name ("__cellfun_fcn__");
           std::string fname = "function y = " + fcn_name + "(x) y = ";
@@ -688,26 +688,34 @@
 /*
 
 %!function r = __f11 (x)
-%!  global __cellfun_test_num_outputs__;
-%!  __cellfun_test_num_outputs__ = nargout;
 %!  r = x;
 %!endfunction
 
 %!function __f01 (x)
-%!  global __cellfun_test_num_outputs__;
-%!  __cellfun_test_num_outputs__ = nargout;
+%!  ## Empty function
 %!endfunction
 
 %!test
-%! global __cellfun_test_num_outputs__;
-%! cellfun (@__f11, {1});
+%! __cellfun_test_num_outputs__ = -1;
+%!
+%! function r = __subf11 (x)
+%!   __cellfun_test_num_outputs__ = nargout;
+%!   r = x;
+%! endfunction
+%!
+%! cellfun ("__subf11", {1});
 %! assert (__cellfun_test_num_outputs__, 0);
-%! x = cellfun (@__f11, {1});
+%!
+%! __cellfun_test_num_outputs__ = -1;
+%! x = cellfun ("__subf11", {1});
 %! assert (__cellfun_test_num_outputs__, 1);
 
 %!test
-%! global __cellfun_test_num_outputs__;
-%! cellfun (@__f01, {1});
+%! __cellfun_test_num_outputs__ = -1;
+%! function __subf01 (x)
+%!   __cellfun_test_num_outputs__ = nargout;
+%! endfunction
+%! cellfun ("__subf01", {1});
 %! assert (__cellfun_test_num_outputs__, 0);
 
 %!error x = cellfun (@__f01, {1, 2})
@@ -1132,7 +1140,7 @@
       // See if we can convert the string into a function.
       std::string name = args(0).string_value ();
 
-      if (! valid_identifier (name))
+      if (! octave::valid_identifier (name))
         {
           std::string fcn_name = unique_symbol_name ("__arrayfun_fcn__");
           std::string fname = "function y = " + fcn_name + "(x) y = ";
@@ -1389,26 +1397,36 @@
 
 /*
 %!function r = __f11 (x)
-%!  global __arrayfun_test_num_outputs__;
-%!  __arrayfun_test_num_outputs__ = nargout;
 %!  r = x;
 %!endfunction
 
 %!function __f01 (x)
-%!  global __arrayfun_test_num_outputs__;
-%!  __arrayfun_test_num_outputs__ = nargout;
+%!  ## Empty function
 %!endfunction
 
 %!test
-%! global __arrayfun_test_num_outputs__;
-%! arrayfun (@__f11, {1});
+%! __arrayfun_test_num_outputs__ = -1;
+%!
+%! function r = __subf11 (x)
+%!   __arrayfun_test_num_outputs__ = nargout;
+%!   r = x;
+%! endfunction
+%!
+%! arrayfun ("__subf11", {1});
 %! assert (__arrayfun_test_num_outputs__, 0);
-%! x = arrayfun (@__f11, {1});
+%!
+%! __arrayfun_test_num_outputs__ = -1;
+%! x = arrayfun ("__subf11", {1});
 %! assert (__arrayfun_test_num_outputs__, 1);
 
 %!test
-%! global __arrayfun_test_num_outputs__;
-%! arrayfun (@__f01, {1});
+%! __arrayfun_test_num_outputs__ = -1;
+%!
+%! function __subf01 (x)
+%!   __arrayfun_test_num_outputs__ = nargout;
+%! endfunction
+%!
+%! arrayfun ("__subf01", {1});
 %! assert (__arrayfun_test_num_outputs__, 0);
 
 %!error x = arrayfun (@__f01, [1, 2])
@@ -1887,7 +1905,8 @@
       octave_idx_type r = (i < dv.ndims () ? dv(i) : 1);
 
       if (s != r)
-        error ("mat2cell: mismatch on dimension %d (%d != %d)", i+1, r, s);
+        error ("mat2cell: mismatch on dimension %d (%" OCTAVE_IDX_TYPE_FORMAT
+               " != %" OCTAVE_IDX_TYPE_FORMAT ")", i+1, r, s);
     }
 
   return false;
--- a/libinterp/corefcn/daspk.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/daspk.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,9 +26,6 @@
 
 #include <string>
 
-#include <iomanip>
-#include <iostream>
-
 #include "DASPK.h"
 
 #include "defun.h"
--- a/libinterp/corefcn/dasrt.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/dasrt.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <string>
 
 #include "DASRT.h"
--- a/libinterp/corefcn/dassl.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/dassl.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,9 +26,6 @@
 
 #include <string>
 
-#include <iomanip>
-#include <iostream>
-
 #include "DASSL.h"
 
 #include "defun.h"
--- a/libinterp/corefcn/data.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/data.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -617,7 +617,7 @@
         btyp1 = btyp0;
 
       if (btyp0 != btyp1)
-        error ("rem: cannot combine %s and %d",
+        error ("rem: cannot combine %s and %s",
                args(0).class_name ().c_str (),
                args(1).class_name ().c_str ());
 
@@ -796,7 +796,7 @@
         btyp1 = btyp0;
 
       if (btyp0 != btyp1)
-        error ("mod: cannot combine %s and %d",
+        error ("mod: cannot combine %s and %s",
                args(0).class_name ().c_str (),
                args(1).class_name ().c_str ());
 
@@ -2537,7 +2537,8 @@
 Return the number of dimensions of @var{a}.
 
 For any array, the result will always be greater than or equal to 2.
-Trailing singleton dimensions are not counted.
+Trailing singleton dimensions are not counted, i.e., tailing dimensions @var{d}
+greater than 2, for which @code{size (@var{a}, @var{d}) = 1}.
 
 @example
 @group
@@ -2551,8 +2552,24 @@
   if (args.length () != 1)
     print_usage ();
 
-  return ovl (args(0).ndims ());
-}
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  octave_idx_type ndims = sz.numel ();
+
+  // Don't count trailing ones.  Trailing zeros are *not* singleton dimension.
+  while ((ndims > 2) && (sz(ndims - 1) == 1))
+    ndims--;
+
+  return ovl (ndims);
+}
+
+/*
+%!assert (ndims (1:5), 2)
+%!assert (ndims (ones (4, 1, 2, 1)), 3)
+%!assert (ndims (ones (4, 1, 2, 0)), 4)
+*/
 
 DEFUN (numel, args, ,
        doc: /* -*- texinfo -*-
@@ -2610,7 +2627,8 @@
     {
       // Don't use numel (const octave_value_list&) here as that corresponds to
       // an overloaded call, not to builtin!
-      retval = dims_to_numel (args(0).dims (), args.slice (1, nargin-1));
+      retval = octave::dims_to_numel (args(0).dims (),
+                                      args.slice (1, nargin-1));
     }
 
   return retval;
@@ -2713,7 +2731,8 @@
       const dim_vector dv = args(0).dims ();
 
       if (nd < 1)
-        error ("size: requested dimension DIM (= %d) out of range", nd);
+        error ("size: requested dimension DIM (= %" OCTAVE_IDX_TYPE_FORMAT ") "
+               "out of range", nd);
 
       if (nd <= dv.ndims ())
         retval(0) = dv(nd-1);
@@ -2803,14 +2822,18 @@
 DEFUN (rows, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} rows (@var{a})
-Return the number of rows of @var{a}.
+Return the number of rows of @var{a}.  This is equivalent to
+@code{size (@var{a}, 1)}.
 @seealso{columns, size, length, numel, isscalar, isvector, ismatrix}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  return ovl (args(0).rows ());
+  // This function *must* use size() to determine the desired values to
+  // allow user-defined class overloading.
+
+  return ovl ((octave_value (args(0)).size ())(0));
 }
 
 /*
@@ -2843,14 +2866,18 @@
 DEFUN (columns, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} columns (@var{a})
-Return the number of columns of @var{a}.
+Return the number of columns of @var{a}.  This is equivalent to
+@code{size (@var{a}, 2)}.
 @seealso{rows, size, length, numel, isscalar, isvector, ismatrix}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  return ovl (args(0).columns ());
+  // This function *must* use size() to determine the desired values to
+  // allow user-defined class overloading.
+
+  return ovl ((octave_value (args(0)).size ())(1));
 }
 
 DEFUN (sum, args, ,
@@ -3224,6 +3251,23 @@
   return ovl (args(0).iscomplex ());
 }
 
+/*
+%!assert (iscomplex (4), false)
+%!assert (iscomplex (i), true)
+%!assert (iscomplex (4+3i), true)
+%!assert (iscomplex ([1, 2, 3]), false)
+%!assert (iscomplex ([1, 2i, 3]), true)
+
+%!assert (iscomplex (0j), false)
+%!assert (iscomplex (complex (0,0)), true)
+%!assert (iscomplex ("4"), false)
+%!assert (iscomplex ({i}), false)
+
+## Test input validation
+%!error iscomplex ()
+%!error iscomplex (1, 2)
+*/
+
 DEFUN (isfloat, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} isfloat (@var{x})
@@ -3619,14 +3663,19 @@
 DEFUN (isscalar, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} isscalar (@var{x})
-Return true if @var{x} is a scalar.
+Return true if @var{x} is a scalar, i.e., @code{size (@var{x})} returns
+@code{[1 1]}.
 @seealso{isvector, ismatrix}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  return ovl (args(0).numel () == 1);
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && sz(0) == 1 && sz(1) == 1);
 }
 
 /*
@@ -3661,9 +3710,11 @@
   if (args.length () != 1)
     print_usage ();
 
-  dim_vector sz = args(0).dims ();
-
-  return ovl (sz.ndims () == 2 && (sz(0) == 1 || sz(1) == 1));
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && (sz(0) == 1 || sz(1) == 1));
 }
 
 /*
@@ -3689,16 +3740,19 @@
 DEFUN (isrow, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} isrow (@var{x})
-Return true if @var{x} is a row vector 1xN with non-negative N.
+Return true if @var{x} is a row vector, i.e., @code{size (@var{x})} returns
+@code{[1 N]} with non-negative N.
 @seealso{iscolumn, isscalar, isvector, ismatrix}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  dim_vector sz = args(0).dims ();
-
-  return ovl (sz.ndims () == 2 && sz(0) == 1);
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && sz(0) == 1);
 }
 
 /*
@@ -3733,16 +3787,19 @@
 DEFUN (iscolumn, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} iscolumn (@var{x})
-Return true if @var{x} is a column vector Nx1 with non-negative N.
+Return true if @var{x} is a column vector, i.e., @code{size (@var{x})} returns
+@code{[N 1]} with non-negative N.
 @seealso{isrow, isscalar, isvector, ismatrix}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  dim_vector sz = args(0).dims ();
-
-  return ovl (sz.ndims () == 2 && sz(1) == 1);
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && sz(1) == 1);
 }
 
 /*
@@ -3777,16 +3834,19 @@
 DEFUN (ismatrix, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} ismatrix (@var{a})
-Return true if @var{a} is a 2-D array.
+Return true if @var{a} is a 2-D array, i.e., @code{size (@var{a})} returns
+@code{[M N]} with non-negative M and N.
 @seealso{isscalar, isvector, iscell, isstruct, issparse, isa}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  dim_vector sz = args(0).dims ();
-
-  return ovl (sz.ndims () == 2 && sz(0) >= 0 && sz(1) >= 0);
+  // This function *must* use size() to determine the desired values to be
+  // compatible with Matlab and to allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && sz(0) >= 0 && sz(1) >= 0);
 }
 
 /*
@@ -3820,16 +3880,19 @@
 DEFUN (issquare, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} issquare (@var{x})
-Return true if @var{x} is a square matrix.
+Return true if @var{x} is a square matrix, i.e., @code{size (@var{x})} returns
+@code{[N N]} with non-negative N.
 @seealso{isscalar, isvector, ismatrix, size}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  dim_vector sz = args(0).dims ();
-
-  return ovl (sz.ndims () == 2 && sz(0) == sz(1));
+  // This function *must* use size() to determine the desired values to
+  // allow user-defined class overloading.
+  Matrix sz = octave_value (args(0)).size ();
+
+  return ovl (sz.numel () == 2 && sz(0) == sz(1));
 }
 
 /*
@@ -3878,7 +3941,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), fcn, dims);
+      octave::get_dimensions (args(0), fcn, dims);
       break;
 
     default:
@@ -3886,19 +3949,17 @@
         dims.resize (nargin);
 
         for (int i = 0; i < nargin; i++)
-          dims(i) = (args(i).isempty ()
-                     ? 0 : args(i).xidx_type_value ("%s: dimension arguments must be scalar integers", fcn));
+          dims(i) = (args(i).isempty () ? 0 : args(i).idx_type_value (true));
       }
       break;
     }
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, fcn);
-
-  // FIXME: perhaps this should be made extensible by
-  // using the class name to lookup a function to call to create
-  // the new value.
+  octave::check_dimensions (dims, fcn);
+
+  // FIXME: Perhaps this should be made extensible by using the class name
+  //        to lookup a function to call to create the new value.
 
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
@@ -3988,7 +4049,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), fcn, dims);
+      octave::get_dimensions (args(0), fcn, dims);
       break;
 
     default:
@@ -3996,15 +4057,14 @@
         dims.resize (nargin);
 
         for (int i = 0; i < nargin; i++)
-          dims(i) = (args(i).isempty ()
-                     ? 0 : args(i).xidx_type_value ("%s: dimension arguments must be scalar integers", fcn));
+          dims(i) = (args(i).isempty () ? 0 : args(i).idx_type_value (true));
       }
       break;
     }
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, fcn);
+  octave::check_dimensions (dims, fcn);
 
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
@@ -4052,7 +4112,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), fcn, dims);
+      octave::get_dimensions (args(0), fcn, dims);
       break;
 
     default:
@@ -4060,15 +4120,14 @@
         dims.resize (nargin);
 
         for (int i = 0; i < nargin; i++)
-          dims(i) = (args(i).isempty ()
-                     ? 0 : args(i).xidx_type_value ("%s: dimension arguments must be scalar integers", fcn));
+          dims(i) = (args(i).isempty () ? 0 : args(i).idx_type_value (true));
       }
       break;
     }
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, fcn);
+  octave::check_dimensions (dims, fcn);
 
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
@@ -4117,7 +4176,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), fcn, dims);
+      octave::get_dimensions (args(0), fcn, dims);
       break;
 
     default:
@@ -4125,15 +4184,14 @@
         dims.resize (nargin);
 
         for (int i = 0; i < nargin; i++)
-          dims(i) = (args(i).isempty ()
-                     ? 0 : args(i).xidx_type_value ("%s: dimension arguments must be scalar integers", fcn));
+          dims(i) = (args(i).isempty () ? 0 : args(i).idx_type_value (true));
       }
       break;
     }
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, fcn);
+  octave::check_dimensions (dims, fcn);
 
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
@@ -4172,7 +4230,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), fcn, dims);
+      octave::get_dimensions (args(0), fcn, dims);
       break;
 
     default:
@@ -4180,15 +4238,14 @@
         dims.resize (nargin);
 
         for (int i = 0; i < nargin; i++)
-          dims(i) = (args(i).isempty ()
-                     ? 0 : args(i).xidx_type_value ("%s: dimension arguments must be scalar integers", fcn));
+          dims(i) = (args(i).isempty () ? 0 : args(i).idx_type_value (true));
       }
       break;
     }
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, fcn);
+  octave::check_dimensions (dims, fcn);
 
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
@@ -4247,6 +4304,13 @@
 %!assert (ones (2, 3, "int8"), int8 ([1, 1, 1; 1, 1, 1]))
 %!assert (ones (3, 2, "int8"), int8 ([1, 1; 1, 1; 1, 1]))
 %!assert (size (ones (3, 4, 5, "int8")), [3, 4, 5])
+
+%!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])
 */
 
 /*
@@ -4308,6 +4372,14 @@
 %!assert (zeros (2, 3, "int8"), int8 ([0, 0, 0; 0, 0, 0]))
 %!assert (zeros (3, 2, "int8"), int8 ([0, 0; 0, 0; 0, 0]))
 %!assert (size (zeros (3, 4, 5, "int8")), [3, 4, 5])
+
+## Test input validation
+%!error <invalid data type specified> zeros (1, 1, "foobar")
+%!error <conversion of 1.1 .*failed> zeros (1.1)
+%!error <conversion of 1.1 .*failed> zeros (1, 1.1)
+%!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])
 */
 
 DEFUN (Inf, args, ,
@@ -4882,9 +4954,8 @@
 {
   octave_value retval;
 
-  // FIXME: perhaps this should be made extensible by using
-  // the class name to lookup a function to call to create the new
-  // value.
+  // FIXME: Perhaps this should be made extensible by using the class name
+  //        to lookup a function to call to create the new value.
 
   switch (dt)
     {
@@ -5016,14 +5087,14 @@
   else if (nargin == 1)
     {
       octave_idx_type nr, nc;
-      get_dimensions (args(0), "eye", nr, nc);
+      octave::get_dimensions (args(0), "eye", nr, nc);
 
       retval = identity_matrix (nr, nc, dt);
     }
   else
     {
       octave_idx_type nr, nc;
-      get_dimensions (args(0), args(1), "eye", nr, nc);
+      octave::get_dimensions (args(0), args(1), "eye", nr, nc);
 
       retval = identity_matrix (nr, nc, dt);
     }
@@ -5041,7 +5112,11 @@
 %!assert (eye (3, "int8"), int8 ([1, 0, 0; 0, 1, 0; 0, 0, 1]))
 %!assert (eye (2, 3, "int8"), int8 ([1, 0, 0; 0, 1, 0]))
 
+## Test input validation
 %!error eye (1, 2, 3)
+%!error <conversion of 1.1 .*failed> eye (1.1)
+%!error <conversion of 1.1 .*failed> eye (1, 1.1)
+%!error <conversion of 1.1 .*failed> eye ([1, 1.1])
 */
 
 template <typename MT>
@@ -5211,6 +5286,16 @@
 %!assert (linspace (10, 20, 2.1), [10 20])
 %!assert (linspace (10, 20, 2.9), [10 20])
 %!assert (1 ./ linspace (-0, 0, 4), [-Inf, Inf, Inf, Inf])
+%!assert (linspace (Inf, Inf, 3), [Inf, Inf, Inf])
+%!assert (linspace (-Inf, -Inf, 3), [-Inf, -Inf, -Inf])
+%!assert (linspace (-Inf, Inf, 3), [-Inf, NaN, Inf])
+%!assert (linspace (Inf + 1i, Inf + 1i, 3), [Inf + 1i, Inf + 1i, Inf + 1i])
+%!assert (linspace (-Inf + 1i, Inf + 1i, 3), [-Inf + 1i, NaN + 1i, Inf + 1i])
+%!assert (linspace (0, Inf, 3), [0, Inf, Inf])
+%!assert (linspace (0, -Inf, 3), [0, -Inf, -Inf])
+%!assert (linspace (-Inf, 0, 3), [-Inf, NaN, 0])
+%!assert (linspace (Inf, 0, 3), [Inf, NaN, 0])
+%!assert (linspace (Inf, -Inf, 3), [Inf, NaN, -Inf])
 
 %!error linspace ()
 %!error linspace (1, 2, 3, 4)
@@ -5409,7 +5494,8 @@
               octave_idx_type size_empty_dim = a_nel / nel;
 
               if (a_nel != size_empty_dim * nel)
-                error ("reshape: SIZE is not divisible by the product of known dimensions (= %d)",
+                error ("reshape: SIZE is not divisible by the product of "
+                       "known dimensions (= %" OCTAVE_IDX_TYPE_FORMAT ")",
                        nel);
 
               new_dims(empty_dim-1) = size_empty_dim;
@@ -5905,14 +5991,12 @@
 {
   int nargin = args.length ();
 
-  if (nargin == 0)
+  if (nargin < 2)
     print_usage ();
 
   octave_value retval;
 
-  if (nargin == 1)
-    retval = args(0);
-  else if (nargin == 2)
+  if (nargin == 2)
     retval = do_binary_op (op, args(0), args(1));
   else
     {
@@ -5938,7 +6022,6 @@
 (@dots{}((@var{x1} + @var{x2}) + @var{x3}) + @dots{})
 @end example
 
-At least one argument is required.
 @seealso{minus, uplus}
 @end deftypefn */)
 {
@@ -5946,6 +6029,17 @@
                                      octave_value::op_add_eq, args);
 }
 
+/*
+%!assert (plus (1,1), 2)
+%!assert (plus (1:3, 1), 2:4)
+%!assert (plus (1:3, 1, 3), 5:7)
+%!assert (plus (1,2,3,4,5,6,7,8,9), sum (1:9))
+
+## Test input validation for all functions which use binary_assoc_op_defun_body
+%!error plus ()
+%!error plus (1)
+*/
+
 DEFUN (minus, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} minus (@var{x}, @var{y})
@@ -5970,7 +6064,6 @@
 (@dots{}((@var{x1} * @var{x2}) * @var{x3}) * @dots{})
 @end example
 
-At least one argument is required.
 @seealso{times, plus, minus, rdivide, mrdivide, mldivide, mpower}
 @end deftypefn */)
 {
@@ -6092,7 +6185,6 @@
 (@dots{}((@var{x1} .* @var{x2}) .* @var{x3}) .* @dots{})
 @end example
 
-At least one argument is required.
 @seealso{mtimes, rdivide}
 @end deftypefn */)
 {
@@ -6157,7 +6249,6 @@
 (@dots{}((@var{x1} & @var{x2}) & @var{x3}) & @dots{})
 @end example
 
-At least one argument is required.
 @seealso{or, not, xor}
 @end deftypefn */)
 {
@@ -6179,7 +6270,6 @@
 (@dots{}((@var{x1} | @var{x2}) | @var{x3}) | @dots{})
 @end example
 
-At least one argument is required.
 @seealso{and, not, xor}
 @end deftypefn */)
 {
@@ -6749,14 +6839,14 @@
 
   std::string mode = arg.xstring_value ("issorted: MODE must be a string");
 
-  if (mode == "ascending")
+  if (mode == "ascend")
     smode = ASCENDING;
-  else if (mode == "descending")
+  else if (mode == "descend")
     smode = DESCENDING;
   else if (mode == "either")
     smode = UNSORTED;
   else
-    error (R"(issorted: MODE must be "ascending", "descending", or "either")");
+    error (R"(issorted: MODE must be "ascend", "descend", or "either")");
 
   return smode;
 }
@@ -6806,7 +6896,9 @@
 
   octave_value arg = args(0);
 
-  if (by_rows)
+  if (arg.isempty ())
+    retval = true;
+  else if (by_rows)
     {
       if (arg.issparse ())
         error ("issorted: sparse matrices not yet supported");
@@ -6840,18 +6932,18 @@
 %!assert (! issorted (uv))
 %!assert (issorted (sv'))
 %!assert (! issorted (uv'))
-%!assert (issorted (sm, "rows", "ascending"))
-%!assert (! issorted (um, "rows", "ascending"))
-%!assert (issorted (sv, "ascending"))
-%!assert (! issorted (uv, "ascending"))
-%!assert (issorted (sv', "ascending"))
-%!assert (! issorted (uv', "ascending"))
-%!assert (! issorted (sm, "rows", "descending"))
-%!assert (issorted (flipud (sm), "rows", "descending"))
-%!assert (! issorted (sv, "descending"))
-%!assert (issorted (fliplr (sv), "descending"))
-%!assert (! issorted (sv', "descending"))
-%!assert (issorted (fliplr (sv)', "descending"))
+%!assert (issorted (sm, "rows", "ascend"))
+%!assert (! issorted (um, "rows", "ascend"))
+%!assert (issorted (sv, "ascend"))
+%!assert (! issorted (uv, "ascend"))
+%!assert (issorted (sv', "ascend"))
+%!assert (! issorted (uv', "ascend"))
+%!assert (! issorted (sm, "rows", "descend"))
+%!assert (issorted (flipud (sm), "rows", "descend"))
+%!assert (! issorted (sv, "descend"))
+%!assert (issorted (fliplr (sv), "descend"))
+%!assert (! issorted (sv', "descend"))
+%!assert (issorted (fliplr (sv)', "descend"))
 %!assert (! issorted (um, "rows", "either"))
 %!assert (! issorted (uv, "either"))
 %!assert (issorted (sm, "rows", "either"))
@@ -6861,7 +6953,24 @@
 %!assert (issorted (sv', "either"))
 %!assert (issorted (fliplr (sv)', "either"))
 
-%!error <needs a vector> issorted ([])
+%!assert (issorted ([]))
+%!assert (issorted ([], "rows"))
+%!assert (issorted ([], "ascend"))
+%!assert (issorted ([], "rows", "ascend"))
+%!assert (issorted ([], "descend"))
+%!assert (issorted ([], "rows", "descend"))
+%!assert (issorted ({}))
+%!assert (issorted ({}, "rows"))
+%!assert (issorted ({}, "ascend"))
+%!assert (issorted ({}, "rows", "ascend"))
+%!assert (issorted ({}, "descend"))
+%!assert (issorted ({}, "rows", "descend"))
+%!assert (issorted (""))
+%!assert (issorted ("", "rows"))
+%!assert (issorted ("", "ascend"))
+%!assert (issorted ("", "rows", "ascend"))
+%!assert (issorted ("", "descend"))
+%!assert (issorted ("", "rows", "descend"))
 
 ## Test input validation
 %!error issorted ()
--- a/libinterp/corefcn/debug.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/debug.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -45,6 +45,7 @@
 #include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
+#include "lo-sysdep.h"
 #include "octave-preserve-stream-state.h"
 #include "ov-usr-fcn.h"
 #include "ov.h"
@@ -80,8 +81,8 @@
   return retval;
 }
 
-DEFUN (dbstop, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbstop, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} dbstop @var{func}
 @deftypefnx {} {} dbstop @var{func} @var{line}
 @deftypefnx {} {} dbstop @var{func} @var{line1} @var{line2} @dots{}
@@ -121,7 +122,7 @@
 editor's context menu.)  For example:
 
 @example
-dbstop in strread at 209 if 'any (format == "%f")'
+dbstop in axis at 246 if 'any (opt == "x")'
 @end example
 
 The form specifying @var{event} does not cause a specific breakpoint at a
@@ -176,7 +177,9 @@
   std::string condition = "";
   octave_value retval;
 
-  octave::bp_table& bptab = octave::__get_bp_table__ ("Fdbstop");
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  octave::bp_table& bptab = tw.get_bp_table ();
 
   if (args.length() >= 1 && ! args(0).isstruct ())
     {
@@ -252,8 +255,8 @@
   return retval;
 }
 
-DEFUN (dbclear, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbclear, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} dbclear @var{func}
 @deftypefnx {} {} dbclear @var{func} @var{line}
 @deftypefnx {} {} dbclear @var{func} @var{line1} @var{line2} @dots{}
@@ -302,7 +305,9 @@
 
   int nargin = args.length ();
 
-  octave::bp_table& bptab = octave::__get_bp_table__ ("Fdbclear");
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  octave::bp_table& bptab = tw.get_bp_table ();
 
   bptab.parse_dbfunction_params ("dbclear", args, symbol_name, lines, dummy);
 
@@ -374,7 +379,9 @@
   octave::bp_table::fname_bp_map bp_list;
   std::string symbol_name;
 
-  octave::bp_table& bptab = octave::__get_bp_table__ ("Fdbstatus");
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  octave::bp_table& bptab = tw.get_bp_table ();
 
   if (nargin == 1)
     {
@@ -390,7 +397,7 @@
 /*
       if (Vdebugging)
         {
-          octave_user_code *dbg_fcn = get_user_code ();
+          octave_user_code *dbg_fcn = tw.get_user_code ();
           if (dbg_fcn)
             {
               symbol_name = dbg_fcn->name ();
@@ -495,7 +502,7 @@
       retmap.assign ("line", line);
       retmap.assign ("cond", cond);
 
-      octave_map ew = bptab.stop_on_err_warn_status (false);
+      const octave_map ew = bptab.stop_on_err_warn_status (false);
       if (ew.isempty ())
         {
           retval = octave_value (retmap);
@@ -504,7 +511,7 @@
         {
           octave_map outer (dim_vector (3,1));
           outer.assign ("bkpt", Cell (retmap));
-          for (octave_map::const_iterator f = ew.begin (); f != ew.end (); f++)
+          for (auto f = ew.begin (); f != ew.end (); f++)
             outer.setfield (f->first, ew.contents (f));
 
           retval = octave_value (outer);
@@ -516,18 +523,28 @@
 
 /*
 %!test
-%! dbclear all;   # Clear out breakpoints before test
-%! dbstop @ftp/dir;
-%! dbstop @audioplayer/set 70;
-%! dbstop quantile>__quantile__;
-%! dbstop ls;
-%! s = dbstatus;
-%! dbclear all;
-%! assert (s(1).name, "@audioplayer/set>setproperty");
-%! assert (s(2).name, "@ftp/dir");
-%! assert (s(3).name, "ls");
-%! assert (s(4).name, "quantile>__quantile__");
-%! assert (s(2).file(end-10:end), [filesep "@ftp" filesep "dir.m"]);
+%! if (isguirunning ())
+%!   orig_show_dbg = __octave_link_gui_preference__ ("editor/show_dbg_file",
+%!                                                   "0");
+%! endif
+%! unwind_protect
+%!   dbclear all;   # Clear out breakpoints before test
+%!   dbstop @ftp/dir;
+%!   dbstop @audioplayer/set 70;
+%!   dbstop quantile>__quantile__;
+%!   dbstop ls;
+%!   s = dbstatus;
+%!   dbclear all;
+%!   assert (s(1).name, "@audioplayer/set>setproperty");
+%!   assert (s(2).name, "@ftp/dir");
+%!   assert (s(3).name, "ls");
+%!   assert (s(4).name, "quantile>__quantile__");
+%!   assert (s(2).file(end-10:end), [filesep "@ftp" filesep "dir.m"]);
+%! unwind_protect_cleanup
+%!   if (isguirunning ())
+%!     __octave_link_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
 */
 
 DEFMETHOD (dbwhere, interp, , ,
@@ -538,7 +555,9 @@
 @seealso{dbstack, dblist, dbstatus, dbcont, dbstep, dbup, dbdown}
 @end deftypefn */)
 {
-  octave_user_code *dbg_fcn = octave::get_user_code ();
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  octave_user_code *dbg_fcn = tw.get_user_code ();
 
   if (! dbg_fcn)
     {
@@ -579,13 +598,15 @@
 static void
 do_dbtype (std::ostream& os, const std::string& name, int start, int end)
 {
-  std::string ff = fcn_file_in_path (name);
+  std::string ff = octave::fcn_file_in_path (name);
 
   if (ff.empty ())
     os << "dbtype: unknown function " << name << "\n";
   else
     {
-      std::ifstream fs (ff.c_str (), std::ios::in);
+      std::string ascii_fname = octave::sys::get_ASCII_filename (ff);
+
+      std::ifstream fs (ascii_fname.c_str (), std::ios::in);
 
       if (! fs)
         os << "dbtype: unable to open '" << ff << "' for reading!\n";
@@ -607,8 +628,8 @@
   os.flush ();
 }
 
-DEFUN (dbtype, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbtype, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} dbtype
 @deftypefnx {} {} dbtype @var{lineno}
 @deftypefnx {} {} dbtype @var{startl:endl}
@@ -635,10 +656,12 @@
 
   string_vector argv = args.make_argv ("dbtype");
 
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
   switch (args.length ())
     {
     case 0:  // dbtype
-      dbg_fcn = octave::get_user_code ();
+      dbg_fcn = tw.get_user_code ();
 
       if (! dbg_fcn)
         error ("dbtype: must be inside a user function to give no arguments to dbtype\n");
@@ -656,7 +679,7 @@
 
         if (ind != std::string::npos)  // (dbtype start:end)
           {
-            dbg_fcn = octave::get_user_code ();
+            dbg_fcn = tw.get_user_code ();
 
             if (dbg_fcn)
               {
@@ -686,7 +709,7 @@
 
             if (line == 0)  // (dbtype func)
               {
-                dbg_fcn = octave::get_user_code (arg);
+                dbg_fcn = tw.get_user_code (arg);
 
                 if (! dbg_fcn)
                   error ("dbtype: function <%s> not found\n", arg.c_str ());
@@ -699,7 +722,7 @@
                 if (line <= 0)
                   error ("dbtype: start and end lines must be >= 1\n");
 
-                dbg_fcn = octave::get_user_code ();
+                dbg_fcn = tw.get_user_code ();
 
                 if (dbg_fcn)
                   do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (),
@@ -711,7 +734,7 @@
 
     case 2:  // (dbtype func start:end) || (dbtype func start)
       {
-        dbg_fcn = octave::get_user_code (argv[1]);
+        dbg_fcn = tw.get_user_code (argv[1]);
 
         if (! dbg_fcn)
           error ("dbtype: function <%s> not found\n", argv[1].c_str ());
@@ -784,7 +807,9 @@
         error ("dblist: N must be a non-negative integer");
     }
 
-  octave_user_code *dbg_fcn = octave::get_user_code ();
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  octave_user_code *dbg_fcn = tw.get_user_code ();
 
   if (! dbg_fcn)
     error ("dblist: must be inside a user function to use dblist\n");
@@ -1050,8 +1075,8 @@
   return ovl ();
 }
 
-DEFUN (dbstep, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbstep, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} dbstep
 @deftypefnx {} {} dbstep @var{n}
 @deftypefnx {} {} dbstep in
@@ -1081,6 +1106,8 @@
   if (nargin > 1)
     print_usage ();
 
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
   if (nargin == 1)
     {
       std::string arg = args(0).xstring_value ("dbstep: input argument must be a string");
@@ -1090,14 +1117,14 @@
           Vdebugging = false;
           Vtrack_line_num = true;
 
-          octave::tree_evaluator::dbstep_flag = -1;
+          tw.set_dbstep_flag (-1);
         }
       else if (arg == "out")
         {
           Vdebugging = false;
           Vtrack_line_num = true;
 
-          octave::tree_evaluator::dbstep_flag = -2;
+          tw.set_dbstep_flag (-2);
         }
       else
         {
@@ -1109,7 +1136,7 @@
           Vdebugging = false;
           Vtrack_line_num = true;
 
-          octave::tree_evaluator::dbstep_flag = n;
+          tw.set_dbstep_flag (n);
         }
     }
   else
@@ -1117,7 +1144,7 @@
       Vdebugging = false;
       Vtrack_line_num = true;
 
-      octave::tree_evaluator::dbstep_flag = 1;
+      tw.set_dbstep_flag (1);
     }
 
   return ovl ();
@@ -1125,8 +1152,8 @@
 
 DEFALIAS (dbnext, dbstep);
 
-DEFUN (dbcont, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbcont, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {} dbcont
 Leave command-line debugging mode and continue code execution normally.
 @seealso{dbstep, dbquit}
@@ -1141,13 +1168,15 @@
   Vdebugging = false;
   Vtrack_line_num = true;
 
-  octave::tree_evaluator::reset_debug_state ();
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.reset_debug_state ();
 
   return ovl ();
 }
 
-DEFUN (dbquit, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (dbquit, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {} dbquit
 Quit debugging mode immediately without further code execution and return to
 the Octave prompt.
@@ -1164,8 +1193,9 @@
 
   Vdebugging = false;
 
-  octave::tree_evaluator::reset_debug_state ();
-  octave::tree_evaluator::debug_mode = false;
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.reset_debug_state (false);
 
   throw octave::interrupt_exception ();
 
@@ -1185,8 +1215,8 @@
   return ovl (Vdebugging);
 }
 
-DEFUN (__db_next_breakpoint_quiet__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__db_next_breakpoint_quiet__, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} __db_next_breakpoint_quiet__ ()
 @deftypefnx {} {} __db_next_breakpoint_quiet__ (@var{flag})
 Disable line info printing at the next breakpoint.
@@ -1204,7 +1234,9 @@
   if (nargin == 1)
     state = args(0).bool_value ();
 
-  octave::tree_evaluator::quiet_breakpoint_flag = state;
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.quiet_breakpoint_flag (state);
 
   return ovl ();
 }
--- a/libinterp/corefcn/default-defs.in.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/default-defs.in.h	Thu Dec 20 17:18:56 2018 -0500
@@ -24,10 +24,6 @@
 // These are used by functions declared in defaults.h and defined in
 // defaults.cc.
 
-#if ! defined (OCTAVE_CANONICAL_HOST_TYPE)
-#  define OCTAVE_CANONICAL_HOST_TYPE %OCTAVE_CANONICAL_HOST_TYPE%
-#endif
-
 #if ! defined (OCTAVE_RELEASE)
 #  define OCTAVE_RELEASE %OCTAVE_RELEASE%
 #endif
--- a/libinterp/corefcn/defaults.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/defaults.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,6 @@
 #include <cstdlib>
 
 #include <algorithm>
-#include <iostream>
 #include <string>
 
 #include "dir-ops.h"
@@ -45,278 +44,408 @@
 
 #include "default-defs.h"
 
-static bool initialized = false;
-
-static std::string Voctave_home;
-static std::string Voctave_exec_home;
-
-static std::string Vbin_dir;
-static std::string Vdata_dir;
-static std::string Vdataroot_dir;
-static std::string Vinclude_dir;
-static std::string Vlib_dir;
-static std::string Vlibexec_dir;
-
-static std::string Vlocal_ver_arch_lib_dir;
-static std::string Vlocal_api_arch_lib_dir;
-static std::string Vlocal_arch_lib_dir;
-static std::string Varch_lib_dir;
-
-static std::string Vlocal_ver_oct_file_dir;
-static std::string Vlocal_api_oct_file_dir;
-static std::string Vlocal_oct_file_dir;
-static std::string Voct_file_dir;
-
-static std::string Vlocal_ver_fcn_file_dir;
-static std::string Vlocal_api_fcn_file_dir;
-static std::string Vlocal_fcn_file_dir;
-static std::string Vfcn_file_dir;
-
-static std::string Voct_data_dir;
-static std::string Voct_doc_dir;
-static std::string Voct_etc_dir;
-static std::string Voct_fonts_dir;
-static std::string Voct_include_dir;
-static std::string Voct_lib_dir;
-static std::string Voct_locale_dir;
-static std::string Voct_tests_dir;
-
-static std::string Vinfo_dir;
-
-static std::string Vman_dir;
-static std::string Vman1_dir;
-static std::string Vman1_ext;
-
-static std::string Vimage_dir;
-
-static std::string Vlocal_startupfile_dir;
-static std::string Vstartupfile_dir;
-
-static std::string Vlocal_site_defaults_file;
-static std::string Vsite_defaults_file;
-
-// Variables that name directories or files are substituted into source
-// files with "${prefix}/" stripped from the beginning of the string.
-
-// All configure variables of this form should be specified as absolute
-// directory names.  The only ones that should not be absolute here are
-// ones that have had "${prefix}/" or "${exec_prefix} stripped.
-
-static std::string
-prepend_home_dir (const std::string& hd, const std::string& s)
-{
-  std::string retval = s;
-
-  char dir_sep_char = octave::sys::file_ops::dir_sep_char ();
-
-  if (! octave::sys::env::absolute_pathname (retval))
-    retval = hd + dir_sep_char + s;
-
-  if (dir_sep_char != '/')
-    std::replace (retval.begin (), retval.end (), '/', dir_sep_char);
-
-  return retval;
-}
-
-static void
-set_octave_home (void)
-{
-  std::string op = OCTAVE_PREFIX;
-  std::string oep = OCTAVE_EXEC_PREFIX;
-
-  std::string oh = octave::sys::env::getenv ("OCTAVE_HOME");
-  std::string oeh = octave::sys::env::getenv ("OCTAVE_EXEC_HOME");
-
-  // If OCTAVE_HOME is set in the enviornment, use that.  Otherwise,
-  // default to ${prefix} from configure.
-
-  Voctave_home = (oh.empty () ? op : oh);
-
-  // If OCTAVE_EXEC_HOME is set in the environment, use that.
-  // Otherwise, if ${prefix} and ${exec_prefix} from configure are set
-  // to the same value, use OCTAVE_HOME from the environment if it is set.
-  // Othewise, default to ${exec_prefix} from configure.
-
-  if (! oeh.empty ())
-    Voctave_exec_home = oeh;
-  else
-    {
-      if (op == oep && ! oh.empty ())
-        Voctave_exec_home = oh;
-      else
-        Voctave_exec_home = oep;
-    }
-}
-
-static void
-set_local_site_defaults_file (void)
-{
-  std::string lsf = octave::sys::env::getenv ("OCTAVE_SITE_INITFILE");
-
-  if (lsf.empty ())
-    Vlocal_site_defaults_file = Vlocal_startupfile_dir + "/octaverc";
-  else
-    Vlocal_site_defaults_file = lsf;
-}
-
-static void
-set_site_defaults_file (void)
-{
-  std::string sf = octave::sys::env::getenv ("OCTAVE_VERSION_INITFILE");
-
-  if (sf.empty ())
-    Vsite_defaults_file = Vstartupfile_dir + "/octaverc";
-  else
-    Vsite_defaults_file = sf;
-}
-
-static void
-init_defaults (void)
-{
-  if (initialized)
-    return;
-
-  // OCTAVE_HOME must be set first!
-
-  set_octave_home ();
-
-  Vbin_dir = octave::config::prepend_octave_exec_home (OCTAVE_BINDIR);
-  Vdata_dir = octave::config::prepend_octave_home (OCTAVE_DATADIR);
-  Vdataroot_dir = octave::config::prepend_octave_home (OCTAVE_DATAROOTDIR);
-  Vinclude_dir = octave::config::prepend_octave_home (OCTAVE_INCLUDEDIR);
-  Vlib_dir = octave::config::prepend_octave_exec_home (OCTAVE_LIBDIR);
-  Vlibexec_dir = octave::config::prepend_octave_exec_home (OCTAVE_LIBEXECDIR);
-
-  Vlocal_ver_arch_lib_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALVERARCHLIBDIR);
-  Vlocal_api_arch_lib_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALAPIARCHLIBDIR);
-  Vlocal_arch_lib_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALARCHLIBDIR);
-  Varch_lib_dir = octave::config::prepend_octave_exec_home (OCTAVE_ARCHLIBDIR);
-
-  Vlocal_ver_oct_file_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALVEROCTFILEDIR);
-  Vlocal_api_oct_file_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALAPIOCTFILEDIR);
-  Vlocal_oct_file_dir
-    = octave::config::prepend_octave_exec_home (OCTAVE_LOCALOCTFILEDIR);
-  Voct_file_dir = octave::config::prepend_octave_exec_home (OCTAVE_OCTFILEDIR);
-
-  Vlocal_ver_fcn_file_dir
-    = octave::config::prepend_octave_home (OCTAVE_LOCALVERFCNFILEDIR);
-  Vlocal_api_fcn_file_dir
-    = octave::config::prepend_octave_home (OCTAVE_LOCALAPIFCNFILEDIR);
-  Vlocal_fcn_file_dir
-    = octave::config::prepend_octave_home (OCTAVE_LOCALFCNFILEDIR);
-  Vfcn_file_dir = octave::config::prepend_octave_home (OCTAVE_FCNFILEDIR);
-
-  Voct_data_dir = octave::config::prepend_octave_home (OCTAVE_OCTDATADIR);
-  Voct_doc_dir = octave::config::prepend_octave_home (OCTAVE_OCTDOCDIR);
-  Voct_etc_dir = octave::config::prepend_octave_home (OCTAVE_OCTETCDIR);
-  Voct_fonts_dir = octave::config::prepend_octave_home (OCTAVE_OCTFONTSDIR);
-  Voct_include_dir = octave::config::prepend_octave_home (OCTAVE_OCTINCLUDEDIR);
-  Voct_lib_dir = octave::config::prepend_octave_exec_home (OCTAVE_OCTLIBDIR);
-  Voct_locale_dir = octave::config::prepend_octave_home (OCTAVE_OCTLOCALEDIR);
-  Voct_tests_dir = octave::config::prepend_octave_home (OCTAVE_OCTTESTSDIR);
-
-  Vinfo_dir = octave::config::prepend_octave_home (OCTAVE_INFODIR);
-
-  Vman_dir = octave::config::prepend_octave_home (OCTAVE_MANDIR);
-  Vman1_dir = octave::config::prepend_octave_home (OCTAVE_MAN1DIR);
-  Vman1_ext = OCTAVE_MAN1EXT;
-
-  Vimage_dir = octave::config::prepend_octave_home (OCTAVE_IMAGEDIR);
-
-  Vlocal_startupfile_dir
-    = octave::config::prepend_octave_home (OCTAVE_LOCALSTARTUPFILEDIR);
-  Vstartupfile_dir
-    = octave::config::prepend_octave_home (OCTAVE_STARTUPFILEDIR);
-
-  set_local_site_defaults_file ();
-
-  set_site_defaults_file ();
-
-  initialized = true;
-}
-
-#define RETURN(VAR)                             \
-  if (! initialized)                            \
-    init_defaults ();                           \
-  return VAR;
-
 namespace octave
 {
   namespace config
   {
-    std::string
-    prepend_octave_home (const std::string& s)
+    // Variables that name directories or files are substituted into source
+    // files with "${prefix}/" stripped from the beginning of the string.
+
+    // All configure variables of this form should be specified as absolute
+    // directory names.  The only ones that should not be absolute here are
+    // ones that have had "${prefix}/" or "${exec_prefix} stripped.
+
+    static std::string
+    prepend_home_dir (const std::string& hd, const std::string& s)
+    {
+      std::string retval = s;
+
+      char dir_sep_char = sys::file_ops::dir_sep_char ();
+
+      if (! sys::env::absolute_pathname (retval))
+        retval = hd + dir_sep_char + s;
+
+      if (dir_sep_char != '/')
+        std::replace (retval.begin (), retval.end (), '/', dir_sep_char);
+
+      return retval;
+    }
+
+    static std::string get_octave_home (void)
+    {
+      std::string op = OCTAVE_PREFIX;
+
+      std::string oh = sys::env::getenv ("OCTAVE_HOME");
+
+      // If OCTAVE_HOME is set in the enviornment, use that.  Otherwise,
+      // default to ${prefix} from configure.
+
+      return oh.empty () ? op : oh;
+    }
+
+    static std::string get_octave_exec_home (void)
     {
-      return prepend_home_dir (Voctave_home, s);
+      std::string op = OCTAVE_PREFIX;
+      std::string oep = OCTAVE_EXEC_PREFIX;
+
+      std::string oh = sys::env::getenv ("OCTAVE_HOME");
+      std::string oeh = sys::env::getenv ("OCTAVE_EXEC_HOME");
+
+      // If OCTAVE_EXEC_HOME is set in the environment, use that.
+      // Otherwise, if ${prefix} and ${exec_prefix} from configure are set
+      // to the same value, use OCTAVE_HOME from the environment if it is set.
+      // Othewise, default to ${exec_prefix} from configure.
+
+      if (! oeh.empty ())
+        return oeh;
+
+      if (op == oep && ! oh.empty ())
+        return oh;
+
+      return oep;
+    }
+
+    static std::string get_local_site_defaults_file (void)
+    {
+      std::string lsf = sys::env::getenv ("OCTAVE_SITE_INITFILE");
+
+      return lsf.empty () ? local_startupfile_dir () + "/octaverc" : lsf;
+    }
+
+    static std::string get_site_defaults_file (void)
+    {
+      std::string sf = sys::env::getenv ("OCTAVE_VERSION_INITFILE");
+
+      return sf.empty () ? startupfile_dir () + "/octaverc" : sf;
+    }
+
+    std::string prepend_octave_home (const std::string& s)
+    {
+      return prepend_home_dir (octave_home (), s);
+    }
+
+    std::string prepend_octave_exec_home (const std::string& s)
+    {
+      return prepend_home_dir (octave_exec_home (), s);
+    }
+
+    std::string canonical_host_type (void)
+    {
+      static const std::string s_canonical_host_type
+        = OCTAVE_CANONICAL_HOST_TYPE;
+
+      return s_canonical_host_type;
+    }
+
+    std::string release (void)
+    {
+      static const std::string s_octave_release = OCTAVE_RELEASE;
+
+      return s_octave_release;
     }
 
-    std::string
-    prepend_octave_exec_home (const std::string& s)
+    std::string default_pager (void)
+    {
+      static const std::string s_default_pager = OCTAVE_DEFAULT_PAGER;
+
+      return s_default_pager;
+    }
+
+    std::string octave_home (void)
+    {
+      static const std::string s_octave_home = get_octave_home ();
+
+      return s_octave_home;
+    }
+
+    std::string octave_exec_home (void)
+    {
+      static const std::string s_octave_exec_home = get_octave_exec_home ();
+
+      return s_octave_exec_home;
+    }
+
+    std::string bin_dir (void)
+    {
+      static const std::string s_bin_dir
+        = prepend_octave_exec_home (OCTAVE_BINDIR);
+
+      return s_bin_dir;
+    }
+
+    std::string data_dir (void)
+    {
+      static const std::string s_data_dir
+        = prepend_octave_home (OCTAVE_DATADIR);
+
+      return s_data_dir;
+    }
+
+    std::string dataroot_dir (void)
+    {
+      static const std::string s_dataroot_dir
+        = prepend_octave_home (OCTAVE_DATAROOTDIR);
+
+      return s_dataroot_dir;
+    }
+
+    std::string include_dir (void)
     {
-      return prepend_home_dir (Voctave_exec_home, s);
+      static const std::string s_include_dir
+        = prepend_octave_home (OCTAVE_INCLUDEDIR);
+
+      return s_include_dir;
+    }
+
+    std::string lib_dir (void)
+    {
+      static const std::string s_lib_dir
+        = prepend_octave_exec_home (OCTAVE_LIBDIR);
+
+      return s_lib_dir;
+    }
+
+    std::string libexec_dir (void)
+    {
+      static const std::string s_libexec_dir
+        = prepend_octave_exec_home (OCTAVE_LIBEXECDIR);
+
+      return s_libexec_dir;
+    }
+
+    std::string arch_lib_dir (void)
+    {
+      static const std::string s_arch_lib_dir
+        = prepend_octave_exec_home (OCTAVE_ARCHLIBDIR);
+
+      return s_arch_lib_dir;
+    }
+
+    std::string info_dir (void)
+    {
+      static const std::string s_info_dir
+        = prepend_octave_exec_home (OCTAVE_INFODIR);
+
+      return s_info_dir;
+    }
+
+    std::string local_ver_arch_lib_dir (void)
+    {
+      static const std::string s_local_ver_arch_lib_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALVERARCHLIBDIR);
+
+      return s_local_ver_arch_lib_dir;
+    }
+
+    std::string local_api_arch_lib_dir (void)
+    {
+      static const std::string s_local_api_arch_lib_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALAPIARCHLIBDIR);
+
+      return s_local_api_arch_lib_dir;
     }
 
-    std::string canonical_host_type (void) { return OCTAVE_CANONICAL_HOST_TYPE; }
+    std::string local_arch_lib_dir (void)
+    {
+      static const std::string s_local_arch_lib_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALARCHLIBDIR);
+
+      return s_local_arch_lib_dir;
+    }
 
-    std::string release (void) { return OCTAVE_RELEASE; }
+    std::string local_ver_oct_file_dir (void)
+    {
+      static const std::string s_local_ver_oct_file_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALVEROCTFILEDIR);
+
+      return s_local_ver_oct_file_dir;
+    }
+
+    std::string local_api_oct_file_dir (void)
+    {
+      static const std::string s_local_api_oct_file_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALAPIOCTFILEDIR);
+
+      return s_local_api_oct_file_dir;
+    }
 
-    std::string default_pager (void) { return OCTAVE_DEFAULT_PAGER; }
+    std::string local_oct_file_dir (void)
+    {
+      static const std::string s_local_oct_file_dir
+        = prepend_octave_exec_home (OCTAVE_LOCALOCTFILEDIR);
+
+      return s_local_oct_file_dir;
+    }
 
-    std::string octave_home (void) { RETURN (Voctave_home); }
-    std::string octave_exec_home (void) { RETURN (Voctave_exec_home); }
+    std::string oct_file_dir (void)
+    {
+      static const std::string s_oct_file_dir
+        = prepend_octave_exec_home (OCTAVE_OCTFILEDIR);
+
+      return s_oct_file_dir;
+    }
+
+    std::string local_ver_fcn_file_dir (void)
+    {
+      static const std::string s_local_ver_fcn_file_dir
+        = prepend_octave_home (OCTAVE_LOCALVERFCNFILEDIR);
+
+      return s_local_ver_fcn_file_dir;
+    }
 
-    std::string bin_dir (void) { RETURN (Vbin_dir); }
-    std::string data_dir (void) { RETURN (Vdata_dir); }
-    std::string dataroot_dir (void) { RETURN (Vdataroot_dir); }
-    std::string include_dir (void) { RETURN (Vinclude_dir); }
-    std::string lib_dir (void) { RETURN (Vlib_dir); }
-    std::string libexec_dir (void) { RETURN (Vlibexec_dir); }
-    std::string arch_lib_dir (void) { RETURN (Varch_lib_dir); }
-    std::string info_dir (void) { RETURN (Vinfo_dir); }
+    std::string local_api_fcn_file_dir (void)
+    {
+      static const std::string s_local_api_fcn_file_dir
+        = prepend_octave_home (OCTAVE_LOCALAPIFCNFILEDIR);
+
+      return s_local_api_fcn_file_dir;
+    }
+
+    std::string local_fcn_file_dir (void)
+    {
+      static const std::string s_local_fcn_file_dir
+        = prepend_octave_home (OCTAVE_LOCALFCNFILEDIR);
+
+      return s_local_fcn_file_dir;
+    }
+
+    std::string fcn_file_dir (void)
+    {
+      static const std::string s_fcn_file_dir
+        = prepend_octave_home (OCTAVE_FCNFILEDIR);
+
+      return s_fcn_file_dir;
+    }
 
-    std::string local_ver_arch_lib_dir (void) { RETURN (Vlocal_ver_arch_lib_dir); }
-    std::string local_api_arch_lib_dir (void) { RETURN (Vlocal_api_arch_lib_dir); }
-    std::string local_arch_lib_dir (void) { RETURN (Vlocal_arch_lib_dir); }
+    std::string oct_data_dir (void)
+    {
+      static const std::string s_oct_data_dir
+        = prepend_octave_home (OCTAVE_OCTDATADIR);
+
+      return s_oct_data_dir;
+    }
+
+    std::string oct_doc_dir (void)
+    {
+      static const std::string s_oct_doc_dir
+        = prepend_octave_home (OCTAVE_OCTDOCDIR);
+
+      return s_oct_doc_dir;
+    }
+
+    std::string oct_etc_dir (void)
+    {
+      static const std::string s_oct_etc_dir
+        = prepend_octave_home (OCTAVE_OCTETCDIR);
+
+      return s_oct_etc_dir;
+    }
 
-    std::string local_ver_oct_file_dir (void) { RETURN (Vlocal_ver_oct_file_dir); }
-    std::string local_api_oct_file_dir (void) { RETURN (Vlocal_api_oct_file_dir); }
-    std::string local_oct_file_dir (void) { RETURN (Vlocal_oct_file_dir); }
-    std::string oct_file_dir (void) { RETURN (Voct_file_dir); }
+    std::string oct_fonts_dir (void)
+    {
+      static const std::string s_oct_fonts_dir
+        = prepend_octave_home (OCTAVE_OCTFONTSDIR);
+
+      return s_oct_fonts_dir;
+    }
+
+    std::string oct_include_dir (void)
+    {
+      static const std::string s_oct_include_dir
+        = prepend_octave_home (OCTAVE_OCTINCLUDEDIR);
+
+      return s_oct_include_dir;
+    }
+
+    std::string oct_lib_dir (void)
+    {
+      static const std::string s_oct_lib_dir
+        = prepend_octave_exec_home (OCTAVE_OCTLIBDIR);
+
+      return s_oct_lib_dir;
+    }
 
-    std::string local_ver_fcn_file_dir (void) { RETURN (Vlocal_ver_fcn_file_dir); }
-    std::string local_api_fcn_file_dir (void) { RETURN (Vlocal_api_fcn_file_dir); }
-    std::string local_fcn_file_dir (void) { RETURN (Vlocal_fcn_file_dir); }
-    std::string fcn_file_dir (void) { RETURN (Vfcn_file_dir); }
+    std::string oct_locale_dir (void)
+    {
+      static const std::string s_oct_locale_dir
+        = prepend_octave_home (OCTAVE_OCTLOCALEDIR);
+
+      return s_oct_locale_dir;
+    }
+
+    std::string oct_tests_dir (void)
+    {
+      static const std::string s_oct_tests_dir
+        = prepend_octave_home (OCTAVE_OCTTESTSDIR);
+
+      return s_oct_tests_dir;
+    }
+
+    std::string man_dir (void)
+    {
+      static const std::string s_man_dir
+        = prepend_octave_home (OCTAVE_MANDIR);
+
+      return s_man_dir;
+    }
 
-    std::string oct_data_dir (void) { RETURN (Voct_data_dir); }
-    std::string oct_doc_dir (void) { RETURN (Voct_doc_dir); }
-    std::string oct_etc_dir (void) { RETURN (Voct_etc_dir); }
-    std::string oct_fonts_dir (void) { RETURN (Voct_fonts_dir); }
-    std::string oct_include_dir (void) { RETURN (Voct_include_dir); }
-    std::string oct_lib_dir (void) { RETURN (Voct_lib_dir); }
-    std::string oct_locale_dir (void) { RETURN (Voct_locale_dir); }
-    std::string oct_tests_dir (void) { RETURN (Voct_tests_dir); }
+    std::string man1_dir (void)
+    {
+      static const std::string s_man1_dir
+        = prepend_octave_home (OCTAVE_MAN1DIR);
+
+      return s_man1_dir;
+    }
+
+    std::string man1_ext (void)
+    {
+      static const std::string s_man1_ext = OCTAVE_MAN1EXT;
+
+      return s_man1_ext;
+    }
+
+    std::string image_dir (void)
+    {
+      static const std::string s_image_dir
+        = prepend_octave_home (OCTAVE_IMAGEDIR);
+
+      return s_image_dir;
+    }
 
-    std::string man_dir (void) { RETURN (Vman_dir); }
-    std::string man1_dir (void) { RETURN (Vman1_dir); }
-    std::string man1_ext (void) { RETURN (Vman1_ext); }
+    std::string local_startupfile_dir (void)
+    {
+      static const std::string s_local_startupfile_dir
+        = prepend_octave_home (OCTAVE_LOCALSTARTUPFILEDIR);
+
+      return s_local_startupfile_dir;
+    }
 
-    std::string image_dir (void) { RETURN (Vimage_dir); }
+    std::string startupfile_dir (void)
+    {
+      static const std::string s_startupfile_dir
+        = prepend_octave_home (OCTAVE_STARTUPFILEDIR);
+
+      return s_startupfile_dir;
+    }
 
-    std::string local_startupfile_dir (void) { RETURN (Vlocal_startupfile_dir); }
-    std::string startupfile_dir (void) { RETURN (Vstartupfile_dir); }
+    std::string local_site_defaults_file (void)
+    {
+      static const std::string s_local_site_defaults_file
+        = get_local_site_defaults_file ();
+
+      return s_local_site_defaults_file;
+    }
 
-    std::string local_site_defaults_file (void) { RETURN (Vlocal_site_defaults_file); }
-    std::string site_defaults_file (void) { RETURN (Vsite_defaults_file); }
+    std::string site_defaults_file (void)
+    {
+      static const std::string s_site_defaults_file
+        = get_site_defaults_file ();
+
+      return s_site_defaults_file;
+    }
   }
 }
 
-#undef RETURN
 
 DEFUN (OCTAVE_HOME, args, ,
        doc: /* -*- texinfo -*-
--- a/libinterp/corefcn/defun.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/defun.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <sstream>
-#include <iostream>
 #include <string>
 
 #include "call-stack.h"
--- a/libinterp/corefcn/dirfns.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/dirfns.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -187,16 +187,16 @@
 
   dirname = octave::sys::file_ops::tilde_expand (dirname);
 
-  octave::sys::dir_entry dir (dirname);
+  string_vector dirlist;
+  std::string msg;
 
-  if (dir)
+  if (octave::sys::get_dirlist (dirname, dirlist, msg))
     {
-      string_vector dirlist = dir.read ();
       retval(0) = Cell (dirlist.sort ());
       retval(1) = 0.0;
     }
   else
-    retval(2) = dir.error ();
+    retval(2) = msg;
 
   return retval;
 }
@@ -250,8 +250,8 @@
     }
 }
 
-DEFUNX ("rmdir", Frmdir, args, ,
-        doc: /* -*- texinfo -*-
+DEFMETHODX ("rmdir", Frmdir, interp, args, ,
+            doc: /* -*- texinfo -*-
 @deftypefn  {} {} rmdir @var{dir}
 @deftypefnx {} {} rmdir (@var{dir}, "s")
 @deftypefnx {} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@dots{})
@@ -290,16 +290,26 @@
           && ! octave::application::forced_interactive ()
           && Vconfirm_recursive_rmdir)
         {
+          octave::input_system& input_sys = interp.get_input_system ();
+
           std::string prompt = "remove entire contents of " + fulldir + "? ";
 
-          doit = octave_yes_or_no (prompt);
+          doit = input_sys.yes_or_no (prompt);
         }
 
       if (doit)
-        status = octave::sys::recursive_rmdir (fulldir, msg);
+        {
+          octave_link::file_remove (fulldir, "");
+          status = octave::sys::recursive_rmdir (fulldir, msg);
+        }
     }
   else
-    status = octave::sys::rmdir (fulldir, msg);
+    {
+      octave_link::file_remove (fulldir, "");
+      status = octave::sys::rmdir (fulldir, msg);
+    }
+
+  octave_link::file_renamed (status >= 0);
 
   if (status < 0)
     return ovl (false, msg, "rmdir");
@@ -422,12 +432,20 @@
 
   std::string msg;
 
+  octave_link::file_remove (from, to);
+
   int status = octave::sys::rename (from, to, msg);
 
   if (status < 0)
-    return ovl (-1.0, msg);
+    {
+      octave_link::file_renamed (false);
+      return ovl (-1.0, msg);
+    }
   else
-    return ovl (status, "");
+    {
+      octave_link::file_renamed (true);
+      return ovl (status, "");
+    }
 }
 
 DEFUN (glob, args, ,
--- a/libinterp/corefcn/dlmread.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/dlmread.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,12 +28,14 @@
 #  include "config.h"
 #endif
 
+#include <cmath>
 #include <cctype>
 #include <fstream>
 #include <limits>
 
 #include "file-ops.h"
 #include "lo-ieee.h"
+#include "lo-sysdep.h"
 
 #include "defun.h"
 #include "interpreter.h"
@@ -190,7 +192,7 @@
 The @qcode{"emptyvalue"} option may be used to specify the value used to
 fill empty fields.  The default is zero.  Note that any non-numeric values,
 such as text, are also replaced by the @qcode{"emptyvalue"}.
-@seealso{csvread, textscan, textread, dlmwrite}
+@seealso{csvread, textscan, dlmwrite}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -218,9 +220,11 @@
 
       std::string tname = octave::sys::file_ops::tilde_expand (fname);
 
-      tname = find_data_file_in_load_path ("dlmread", tname);
+      tname = octave::find_data_file_in_load_path ("dlmread", tname);
 
-      input_file.open (tname.c_str (), std::ios::in);
+      std::string ascii_fname = octave::sys::get_ASCII_filename (tname);
+
+      input_file.open (ascii_fname.c_str (), std::ios::in);
 
       if (! input_file)
         error ("dlmread: unable to open file '%s'", fname.c_str ());
@@ -246,7 +250,7 @@
   if (nargin > 1)
     {
       if (args(1).is_sq_string ())
-        sep = do_string_escapes (args(1).string_value ());
+        sep = octave::do_string_escapes (args(1).string_value ());
       else
         sep = args(1).string_value ();
     }
@@ -442,17 +446,33 @@
                 }
               else
                 {
-                  int next_char = std::tolower (tmp_stream.peek ());
-                  if (next_char == 'i' || next_char == 'j')
+                  int next_char = tmp_stream.peek ();
+                  if (next_char == 'i' || next_char == 'j'
+                      || next_char == 'I' || next_char == 'J')
                     {
                       // Process pure imaginary numbers.
-                      if (! iscmplx)
+                      tmp_stream.get ();
+                      next_char = tmp_stream.peek ();
+                      if (next_char == std::istringstream::traits_type::eof ())
                         {
-                          iscmplx = true;
-                          cdata = ComplexMatrix (rdata);
+                          if (! iscmplx)
+                            {
+                              iscmplx = true;
+                              cdata = ComplexMatrix (rdata);
+                            }
+
+                          cdata(i,j++) = Complex (0, x);
                         }
-
-                      cdata(i,j++) = Complex (0, x);
+                      else
+                        {
+                          // Parsing failed, <number>i|j<extra text>
+                          j++;  // Leave data initialized to empty_value
+                        }
+                    }
+                  else if (std::isalpha (next_char) && ! std::isfinite (x))
+                    {
+                      // Parsing failed, <Inf|NA|NaN><extra text>
+                      j++;  // Leave data initialized to empty_value
                     }
                   else
                     {
@@ -471,10 +491,11 @@
                     }
                 }
             }
-          else if (iscmplx)
-            cdata(i,j++) = empty_value;
           else
-            rdata(i,j++) = empty_value;
+            {
+              // octave_read_double() parsing failed
+              j++;  // Leave data initialized to empty_value
+            }
 
           pos1 = pos2 + 1;
         }
@@ -631,4 +652,56 @@
 %!   unlink (file);
 %! end_unwind_protect
 
+## NA was not properly read from a file
+%!test
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, "1,NA,3");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [1, NA, 3]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
+## "Name" was read as NA rather than parse error
+%!test <*54029>
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, "NaNe,bNa,Name,c\n1,NaN,3,Inftest\n-Inf,6,NA,8");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [0, 0, 0, 0; 1, NaN, 3, 0; -Inf, 6, NA, 8]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
+## Infinity incorrectly changed matrix to complex, rather than parse error
+%!test
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, "1,Infinity,3");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [1, 0, 3]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
+## Purely complex numbers with trailing garbage produced complex matrix
+%!test
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, "1,2jack,3");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [1, 0, 3]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
 */
--- a/libinterp/corefcn/dynamic-ld.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/dynamic-ld.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,7 +31,6 @@
 #include "oct-env.h"
 #include "oct-time.h"
 
-#include "defaults.h"
 #include "defun.h"
 #include "dynamic-ld.h"
 #include "interpreter-private.h"
@@ -60,7 +59,7 @@
   {
     std::list<std::string> removed_fcns;
 
-    for (iterator p = m_lib_list.begin (); p != m_lib_list.end (); p++)
+    for (auto p = m_lib_list.begin (); p != m_lib_list.end (); p++)
       {
         if (*p == shl)
           {
--- a/libinterp/corefcn/environment.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/environment.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -105,7 +105,7 @@
   {
     std::string retval = "emacs";
 
-    std::string env_editor = octave::sys::env::getenv ("EDITOR");
+    std::string env_editor = sys::env::getenv ("EDITOR");
 
     if (! env_editor.empty ())
       retval = env_editor;
@@ -115,9 +115,9 @@
 
   std::string environment::init_exec_path (void)
   {
-    std::string exec_path = octave::sys::env::getenv ("OCTAVE_EXEC_PATH");
+    std::string exec_path = sys::env::getenv ("OCTAVE_EXEC_PATH");
 
-    std::string path_sep = octave::directory_path::path_sep_str ();
+    std::string path_sep = directory_path::path_sep_str ();
 
     if (exec_path.empty ())
       exec_path = (config::local_ver_arch_lib_dir () + path_sep
@@ -135,14 +135,14 @@
   {
     std::string image_path = ".";
 
-    std::string path_sep = octave::directory_path::path_sep_str ();
+    std::string path_sep = directory_path::path_sep_str ();
 
-    std::string env_path = octave::sys::env::getenv ("OCTAVE_IMAGE_PATH");
+    std::string env_path = sys::env::getenv ("OCTAVE_IMAGE_PATH");
 
     if (! env_path.empty ())
       image_path += path_sep + env_path;
 
-    std::string gen_path = octave::genpath (config::image_dir (), "");
+    std::string gen_path = genpath (config::image_dir (), "");
 
     if (! gen_path.empty ())
       image_path += path_sep + gen_path;
--- a/libinterp/corefcn/error.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/error.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -166,7 +166,7 @@
 
   std::ostringstream output_buf;
 
-  octave_vformat (output_buf, fmt, args);
+  octave::vformat (output_buf, fmt, args);
 
   std::string base_msg = output_buf.str ();
 
@@ -368,9 +368,11 @@
       frame.protect_var (Vdebug_on_error);
       Vdebug_on_error = false;
 
-      octave::tree_evaluator::debug_mode = true;
+      octave::tree_evaluator& tw
+        = octave::__get_evaluator__ ("maybe_enter_debugger");
 
-      octave::tree_evaluator::current_frame = cs.current_frame ();
+      tw.debug_mode (true);
+      tw.current_frame (cs.current_frame ());
 
       if (show_stack_trace)
         {
@@ -384,7 +386,10 @@
             }
         }
 
-      do_keyboard (octave_value_list ());
+      octave::input_system& input_sys
+        = octave::__get_input_system__ ("maybe_enter_debugger");
+
+      input_sys.keyboard ();
     }
 }
 
@@ -400,7 +405,7 @@
 
   std::ostringstream output_buf;
 
-  octave_vformat (output_buf, fmt, args);
+  octave::vformat (output_buf, fmt, args);
 
   // FIXME: we really want to capture the message before it has all the
   //        formatting goop attached to it.  We probably also want just the
@@ -478,21 +483,6 @@
 }
 
 void
-vusage (const char *fmt, va_list args)
-{
-  usage_1 ("", fmt, args);
-}
-
-void
-usage (const char *fmt, ...)
-{
-  va_list args;
-  va_start (args, fmt);
-  usage_1 ("", fmt, args);
-  va_end (args);
-}
-
-void
 vusage_with_id (const char *id, const char *fmt, va_list args)
 {
   usage_1 (id, fmt, args);
@@ -782,11 +772,16 @@
           frame.protect_var (Vdebug_on_warning);
           Vdebug_on_warning = false;
 
-          octave::tree_evaluator::debug_mode = true;
+          octave::tree_evaluator& tw
+            = octave::__get_evaluator__ ("warning_1");
 
-          octave::tree_evaluator::current_frame = cs.current_frame ();
+          tw.debug_mode (true);
+          tw.current_frame (cs.current_frame ());
 
-          do_keyboard (octave_value_list ());
+          octave::input_system& input_sys
+            = octave::__get_input_system__ ("warning_1");
+
+          input_sys.keyboard ();
         }
     }
 }
--- a/libinterp/corefcn/error.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/error.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
 #include "octave-config.h"
 
 #include <cstdarg>
+#include <cinttypes>
 #include <string>
 
 #include "unwind-prot.h"
@@ -50,37 +51,38 @@
 extern OCTINTERP_API void
 vmessage (const char *name, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 extern OCTINTERP_API void message (const char *name, const char *fmt, ...);
 
-OCTAVE_DEPRECATED (4.2, "use 'print_usage' or 'verror' instead")
-OCTAVE_NORETURN OCTINTERP_API extern
-void vusage (const char *fmt, va_list args);
-
-OCTAVE_DEPRECATED (4.2, "use 'print_usage' or 'error' instead")
-OCTAVE_NORETURN OCTINTERP_API extern
-void usage (const char *fmt, ...);
-
 extern OCTINTERP_API void vwarning (const char *fmt, va_list args);
+OCTAVE_FORMAT_PRINTF (1, 2)
 extern OCTINTERP_API void warning (const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void verror (const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (1, 2)
 OCTAVE_NORETURN OCTINTERP_API extern
 void error (const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void verror (octave::execution_exception&, const char *fmt, va_list args);
+
+OCTAVE_FORMAT_PRINTF (2, 3)
 OCTAVE_NORETURN OCTINTERP_API extern
 void error (octave::execution_exception&, const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void verror_with_cfn (const char *fmt, va_list args);
+
+OCTAVE_FORMAT_PRINTF (1, 2)
 OCTAVE_NORETURN OCTINTERP_API extern
 void error_with_cfn (const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void vparse_error (const char *fmt, va_list args);
+
+OCTAVE_FORMAT_PRINTF (1, 2)
 OCTAVE_NORETURN OCTINTERP_API extern
 void parse_error (const char *fmt, ...);
 
@@ -88,43 +90,51 @@
 vmessage_with_id (const char *id, const char *name,
                   const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (3, 4)
 extern OCTINTERP_API void
 message_with_id (const char *id, const char *name, const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void vusage_with_id (const char *id, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 OCTAVE_NORETURN OCTINTERP_API extern
 void usage_with_id (const char *id, const char *fmt, ...);
 
 extern OCTINTERP_API void
 vwarning_with_id (const char *id, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 extern OCTINTERP_API void
 warning_with_id (const char *id, const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void verror_with_id (const char *id, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 OCTAVE_NORETURN OCTINTERP_API extern
 void error_with_id (const char *id, const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void verror_with_id_cfn (const char *id, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 OCTAVE_NORETURN OCTINTERP_API extern
 void error_with_id_cfn (const char *id, const char *fmt, ...);
 
 OCTAVE_NORETURN OCTINTERP_API extern
 void vparse_error_with_id (const char *id, const char *fmt, va_list args);
 
+OCTAVE_FORMAT_PRINTF (2, 3)
 OCTAVE_NORETURN OCTINTERP_API extern
 void parse_error_with_id (const char *id, const char *fmt, ...);
 
+OCTAVE_FORMAT_PRINTF (1, 2)
 OCTAVE_NORETURN OCTINTERP_API extern
 void panic (const char *fmt, ...);
 
-// Helper function for print_usage defined in defun.cc.
+//! Helper function for print_usage defined in defun.cc.
+
 extern OCTINTERP_API void defun_usage_message (const std::string& msg);
 
 extern OCTINTERP_API octave_value_list
@@ -136,47 +146,60 @@
 extern OCTINTERP_API void disable_warning (const std::string& id);
 extern OCTINTERP_API void initialize_default_warning_state (void);
 
-// TRUE means that Octave will try to enter the debugger when an error
-// is encountered.  This will also inhibit printing of the normal
-// traceback message (you will only see the top-level error message).
+//! TRUE means that Octave will try to enter the debugger when an error
+//! is encountered.  This will also inhibit printing of the normal
+//! traceback message (you will only see the top-level error message).
+
 extern OCTINTERP_API bool Vdebug_on_error;
 
-// TRUE means that Octave will try to enter the debugger when an error
-// is encountered within the 'try' section of a 'try' / 'catch' block.
+//! TRUE means that Octave will try to enter the debugger when an error
+//! is encountered within the 'try' section of a 'try' / 'catch' block.
+
 extern OCTINTERP_API bool Vdebug_on_caught;
 
-// TRUE means that Octave will try to enter the debugger when a warning
-// is encountered.
+//! TRUE means that Octave will try to enter the debugger when a warning
+//! is encountered.
+
 extern OCTINTERP_API bool Vdebug_on_warning;
 
-// Current error state.
+//! Current error state.
+
 extern OCTINTERP_API int error_state;
 
-// Current warning state.
+//! Current warning state.
+
 extern OCTINTERP_API int warning_state;
 
-// Tell the error handler whether to print messages, or just store
-// them for later.  Used for handling errors in eval() and
-// the 'unwind_protect' statement.
+//! Tell the error handler whether to print messages, or just store
+//! them for later.  Used for handling errors in eval() and
+//! the 'unwind_protect' statement.
+
 extern OCTINTERP_API int buffer_error_messages;
 
-// The number of layers of try / catch blocks we're in.  Used to print
-// "caught error" instead of "error" when "dbstop if caught error" is on.
+//! The number of layers of try / catch blocks we're in.  Used to print
+//! "caught error" instead of "error" when "dbstop if caught error" is on.
+
 extern OCTINTERP_API int in_try_catch;
 
-// TRUE means error messages are turned off.
+//! TRUE means error messages are turned off.
+
 extern OCTINTERP_API bool discard_error_messages;
 
-// TRUE means warning messages are turned off.
+//! TRUE means warning messages are turned off.
+
 extern OCTINTERP_API bool discard_warning_messages;
 
-// Helper functions to pass last error and warning messages and ids
+//! Helper functions to pass last error and warning messages and ids.
+//! @{
+
 extern OCTINTERP_API std::string last_error_message (void);
 extern OCTINTERP_API std::string last_error_id (void);
 extern OCTINTERP_API octave_map last_error_stack (void);
 extern OCTINTERP_API std::string last_warning_message (void);
 extern OCTINTERP_API std::string last_warning_id (void);
 
+//! @}
+
 extern OCTINTERP_API void interpreter_try (octave::unwind_protect&);
 
 #endif
--- a/libinterp/corefcn/errwarn.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/errwarn.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -98,8 +98,9 @@
 err_nonconformant (octave_idx_type r1, octave_idx_type c1,
                    octave_idx_type r2, octave_idx_type c2)
 {
-  error ("nonconformant matrices (op1 is %dx%d, op2 is %dx%d)",
-         r1, c1, r2, c2);
+  error ("nonconformant matrices (op1 is %" OCTAVE_IDX_TYPE_FORMAT
+         "x%" OCTAVE_IDX_TYPE_FORMAT ", op2 is %" OCTAVE_IDX_TYPE_FORMAT
+         "x%" OCTAVE_IDX_TYPE_FORMAT ")", r1, c1, r2, c2);
 }
 
 void
--- a/libinterp/corefcn/event-queue.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/event-queue.h	Thu Dec 20 17:18:56 2018 -0500
@@ -51,11 +51,6 @@
 
     ~event_queue (void) { run (); }
 
-    void add (elem *new_elem)
-    {
-      fifo.push (new_elem);
-    }
-
     void run_first (void)
     {
       if (! empty ())
@@ -81,6 +76,11 @@
 
   protected:
 
+    void add_action (elem *new_elem)
+    {
+      fifo.push (new_elem);
+    }
+
     std::queue<elem *> fifo;
   };
 
--- a/libinterp/corefcn/fcn-info.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/fcn-info.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -196,7 +196,7 @@
                 const std::list<std::string>& plist =
                   symtab.parent_classes (dispatch_type);
 
-                std::list<std::string>::const_iterator it = plist.begin ();
+                auto it = plist.begin ();
 
                 while (it != plist.end ())
                   {
@@ -345,9 +345,9 @@
   // than methods, but that does not seem to be the case.
 
   octave_value
-  fcn_info::fcn_info_rep::find (const octave_value_list& args, bool local_funcs)
+  fcn_info::fcn_info_rep::find (const octave_value_list& args)
   {
-    octave_value retval = xfind (args, local_funcs);
+    octave_value retval = xfind (args);
 
     if (retval.is_undefined ())
       {
@@ -359,93 +359,89 @@
 
         lp.update ();
 
-        retval = xfind (args, local_funcs);
+        retval = xfind (args);
       }
 
     return retval;
   }
 
   octave_value
-  fcn_info::fcn_info_rep::xfind (const octave_value_list& args,
-                                 bool local_funcs)
+  fcn_info::fcn_info_rep::xfind (const octave_value_list& args)
   {
-    if (local_funcs)
-      {
-        symbol_scope curr_scope
-          = __get_current_scope__ ("fcn_info::fcn_info_rep::xfind");
+    symbol_scope curr_scope
+      = __get_current_scope__ ("fcn_info::fcn_info_rep::xfind");
+
+    octave_user_function *current_fcn
+      = curr_scope ? curr_scope.function () : nullptr;
 
-        octave_user_function *current_fcn
-          = curr_scope ? curr_scope.function () : nullptr;
-
-        // Local function.
+    // Local function.
 
-        if (current_fcn)
-          {
-            std::string fcn_file = current_fcn->fcn_file_name ();
+    if (current_fcn)
+      {
+        std::string fcn_file = current_fcn->fcn_file_name ();
 
-            // For anonymous functions we look at the parent scope so that if
-            // they were defined within class methods and use local functions
-            // (helper functions) we can still use those anonymous functions
+        // For anonymous functions we look at the parent scope so that if
+        // they were defined within class methods and use local functions
+        // (helper functions) we can still use those anonymous functions
 
-            if (current_fcn->is_anonymous_function ())
-              {
-                if (fcn_file.empty ()
-                    && curr_scope.parent_scope ()
-                    && curr_scope.parent_scope ()->function () != nullptr)
-                  fcn_file
-                    = curr_scope.parent_scope ()->function ()->fcn_file_name();
-              }
+        if (current_fcn->is_anonymous_function ())
+          {
+            if (fcn_file.empty ()
+                && curr_scope.parent_scope ()
+                && curr_scope.parent_scope ()->function () != nullptr)
+              fcn_file
+                = curr_scope.parent_scope ()->function ()->fcn_file_name();
+          }
 
-            if (! fcn_file.empty ())
+        if (! fcn_file.empty ())
+          {
+            auto r = local_functions.find (fcn_file);
+
+            if (r != local_functions.end ())
               {
-                str_val_iterator r = local_functions.find (fcn_file);
+                // We shouldn't need an out-of-date check here since
+                // local functions may ultimately be called only from
+                // a primary function or method defined in the same
+                // file.
 
-                if (r != local_functions.end ())
-                  {
-                    // We shouldn't need an out-of-date check here since
-                    // local functions may ultimately be called only from
-                    // a primary function or method defined in the same
-                    // file.
-
-                    return r->second;
-                  }
+                return r->second;
               }
           }
+      }
 
-        // Private function.
+    // Private function.
 
-        if (current_fcn)
+    if (current_fcn)
+      {
+        std::string dir_name = current_fcn->dir_name ();
+
+        if (! dir_name.empty ())
           {
-            std::string dir_name = current_fcn->dir_name ();
+            auto q = private_functions.find (dir_name);
 
-            if (! dir_name.empty ())
+            if (q == private_functions.end ())
               {
-                str_val_iterator q = private_functions.find (dir_name);
+                octave_value val = load_private_function (dir_name);
 
-                if (q == private_functions.end ())
+                if (val.is_defined ())
+                  return val;
+              }
+            else
+              {
+                octave_value& fval = q->second;
+
+                if (fval.is_defined ())
+                  out_of_date_check (fval, "", false);
+
+                if (fval.is_defined ())
+                  return fval;
+                else
                   {
                     octave_value val = load_private_function (dir_name);
 
                     if (val.is_defined ())
                       return val;
                   }
-                else
-                  {
-                    octave_value& fval = q->second;
-
-                    if (fval.is_defined ())
-                      out_of_date_check (fval, "", false);
-
-                    if (fval.is_defined ())
-                      return fval;
-                    else
-                      {
-                        octave_value val = load_private_function (dir_name);
-
-                        if (val.is_defined ())
-                          return val;
-                      }
-                  }
               }
           }
       }
@@ -464,7 +460,7 @@
 
     // Class constructors.  The class name and function name are the same.
 
-    str_val_iterator q = class_constructors.find (name);
+    auto q = class_constructors.find (name);
 
     if (q == class_constructors.end ())
       {
@@ -601,7 +597,7 @@
 
         if (! dir_name.empty ())
           {
-            str_val_iterator q = private_functions.find (dir_name);
+            auto q = private_functions.find (dir_name);
 
             if (q == private_functions.end ())
               {
@@ -638,7 +634,7 @@
 
         if (! fcn_file.empty ())
           {
-            str_val_iterator r = local_functions.find (fcn_file);
+            auto r = local_functions.find (fcn_file);
 
             if (r != local_functions.end ())
               {
@@ -671,7 +667,7 @@
   {
     octave_value retval;
 
-    str_val_iterator q = class_methods.find (dispatch_type);
+    auto q = class_methods.find (dispatch_type);
 
     if (q == class_methods.end ())
       {
--- a/libinterp/corefcn/fcn-info.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/fcn-info.h	Thu Dec 20 17:18:56 2018 -0500
@@ -81,7 +81,7 @@
 
       octave_value load_class_method (const std::string& dispatch_type);
 
-      octave_value find (const octave_value_list& args, bool local_funcs);
+      octave_value find (const octave_value_list& args);
 
       octave_value builtin_find (void);
 
@@ -98,10 +98,9 @@
         return function_on_path.is_defined ();
       }
 
-      octave_value find_function (const octave_value_list& args,
-                                  bool local_funcs)
+      octave_value find_function (const octave_value_list& args)
       {
-        return find (args, local_funcs);
+        return find (args);
       }
 
       void install_cmdline_function (const octave_value& f)
@@ -131,7 +130,7 @@
       void
       clear_map (std::map<T, octave_value>& map, bool force = false)
       {
-        typename std::map<T, octave_value>::iterator p = map.begin ();
+        auto p = map.begin ();
 
         while (p != map.end ())
           {
@@ -222,7 +221,7 @@
 
     private:
 
-      octave_value xfind (const octave_value_list& args, bool local_funcs);
+      octave_value xfind (const octave_value_list& args);
 
       octave_value x_builtin_find (void);
     };
@@ -238,10 +237,9 @@
 
     ~fcn_info (void) = default;
 
-    octave_value find (const octave_value_list& args = octave_value_list (),
-                       bool local_funcs = true)
+    octave_value find (const octave_value_list& args = octave_value_list ())
     {
-      return m_rep->find (args, local_funcs);
+      return m_rep->find (args);
     }
 
     octave_value builtin_find (void)
@@ -280,10 +278,9 @@
     }
 
     octave_value find_function (const octave_value_list& args
-                                = octave_value_list (),
-                                bool local_funcs = true)
+                                = octave_value_list ())
     {
-      return m_rep->find_function (args, local_funcs);
+      return m_rep->find_function (args);
     }
 
     void install_cmdline_function (const octave_value& f)
@@ -333,7 +330,14 @@
     std::shared_ptr<fcn_info_rep> m_rep;
   };
 
-  octave_value
+  extern OCTINTERP_API std::string
+  get_dispatch_type (const octave_value_list& args);
+
+  extern OCTINTERP_API std::string
+  get_dispatch_type (const octave_value_list& args,
+                     builtin_type_t& builtin_type);
+
+  extern octave_value
   dump_function_map (const std::map<std::string, octave_value>& fcn_map);
 }
 
--- a/libinterp/corefcn/fft.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/fft.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -33,12 +33,6 @@
 #include "ovl.h"
 #include "utils.h"
 
-#if defined (HAVE_FFTW)
-#  define FFTSRC "@sc{fftw}"
-#else
-#  define FFTSRC "@sc{fftpack}"
-#endif
-
 static octave_value
 do_fft (const octave_value_list& args, const char *fcn, int type)
 {
@@ -161,21 +155,35 @@
 }
 
 /*
-%!assert (fft ([]), [])
-%!assert (fft (zeros (10,0)), zeros (10,0))
-%!assert (fft (zeros (0,10)), zeros (0,10))
-%!assert (fft (0), 0)
-%!assert (fft (1), 1)
-%!assert (fft (ones (2,2)), [2,2; 0,0])
-%!assert (fft (eye (2,2)), [1,1; 1,-1])
+%!testif HAVE_FFTW
+%! assert (fft ([]), [])
+%!testif HAVE_FFTW
+%! assert (fft (zeros (10,0)), zeros (10,0))
+%!testif HAVE_FFTW
+%! assert (fft (zeros (0,10)), zeros (0,10))
+%!testif HAVE_FFTW
+%! assert (fft (0), 0)
+%!testif HAVE_FFTW
+%! assert (fft (1), 1)
+%!testif HAVE_FFTW
+%! assert (fft (ones (2,2)), [2,2; 0,0])
+%!testif HAVE_FFTW
+%! assert (fft (eye (2,2)), [1,1; 1,-1])
 
-%!assert (fft (single ([])), single ([]))
-%!assert (fft (zeros (10,0,"single")), zeros (10,0,"single"))
-%!assert (fft (zeros (0,10,"single")), zeros (0,10,"single"))
-%!assert (fft (single (0)), single (0))
-%!assert (fft (single (1)), single (1))
-%!assert (fft (ones (2,2,"single")), single ([2,2; 0,0]))
-%!assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
+%!testif HAVE_FFTW
+%! assert (fft (single ([])), single ([]))
+%!testif HAVE_FFTW
+%! assert (fft (zeros (10,0,"single")), zeros (10,0,"single"))
+%!testif HAVE_FFTW
+%! assert (fft (zeros (0,10,"single")), zeros (0,10,"single"))
+%!testif HAVE_FFTW
+%! assert (fft (single (0)), single (0))
+%!testif HAVE_FFTW
+%! assert (fft (single (1)), single (1))
+%!testif HAVE_FFTW
+%! assert (fft (ones (2,2,"single")), single ([2,2; 0,0]))
+%!testif HAVE_FFTW
+%! assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
 
 %!error (fft ())
 */
@@ -242,7 +250,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! N = 64;
 %! n = 4;
 %! t = 2*pi*(0:1:N-1)/N;
@@ -258,7 +266,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! N = 64;
 %! n = 7;
 %! t = 2*pi*(0:1:N-1)/N;
@@ -273,7 +281,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! N = 64;
 %! n = 4;
 %! t = single (2*pi*(0:1:N-1)/N);
@@ -289,7 +297,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! N = 64;
 %! n = 7;
 %! t = 2*pi*(0:1:N-1)/N;
--- a/libinterp/corefcn/fft2.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/fft2.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -35,12 +35,6 @@
 
 // This function should be merged with Fifft.
 
-#if defined (HAVE_FFTW)
-#  define FFTSRC "@sc{fftw}"
-#else
-#  define FFTSRC "@sc{fftpack}"
-#endif
-
 static octave_value
 do_fft2 (const octave_value_list& args, const char *fcn, int type)
 {
@@ -182,7 +176,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! M = 16;
 %! N = 8;
 %!
@@ -201,7 +195,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! M = 12;
 %! N = 7;
 %!
@@ -223,7 +217,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! M = 16;
 %! N = 8;
 %!
@@ -242,7 +236,7 @@
 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
 ##         Comalco Research and Technology
 ##         02 May 2000
-%!test
+%!testif HAVE_FFTW
 %! M = 12;
 %! N = 7;
 %!
--- a/libinterp/corefcn/fftn.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/fftn.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -34,12 +34,6 @@
 
 // This function should be merged with Fifft.
 
-#if defined (HAVE_FFTW)
-#  define FFTSRC "@sc{fftw}"
-#else
-#  define FFTSRC "@sc{fftpack}"
-#endif
-
 static octave_value
 do_fftn (const octave_value_list& args, const char *fcn, int type)
 {
--- a/libinterp/corefcn/file-io.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/file-io.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -41,8 +41,7 @@
 #include <cerrno>
 #include <cstdio>
 
-#include <iostream>
-#include <limits>
+#include <iomanip>
 #include <stack>
 #include <string>
 #include <vector>
@@ -425,7 +424,7 @@
   octave::sys::file_stat fs (fname);
 
   if (! (md & std::ios::out))
-    fname = find_data_file_in_load_path ("fopen", fname);
+    fname = octave::find_data_file_in_load_path ("fopen", fname);
 
   if (! fs.is_dir ())
     {
@@ -1199,7 +1198,7 @@
       fmt = args(1).string_value ();
 
       if (args(1).is_sq_string ())
-        fmt = do_string_escapes (fmt);
+        fmt = octave::do_string_escapes (fmt);
 
       nskip++;
     }
@@ -3080,7 +3079,7 @@
   if (args.length () != 0)
     print_usage ();
 
-  return ovl (get_P_tmpdir ());
+  return ovl (octave::get_P_tmpdir ());
 }
 
 // NOTE: the values of SEEK_SET, SEEK_CUR, and SEEK_END have to be
--- a/libinterp/corefcn/ft-text-renderer.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ft-text-renderer.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -37,6 +37,7 @@
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
+#include FT_GLYPH_H
 
 #if defined (HAVE_FONTCONFIG)
 #  include <fontconfig/fontconfig.h>
@@ -48,11 +49,11 @@
 
 #include <clocale>
 #include <cwchar>
-#include <iostream>
 #include <map>
 #include <utility>
 
 #include "singleton-cleanup.h"
+#include "unistr-wrappers.h"
 
 #include "defaults.h"
 #include "error.h"
@@ -70,14 +71,14 @@
   warn_missing_glyph (FT_ULong c)
   {
     warning_with_id ("Octave:missing-glyph",
-                     "text_renderer: skipping missing glyph for character '%x'", c);
+                     "text_renderer: skipping missing glyph for character '%lx'", c);
   }
 
   static void
   warn_glyph_render (FT_ULong c)
   {
     warning_with_id ("Octave:glyph-render",
-                     "text_renderer: unable to render glyph for character '%x'", c);
+                     "text_renderer: unable to render glyph for character '%lx'", c);
   }
 
 #if defined (_MSC_VER)
@@ -226,7 +227,7 @@
 
       if (! fonts_dir.empty ())
         {
-          file = fonts_dir + octave::sys::file_ops::dir_sep_str () + "FreeSans";
+          file = fonts_dir + sys::file_ops::dir_sep_str () + "FreeSans";
 
           if (weight == "bold")
             file += "Bold";
@@ -347,7 +348,7 @@
   static void
   ft_face_destroyed (void *object)
   {
-    octave::ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object));
+    ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object));
   }
 
   class
@@ -375,7 +376,8 @@
     ft_text_renderer (void)
       : base_text_renderer (), font (), bbox (1, 4, 0.0), halign (0),
         xoffset (0), line_yoffset (0), yoffset (0), mode (MODE_BBOX),
-        color (dim_vector (1, 3), 0)
+        color (dim_vector (1, 3), 0), m_ymin (0), m_ymax (0), m_deltax (0),
+        m_max_fontsize (0)
     { }
 
     // No copying!
@@ -532,6 +534,16 @@
 
     // The X offset of the baseline for the current line.
     int line_xoffset;
+     
+    // Min and max y coordinates of all glyphs in a line.
+    FT_Pos m_ymin;
+    FT_Pos m_ymax;
+
+    // Difference between the advance and the actual extent of the latest glyph
+    FT_Pos m_deltax;
+
+    // Used for computing the distance between lines.
+    double m_max_fontsize;
 
   };
 
@@ -557,19 +569,12 @@
 
           if (face)
             {
-              int asc = face->size->metrics.ascender >> 6;
-              int desc = face->size->metrics.descender >> 6;
-              int h = face->size->metrics.height >> 6;
-
               Matrix bb (1, 5, 0.0);
 
-              bb(1) = desc;
-              bb(3) = asc - desc;
-              bb(4) = h;
-
               line_bbox.push_back (bb);
 
               xoffset = yoffset = 0;
+              m_ymin = m_ymax = m_deltax = 0;
             }
         }
         break;
@@ -584,8 +589,10 @@
           Matrix new_bbox = line_bbox.front ();
 
           xoffset = line_xoffset = compute_line_xoffset (new_bbox);
-          line_yoffset += (old_bbox(1) - (new_bbox(1) + new_bbox(3)));
+          line_yoffset -= (-old_bbox(1) + math::round (0.4 * m_max_fontsize)
+                           + (new_bbox(3) + new_bbox(1)));
           yoffset = 0;
+          m_ymin = m_ymax = m_deltax = 0;
         }
         break;
       }
@@ -634,8 +641,9 @@
               bbox = lbox.extract (0, 0, 0, 3);
             else
               {
-                bbox(1) -= lbox(3);
-                bbox(3) += lbox(3);
+                double delta = math::round (0.4 * m_max_fontsize) + lbox(3);
+                bbox(1) -= delta;
+                bbox(3) += delta;
                 bbox(2) = math::max (bbox(2), lbox(2));
               }
           }
@@ -653,29 +661,11 @@
 
     if (mode == MODE_BBOX)
       {
-        int asc = font.get_face ()->size->metrics.ascender >> 6;
-        int desc = font.get_face ()->size->metrics.descender >> 6;
-
         Matrix& bb = line_bbox.back ();
-
-        if ((yoffset + desc) < bb(1))
-          {
-            // The new font goes below the bottom of the current bbox.
-
-            int delta = bb(1) - (yoffset + desc);
-
-            bb(1) -= delta;
-            bb(3) += delta;
-          }
-
-        if ((yoffset + asc) > (bb(1) + bb(3)))
-          {
-            // The new font goes above the top of the current bbox.
-
-            int delta = (yoffset + asc) - (bb(1) + bb(3));
-
-            bb(3) += delta;
-          }
+        bb(1) = m_ymin;
+        bb(3) = m_ymax - m_ymin;
+        if (m_deltax > 0)
+          bb(2) += m_deltax;
       }
   }
 
@@ -688,6 +678,7 @@
       {
       case MODE_BBOX:
         xoffset = line_yoffset = yoffset = 0;
+        m_max_fontsize = 0.0;
         bbox = Matrix (1, 4, 0.0);
         line_bbox.clear ();
         push_new_line ();
@@ -707,7 +698,7 @@
                           octave_idx_type (bbox(3)));
             pixels = uint8NDArray (d, static_cast<uint8_t> (0));
             xoffset = compute_line_xoffset (line_bbox.front ());
-            line_yoffset = -bbox(1)-1;
+            line_yoffset = -bbox(1);
             yoffset = 0;
           }
         break;
@@ -728,31 +719,38 @@
       {
         glyph_index = FT_Get_Char_Index (face, code);
 
-        if (code != '\n'
+        if (code != '\n' && code != '\t'
             && (! glyph_index
                 || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
           {
             glyph_index = 0;
             warn_missing_glyph (code);
           }
+        else if ((code == '\n') || (code == '\t'))
+          {
+            glyph_index = FT_Get_Char_Index (face, ' ');
+            if (! glyph_index
+                || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
+              {
+                glyph_index = 0;
+                warn_missing_glyph (' ');
+              }
+            else if (code == '\n')
+              push_new_line ();
+            else
+              {
+                // Advance to next multiple of 4 times the width of the "space"
+                // character.
+                int x_tab = 4 * (face->glyph->advance.x >> 6);
+                xoffset = (1 + std::floor (1. * xoffset / x_tab)) * x_tab;
+              }
+          }
         else
           {
             switch (mode)
               {
               case MODE_RENDER:
-                if (code == '\n')
-                  {
-                    glyph_index = FT_Get_Char_Index (face, ' ');
-                    if (! glyph_index
-                        || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                      {
-                        glyph_index = 0;
-                        warn_missing_glyph (' ');
-                      }
-                    else
-                      push_new_line ();
-                  }
-                else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
+                if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
                   {
                     glyph_index = 0;
                     warn_glyph_render (code);
@@ -772,12 +770,12 @@
                       }
 
                     x0 = xoffset + face->glyph->bitmap_left;
-                    y0 = line_yoffset + yoffset + face->glyph->bitmap_top;
+                    y0 = line_yoffset + yoffset + (face->glyph->bitmap_top - 1);
 
                     // 'w' seems to have a negative -1
-                    // face->glyph->bitmap_left, this is so we don't
-                    // index out of bound, and assumes we've allocated
-                    // the right amount of horizontal space in the bbox.
+                    // face->glyph->bitmap_left, this is so we don't index out
+                    // of bound, and assumes we've allocated the right amount of
+                    // horizontal space in the bbox.
                     if (x0 < 0)
                       x0 = 0;
 
@@ -788,8 +786,8 @@
                           if (x0+c < 0 || x0+c >= pixels.dim2 ()
                               || y0-r < 0 || y0-r >= pixels.dim3 ())
                             {
-                              //::warning ("ft_text_renderer: pixel out of bound (char=%d, (x,y)=(%d,%d), (w,h)=(%d,%d)",
-                              //           str[i], x0+c, y0-r, pixels.dim2 (), pixels.dim3 ());
+                              // ::warning ("ft_text_renderer: x %d,  y %d",
+                              //            x0+c, y0-r);
                             }
                           else if (pixels(3, x0+c, y0-r).value () == 0)
                             {
@@ -805,40 +803,42 @@
                 break;
 
               case MODE_BBOX:
-                if (code == '\n')
+                Matrix& bb = line_bbox.back ();
+
+                // If we have a previous glyph, use kerning information.  This
+                // usually means moving a bit backward before adding the next
+                // glyph.  That is, "delta.x" is usually < 0.
+                if (previous)
                   {
-                    glyph_index = FT_Get_Char_Index (face, ' ');
-                    if (! glyph_index
-                        || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                      {
-                        glyph_index = 0;
-                        warn_missing_glyph (' ');
-                      }
-                    else
-                      push_new_line ();
+                    FT_Vector delta;
+
+                    FT_Get_Kerning (face, previous, glyph_index,
+                                    FT_KERNING_DEFAULT, &delta);
+
+                    xoffset += (delta.x >> 6);
                   }
+
+                // Extend current X offset box by the width of the current
+                // glyph.  Then extend the line bounding box if necessary.
+
+                xoffset += (face->glyph->advance.x >> 6);
+                bb(2) = math::max (bb(2), xoffset);
+
+                // Store the actual bbox vertical coordinates of this character
+                FT_Glyph glyph;
+                if (FT_Get_Glyph (face->glyph, &glyph))
+                  warn_glyph_render (code);
                 else
                   {
-                    Matrix& bb = line_bbox.back ();
-
-                    // If we have a previous glyph, use kerning information.
-                    // This usually means moving a bit backward before adding
-                    // the next glyph.  That is, "delta.x" is usually < 0.
-                    if (previous)
-                      {
-                        FT_Vector delta;
-
-                        FT_Get_Kerning (face, previous, glyph_index,
-                                        FT_KERNING_DEFAULT, &delta);
-
-                        xoffset += (delta.x >> 6);
-                      }
-
-                    // Extend current X offset box by the width of the current
-                    // glyph.  Then extend the line bounding box if necessary.
-
-                    xoffset += (face->glyph->advance.x >> 6);
-                    bb(2) = math::max (bb(2), xoffset);
+                    FT_BBox  glyph_bbox;
+                    FT_Glyph_Get_CBox (glyph, FT_GLYPH_BBOX_UNSCALED,
+                                       &glyph_bbox);
+                    m_deltax = (glyph_bbox.xMax - face->glyph->advance.x) >> 6;
+                    m_ymin = math::min ((glyph_bbox.yMin >> 6) + yoffset,
+                                        m_ymin);
+                    m_ymax = math::max ((glyph_bbox.yMax >> 6) + yoffset,
+                                        m_ymax);
+                    update_line_bbox ();
                   }
                 break;
               }
@@ -869,70 +869,65 @@
   {
     if (font.is_valid ())
       {
+        m_max_fontsize = std::max (m_max_fontsize, font.get_size ());
         FT_UInt glyph_index, previous = 0;
 
         std::string str = e.string_value ();
-        size_t n = str.length ();
-        size_t curr = 0;
-        size_t idx = 0;
-        mbstate_t ps;
-        memset (&ps, 0, sizeof (ps));  // Initialize state to 0.
-        wchar_t wc;
+        const uint8_t *c = reinterpret_cast<const uint8_t *> (str.c_str ());
+        uint32_t u32_c;
+        
+        size_t n = str.size ();
+        size_t icurr = 0;
+        size_t ibegin = 0;
+
+        // Initialize a new string
         std::string fname = font.get_face ()->family_name;
         text_renderer::string fs (str, font, xoffset, yoffset);
         std::vector<double> xdata;
 
         while (n > 0)
           {
-            size_t r = std::mbrtowc (&wc, str.data () + curr, n, &ps);
-
-            if (r > 0
-                && r != static_cast<size_t> (-1)
-                && r != static_cast<size_t> (-2))
+            // Retrieve the length and the u32 representation of the current
+            // character
+            int mblen = octave_u8_strmbtouc_wrapper (&u32_c, c + icurr);
+            n -= mblen;
+            
+            if (u32_c == 10)
               {
-                n -= r;
-                curr += r;
-
-                if (wc == L'\n')
+                // Finish previous string in strlist before processing
+                // the newline character
+                fs.set_y (line_yoffset + yoffset);
+                fs.set_color (color);
+                
+                std::string s = str.substr (ibegin, icurr - ibegin);
+                if (! s.empty ())
                   {
-                    // Finish previous string in strlist before processing
-                    // the newline character
+                    fs.set_string (s);
                     fs.set_y (line_yoffset + yoffset);
-                    fs.set_color (color);
-                    std::string s = str.substr (idx, curr - idx - 1);
-                    if (! s.empty ())
-                      {
-                        fs.set_string (s);
-                        fs.set_xdata (xdata);
-                        fs.set_family (fname);
-                        strlist.push_back (fs);
-                      }
+                    fs.set_xdata (xdata);
+                    fs.set_family (fname);
+                    strlist.push_back (fs);
                   }
-                else
-                  xdata.push_back (xoffset);
-
-                glyph_index = process_character (wc, previous);
-
-                if (wc == L'\n')
-                  {
-                    previous = 0;
-                    // Start a new string in strlist
-                    idx = curr;
-                    xdata.clear ();
-                    fs = text_renderer::string (str.substr (idx), font,
-                                                line_xoffset, yoffset);
-                  }
-                else
-                  previous = glyph_index;
               }
             else
+              xdata.push_back (xoffset);
+
+            glyph_index = process_character (u32_c, previous);
+
+
+            if (u32_c == 10)
               {
-                if (r != 0)
-                  ::warning ("ft_text_renderer: failed to decode string `%s' with "
-                             "locale `%s'", str.c_str (),
-                             std::setlocale (LC_CTYPE, nullptr));
-                break;
+                previous = 0;
+                // Start a new string in strlist
+                ibegin = icurr+1;
+                xdata.clear ();
+                fs = text_renderer::string (str.substr (ibegin), font,
+                                            line_xoffset, yoffset);
               }
+            else
+              previous = glyph_index;
+
+            icurr += mblen;
           }
 
         if (! fs.get_string ().empty ())
--- a/libinterp/corefcn/gammainc.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
-
-Copyright (C) 1997-2018 John W. Eaton
-
-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 "lo-specfun.h"
-
-#include "defun.h"
-#include "error.h"
-#include "errwarn.h"
-#include "ovl.h"
-#include "utils.h"
-
-DEFUN (gammainc, args, ,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {} gammainc (@var{x}, @var{a})
-@deftypefnx {} {} gammainc (@var{x}, @var{a}, "lower")
-@deftypefnx {} {} gammainc (@var{x}, @var{a}, "upper")
-Compute the normalized incomplete gamma function.
-
-This is defined as
-@tex
-$$
- \gamma (x, a) = {1 \over {\Gamma (a)}}\displaystyle{\int_0^x t^{a-1} e^{-t} dt}
-$$
-@end tex
-@ifnottex
-
-@example
-@group
-                                x
-                       1       /
-gammainc (x, a) = ---------    | exp (-t) t^(a-1) dt
-                  gamma (a)    /
-                            t=0
-@end group
-@end example
-
-@end ifnottex
-with the limiting value of 1 as @var{x} approaches infinity.
-The standard notation is @math{P(a,x)}, e.g., @nospell{Abramowitz} and
-@nospell{Stegun} (6.5.1).
-
-If @var{a} is scalar, then @code{gammainc (@var{x}, @var{a})} is returned
-for each element of @var{x} and vice versa.
-
-If neither @var{x} nor @var{a} is scalar, the sizes of @var{x} and
-@var{a} must agree, and @code{gammainc} is applied element-by-element.
-
-By default the incomplete gamma function integrated from 0 to @var{x} is
-computed.  If @qcode{"upper"} is given then the complementary function
-integrated from @var{x} to infinity is calculated.  It should be noted that
-
-@example
-gammainc (@var{x}, @var{a}) @equiv{} 1 - gammainc (@var{x}, @var{a}, "upper")
-@end example
-@seealso{gamma, gammaln}
-@end deftypefn */)
-{
-  int nargin = args.length ();
-
-  if (nargin < 2 || nargin > 3)
-    print_usage ();
-
-  bool lower = true;
-  if (nargin == 3)
-    {
-      std::string s = args(2).xstring_value (R"(gammainc: third argument must be "lower" or "upper")");
-
-      std::transform (s.begin (), s.end (), s.begin (), tolower);
-
-      if (s == "upper")
-        lower = false;
-      else if (s == "lower")
-        lower = true;
-      else
-        error (R"(gammainc: third argument must be "lower" or "upper")");
-    }
-
-  octave_value retval;
-
-  octave_value x_arg = args(0);
-  octave_value a_arg = args(1);
-
-  // FIXME: Can we make a template version of the duplicated code below
-  if (x_arg.is_single_type () || a_arg.is_single_type ())
-    {
-      if (x_arg.is_scalar_type ())
-        {
-          float x = x_arg.float_value ();
-
-          if (a_arg.is_scalar_type ())
-            {
-              float a = a_arg.float_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0f - octave::math::gammainc (x, a));
-            }
-          else
-            {
-              FloatNDArray a = a_arg.float_array_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0f - octave::math::gammainc (x, a));
-            }
-        }
-      else
-        {
-          FloatNDArray x = x_arg.float_array_value ();
-
-          if (a_arg.is_scalar_type ())
-            {
-              float a = a_arg.float_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0f - octave::math::gammainc (x, a));
-            }
-          else
-            {
-              FloatNDArray a = a_arg.float_array_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0f - octave::math::gammainc (x, a));
-            }
-        }
-    }
-  else
-    {
-      if (x_arg.is_scalar_type ())
-        {
-          double x = x_arg.double_value ();
-
-          if (a_arg.is_scalar_type ())
-            {
-              double a = a_arg.double_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0 - octave::math::gammainc (x, a));
-            }
-          else
-            {
-              NDArray a = a_arg.array_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0 - octave::math::gammainc (x, a));
-            }
-        }
-      else
-        {
-          NDArray x = x_arg.array_value ();
-
-          if (a_arg.is_scalar_type ())
-            {
-              double a = a_arg.double_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0 - octave::math::gammainc (x, a));
-            }
-          else
-            {
-              NDArray a = a_arg.array_value ();
-
-              retval = (lower ? octave::math::gammainc (x, a)
-                              : 1.0 - octave::math::gammainc (x, a));
-            }
-        }
-    }
-
-  return retval;
-}
-
-/*
-%!test
-%! a = [.5 .5 .5 .5 .5];
-%! x = [0 1 2 3 4];
-%! v1 = sqrt (pi)*erf (x)./gamma (a);
-%! v3 = gammainc (x.*x, a);
-%! assert (v1, v3, sqrt (eps));
-
-%!assert (gammainc (0:4,0.5, "upper"), 1-gammainc (0:4,0.5), 1e-10)
-
-%!test
-%! a = single ([.5 .5 .5 .5 .5]);
-%! x = single ([0 1 2 3 4]);
-%! v1 = sqrt (pi ("single"))*erf (x)./gamma (a);
-%! v3 = gammainc (x.*x, a);
-%! assert (v1, v3, sqrt (eps ("single")));
-
-%!assert (gammainc (single (0:4), single (0.5), "upper"),
-%!        single (1)-gammainc (single (0:4), single (0.5)),
-%!        single (1e-7))
-*/
--- a/libinterp/corefcn/genprops.awk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/genprops.awk	Thu Dec 20 17:18:56 2018 -0500
@@ -137,7 +137,7 @@
 ##
 ##   f:  The property does not have any factory default value.
 ##
-## The 'o' and 'O' qualifiers are only useful when the the property type
+## The 'o' and 'O' qualifiers are only useful when the property type
 ## is something other than octave_value.
 
 ## simple accessor
@@ -232,10 +232,10 @@
 
 function emit_get_callback (i)
 {
-  printf ("  void execute_%s (const octave_value& data = octave_value ()) const", name[i]);
+  printf ("  void execute_%s (const octave_value& new_data = octave_value ()) const", name[i]);
 
   if (emit_get[i] == "definition")
-    printf (" { %s.execute (data); }\n", name[i]);
+    printf (" { %s.execute (new_data); }\n", name[i]);
   else
     printf (";\n");
 
--- a/libinterp/corefcn/gl-render.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gl-render.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <sstream>
 
 #if defined (HAVE_WINDOWS_H)
 #  define WIN32_LEAN_AND_MEAN
@@ -96,28 +96,31 @@
     class texture_rep
     {
     public:
-      texture_rep (void)
-        : id (), w (), h (), tw (), th (), tx (), ty (),
+      texture_rep (opengl_functions& glfcns)
+        : m_glfcns (glfcns), id (), w (), h (), tw (), th (), tx (), ty (),
           valid (false), count (1)
       { }
 
-      texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
-        : 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_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 (void)
       {
         if (valid)
-          glDeleteTextures (1, &id);
+          m_glfcns.glDeleteTextures (1, &id);
       }
 
       void bind (int mode) const
-      { if (valid) glBindTexture (mode, id); }
+      { if (valid) m_glfcns.glBindTexture (mode, id); }
 
       void tex_coord (double q, double r) const
-      { if (valid) glTexCoord2d (q*tx, r*ty); }
-
+      { if (valid) m_glfcns.glTexCoord2d (q*tx, r*ty); }
+
+      opengl_functions& m_glfcns;
       GLuint id;
       int w, h;
       int tw, th;
@@ -132,7 +135,8 @@
     opengl_texture (texture_rep *_rep) : rep (_rep) { }
 
   public:
-    opengl_texture (void) : rep (new texture_rep ()) { }
+    opengl_texture (opengl_functions& glfcns)
+      : rep (new texture_rep (glfcns)) { }
 
     opengl_texture (const opengl_texture& tx)
       : rep (tx.rep)
@@ -157,7 +161,8 @@
       return *this;
     }
 
-    static opengl_texture create (const octave_value& data);
+    static opengl_texture create (opengl_functions& glfcns,
+                                  const octave_value& data);
 
     void bind (int mode = GL_TEXTURE_2D) const
     { rep->bind (mode); }
@@ -170,9 +175,9 @@
   };
 
   opengl_texture
-  opengl_texture::create (const octave_value& data)
+  opengl_texture::create (opengl_functions& glfcns, const octave_value& data)
   {
-    opengl_texture retval;
+    opengl_texture retval (glfcns);
 
     dim_vector dv (data.dims ());
 
@@ -189,8 +194,8 @@
         tw = next_power_of_2 (w);
         th = next_power_of_2 (h);
 
-        glGenTextures (1, &id);
-        glBindTexture (GL_TEXTURE_2D, id);
+        glfcns.glGenTextures (1, &id);
+        glfcns.glBindTexture (GL_TEXTURE_2D, id);
 
         if (data.is_double_type ())
           {
@@ -208,7 +213,7 @@
                   }
               }
 
-            glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB, GL_FLOAT, a);
+            glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB, GL_FLOAT, a);
           }
         else if (data.is_uint8_type ())
           {
@@ -226,8 +231,8 @@
                   }
               }
 
-            glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
-                          GL_RGB, GL_UNSIGNED_BYTE, a);
+            glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
+                                 GL_RGB, GL_UNSIGNED_BYTE, a);
           }
         else
           {
@@ -237,13 +242,13 @@
 
         if (ok)
           {
-            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-            if (glGetError () != GL_NO_ERROR)
+            glfcns.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            glfcns.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+            if (glfcns.glGetError () != GL_NO_ERROR)
               warning ("opengl_texture::create: OpenGL error while generating texture data");
             else
-              retval = opengl_texture (new texture_rep (id, w, h, tw, th));
+              retval = opengl_texture (new texture_rep (glfcns, id, w, h, tw, th));
           }
       }
     else
@@ -365,7 +370,8 @@
     public:
       Matrix coords;
       Matrix color;
-      Matrix normal;
+      Matrix vertex_normal;
+      Matrix face_normal;
       double alpha;
       float ambient;
       float diffuse;
@@ -377,16 +383,16 @@
       refcount<int> count;
 
       vertex_data_rep (void)
-        : coords (), color (), normal (), alpha (),
+        : coords (), color (), vertex_normal (), face_normal (), alpha (),
           ambient (), diffuse (), specular (), specular_exp (),
           specular_color_refl (), count (1) { }
 
-      vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n,
-                       double a, float as, float ds, float ss, float se,
-                       float scr)
-        : coords (c), color (col), normal (n), alpha (a),
-          ambient (as), diffuse (ds), specular (ss), specular_exp (se),
-          specular_color_refl (scr), count (1) { }
+      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) { }
     };
 
   private:
@@ -406,10 +412,10 @@
     vertex_data (const vertex_data& v) : rep (v.rep)
     { rep->count++; }
 
-    vertex_data (const Matrix& c, const Matrix& col, const Matrix& n,
-                 double a, float as, float ds, float ss, float se,
-                 float scr)
-      : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se, scr))
+    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))
     { }
 
     vertex_data (vertex_data_rep *new_rep)
@@ -448,29 +454,35 @@
   protected:
     void begin (GLenum type)
     {
+      opengl_functions& glfcns = renderer->get_opengl_functions ();
+
       //printf ("patch_tesselator::begin (%d)\n", type);
       first = true;
 
       if (color_mode == INTERP || light_mode == GOURAUD)
-        glShadeModel (GL_SMOOTH);
+        glfcns.glShadeModel (GL_SMOOTH);
       else
-        glShadeModel (GL_FLAT);
+        glfcns.glShadeModel (GL_FLAT);
 
       if (is_filled ())
         renderer->set_polygon_offset (true, index);
 
-      glBegin (type);
+      glfcns.glBegin (type);
     }
 
     void end (void)
     {
+      opengl_functions& glfcns = renderer->get_opengl_functions ();
+
       //printf ("patch_tesselator::end\n");
-      glEnd ();
+      glfcns.glEnd ();
       renderer->set_polygon_offset (false);
     }
 
     void vertex (void *data)
     {
+      opengl_functions& glfcns = renderer->get_opengl_functions ();
+
       vertex_data::vertex_data_rep *v
         = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
       //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
@@ -484,32 +496,34 @@
 
           if (col.numel () == 3)
             {
-              glColor4d (col(0), col(1), col(2), v->alpha);
+              glfcns.glColor4d (col(0), col(1), col(2), v->alpha);
               if (light_mode > 0)
                 {
                   float buf[4] = { 0, 0, 0, 1 };
 
                   for (int k = 0; k < 3; k++)
                     buf[k] = (v->ambient * col(k));
-                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
+                  glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
 
                   for (int k = 0; k < 3; k++)
                     buf[k] = (v->diffuse * col(k));
-                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
+                  glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
 
                   for (int k = 0; k < 3; k++)
                     buf[k] = v->specular * (v->specular_color_refl +
                                             (1 - v->specular_color_refl) * col(k));
-                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
+                  glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
 
                 }
             }
         }
 
-      if (light_mode > 0 && (first || light_mode == GOURAUD))
-        glNormal3dv (v->normal.data ());
-
-      glVertex3dv (v->coords.data ());
+      if (light_mode == FLAT && first)
+        glfcns.glNormal3dv (v->face_normal.data ());
+      else if (light_mode == GOURAUD)
+        glfcns.glNormal3dv (v->vertex_normal.data ());
+
+      glfcns.glVertex3dv (v->coords.data ());
 
       first = false;
     }
@@ -531,7 +545,8 @@
 
       Matrix vv (1, 3, 0.0);
       Matrix cc;
-      Matrix nn (1, 3, 0.0);
+      Matrix vnn (1, 3, 0.0);
+      Matrix fnn (1, 3, 0.0);
       double aa = 0.0;
 
       vv(0) = xyz[0];
@@ -546,18 +561,26 @@
               cc(ic) += (w[iv] * v[iv]->color (ic));
         }
 
-      if (v[0]->normal.numel () > 0)
+      if (v[0]->vertex_normal.numel () > 0)
         {
           for (int in = 0; in < 3; in++)
             for (int iv = 0; iv < vmax; iv++)
-              nn(in) += (w[iv] * v[iv]->normal (in));
+              vnn(in) += (w[iv] * v[iv]->vertex_normal (in));
+        }
+
+      if (v[0]->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));
         }
 
       for (int iv = 0; iv < vmax; iv++)
         aa += (w[iv] * v[iv]->alpha);
 
-      vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse,
-                         v[0]->specular, v[0]->specular_exp, v[0]->specular_color_refl);
+      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);
       tmp_vdata.push_back (new_v);
 
       *out_data = new_v.get_rep ();
@@ -589,11 +612,12 @@
 
 #endif
 
-  opengl_renderer::opengl_renderer (void)
-    : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
-      zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
-      camera_pos (), camera_dir (), interpreter ("none"), txt_renderer (),
-      selecting (false)
+  opengl_renderer::opengl_renderer (opengl_functions& glfcns)
+    : m_glfcns (glfcns), toolkit (), xform (), xmin (), xmax (), ymin (),
+      ymax (), zmin (), zmax (), xZ1 (), xZ2 (), marker_id (),
+      filled_marker_id (), camera_pos (), camera_dir (), view_vector (),
+      interpreter ("none"), txt_renderer (), m_current_light (0),
+      m_max_lights (0), selecting (false), m_devpixratio (1.)
   {
     // This constructor will fail if we don't have OpenGL or if the data
     // types we assumed in our public interface aren't compatible with the
@@ -647,7 +671,8 @@
       draw_image (dynamic_cast<const image::properties&> (props));
     else if (go.isa ("uimenu") || go.isa ("uicontrol")
              || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
-             || go.isa ("uipushtool") || go.isa ("uitoggletool"))
+             || go.isa ("uipushtool") || go.isa ("uitoggletool")
+             || go.isa ("uitable"))
       ; // SKIP
     else if (go.isa ("uipanel"))
       {
@@ -667,7 +692,7 @@
 
 #if defined (HAVE_OPENGL)
 
-    GLenum gl_error = glGetError ();
+    GLenum gl_error = m_glfcns.glGetError ();
     if (gl_error)
       warning ("opengl_renderer: Error '%s' (%d) occurred drawing '%s' object",
                gluErrorString (gl_error), gl_error, props.graphics_object_name ().c_str ());
@@ -675,22 +700,6 @@
 #endif
   }
 
-#if defined (HAVE_OPENGL)
-
-  static std::string
-  gl_get_string (GLenum id)
-  {
-    // This is kind of ugly, but glGetString returns a pointer to GLubyte
-    // and there is no std::string constructor that matches.  Is there a
-    // better way?
-
-    std::ostringstream buf;
-    buf << glGetString (id);
-    return std::string (buf.str ());
-  }
-
-#endif
-
   void
   opengl_renderer::draw_figure (const figure::properties& props)
   {
@@ -700,10 +709,10 @@
 
 #if defined (HAVE_OPENGL)
 
-    props.set___gl_extensions__ (gl_get_string (GL_EXTENSIONS));
-    props.set___gl_renderer__ (gl_get_string (GL_RENDERER));
-    props.set___gl_vendor__ (gl_get_string (GL_VENDOR));
-    props.set___gl_version__ (gl_get_string (GL_VERSION));
+    props.set___gl_extensions__ (get_string (GL_EXTENSIONS));
+    props.set___gl_renderer__ (get_string (GL_RENDERER));
+    props.set___gl_vendor__ (get_string (GL_VENDOR));
+    props.set___gl_version__ (get_string (GL_VERSION));
 
 #endif
 
@@ -755,22 +764,22 @@
 
     // Initialize OpenGL context
 
-    glEnable (GL_DEPTH_TEST);
-    glDepthFunc (GL_LEQUAL);
-    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glAlphaFunc (GL_GREATER, 0.0f);
-    glEnable (GL_NORMALIZE);
+    m_glfcns.glEnable (GL_DEPTH_TEST);
+    m_glfcns.glDepthFunc (GL_LEQUAL);
+    m_glfcns.glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m_glfcns.glAlphaFunc (GL_GREATER, 0.0f);
+    m_glfcns.glEnable (GL_NORMALIZE);
 
     if (enhanced)
       {
-        glEnable (GL_BLEND);
-        glEnable (GL_MULTISAMPLE);
+        m_glfcns.glEnable (GL_BLEND);
+        m_glfcns.glEnable (GL_MULTISAMPLE);
         bool has_multisample = false;
-        if (! glGetError ())
+        if (! m_glfcns.glGetError ())
           {
             GLint iMultiSample, iNumSamples;
-            glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
-            glGetIntegerv (GL_SAMPLES, &iNumSamples);
+            m_glfcns.glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
+            m_glfcns.glGetIntegerv (GL_SAMPLES, &iNumSamples);
             if (iMultiSample == GL_TRUE && iNumSamples > 0)
               has_multisample = true;
           }
@@ -778,30 +787,30 @@
         if (! has_multisample)
           {
             // MultiSample not implemented.  Use old-style anti-aliasing
-            glDisable (GL_MULTISAMPLE);
+            m_glfcns.glDisable (GL_MULTISAMPLE);
             // Disabling GL_MULTISAMPLE will raise a gl error if it is not
             // implemented.  Thus, call glGetError to reset the error state.
-            glGetError ();
-
-            glEnable (GL_LINE_SMOOTH);
-            glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+            m_glfcns.glGetError ();
+
+            m_glfcns.glEnable (GL_LINE_SMOOTH);
+            m_glfcns.glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
           }
       }
     else
       {
-        glDisable (GL_BLEND);
-        glDisable (GL_LINE_SMOOTH);
+        m_glfcns.glDisable (GL_BLEND);
+        m_glfcns.glDisable (GL_LINE_SMOOTH);
       }
 
     // Clear background
 
     if (c.numel () >= 3)
       {
-        glClearColor (c(0), c(1), c(2), 1);
-        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+        m_glfcns.glClearColor (c(0), c(1), c(2), 1);
+        m_glfcns.glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
       }
 
-    GLenum gl_error = glGetError ();
+    GLenum gl_error = m_glfcns.glGetError ();
     if (gl_error)
       warning ("opengl_renderer: Error '%s' (%d) occurred in init_gl_context",
                gluErrorString (gl_error), gl_error);
@@ -829,9 +838,9 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glColor4d (gridcolor(0), gridcolor(1), gridcolor(2), gridalpha);
+    m_glfcns.glColor4d (gridcolor(0), gridcolor(1), gridcolor(2), gridalpha);
     set_linestyle (gridstyle, true, linewidth);
-    glBegin (GL_LINES);
+    m_glfcns.glBegin (GL_LINES);
     for (int i = 0; i < ticks.numel (); i++)
       {
         double val = ticks(i);
@@ -839,37 +848,37 @@
           {
             if (xyz == X_AXIS)
               {
-                glVertex3d (val, p1N, p2);
-                glVertex3d (val, p1, p2);
+                m_glfcns.glVertex3d (val, p1N, p2);
+                m_glfcns.glVertex3d (val, p1, p2);
                 if (is_3D)
                   {
-                    glVertex3d (val, p1, p2N);
-                    glVertex3d (val, p1, p2);
+                    m_glfcns.glVertex3d (val, p1, p2N);
+                    m_glfcns.glVertex3d (val, p1, p2);
                   }
               }
             else if (xyz == Y_AXIS)
               {
-                glVertex3d (p1N, val, p2);
-                glVertex3d (p1, val, p2);
+                m_glfcns.glVertex3d (p1N, val, p2);
+                m_glfcns.glVertex3d (p1, val, p2);
                 if (is_3D)
                   {
-                    glVertex3d (p1, val, p2N);
-                    glVertex3d (p1, val, p2);
+                    m_glfcns.glVertex3d (p1, val, p2N);
+                    m_glfcns.glVertex3d (p1, val, p2);
                   }
               }
             else if (xyz == Z_AXIS)
               {
-                glVertex3d (p1N, p2, val);
-                glVertex3d (p1, p2, val);
-                glVertex3d (p1, p2N, val);
-                glVertex3d (p1, p2, val);
+                m_glfcns.glVertex3d (p1N, p2, val);
+                m_glfcns.glVertex3d (p1, p2, val);
+                m_glfcns.glVertex3d (p1, p2N, val);
+                m_glfcns.glVertex3d (p1, p2, val);
               }
           }
       }
-    glEnd ();
+    m_glfcns.glEnd ();
     set_linestyle ("-");  // Disable LineStipple
     double black[3] = {0, 0, 0};
-    glColor3dv (black);
+    m_glfcns.glColor3dv (black);
 
 #else
 
@@ -905,7 +914,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glBegin (GL_LINES);
+    m_glfcns.glBegin (GL_LINES);
 
     for (int i = 0; i < ticks.numel (); i++)
       {
@@ -915,38 +924,38 @@
           {
             if (xyz == X_AXIS)
               {
-                glVertex3d (val, p1, p2);
-                glVertex3d (val, p1+dy, p2+dz);
+                m_glfcns.glVertex3d (val, p1, p2);
+                m_glfcns.glVertex3d (val, p1+dy, p2+dz);
                 if (mirror)
                   {
-                    glVertex3d (val, p1N, p2N);
-                    glVertex3d (val, p1N-dy, p2N-dz);
+                    m_glfcns.glVertex3d (val, p1N, p2N);
+                    m_glfcns.glVertex3d (val, p1N-dy, p2N-dz);
                   }
               }
             else if (xyz == Y_AXIS)
               {
-                glVertex3d (p1, val, p2);
-                glVertex3d (p1+dx, val, p2+dz);
+                m_glfcns.glVertex3d (p1, val, p2);
+                m_glfcns.glVertex3d (p1+dx, val, p2+dz);
                 if (mirror)
                   {
-                    glVertex3d (p1N, val, p2N);
-                    glVertex3d (p1N-dx, val, p2N-dz);
+                    m_glfcns.glVertex3d (p1N, val, p2N);
+                    m_glfcns.glVertex3d (p1N-dx, val, p2N-dz);
                   }
               }
             else if (xyz == Z_AXIS)
               {
-                glVertex3d (p1, p2, val);
-                glVertex3d (p1+dx, p2+dy, val);
+                m_glfcns.glVertex3d (p1, p2, val);
+                m_glfcns.glVertex3d (p1+dx, p2+dy, val);
                 if (mirror)
                   {
-                    glVertex3d (p1N, p2N, val);
-                    glVertex3d (p1N-dx, p2N-dy, val);
+                    m_glfcns.glVertex3d (p1N, p2N, val);
+                    m_glfcns.glVertex3d (p1N-dx, p2N-dy, val);
                   }
               }
           }
       }
 
-    glEnd ();
+    m_glfcns.glEnd ();
 
 #else
 
@@ -1041,15 +1050,107 @@
 #endif
   }
 
+  void
+  opengl_renderer::draw_zoom_rect (int x1, int y1, int x2, int y2)
+  {
+#if defined (HAVE_OPENGL)
+
+    m_glfcns.glVertex2d (x1, y1);
+    m_glfcns.glVertex2d (x2, y1);
+    m_glfcns.glVertex2d (x2, y2);
+    m_glfcns.glVertex2d (x1, y2);
+    m_glfcns.glVertex2d (x1, y1);
+
+#else
+
+    octave_unused_parameter (x1);
+    octave_unused_parameter (x2);
+    octave_unused_parameter (y1);
+    octave_unused_parameter (y2);
+
+    // 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_zoom_box (int width, int height,
+                                  int x1, int y1, int x2, int y2,
+                                  const Matrix& overlaycolor,
+                                  double overlayalpha,
+                                  const Matrix& bordercolor,
+                                  double borderalpha, double borderwidth)
+  {
+#if defined (HAVE_OPENGL)
+
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glPushMatrix ();
+    m_glfcns.glLoadIdentity ();
+
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPushMatrix ();
+    m_glfcns.glLoadIdentity ();
+    m_glfcns.glOrtho (0, width, height, 0, 1, -1);
+
+    m_glfcns.glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
+    m_glfcns.glDisable (GL_DEPTH_TEST);
+
+    m_glfcns.glBegin (GL_POLYGON);
+    m_glfcns.glColor4f (overlaycolor(0), overlaycolor(1), overlaycolor(2),
+                        overlayalpha);
+    draw_zoom_rect (x1, y1, x2, y2);
+    m_glfcns.glEnd ();
+
+    m_glfcns.glLineWidth (borderwidth);
+    m_glfcns.glBegin (GL_LINE_STRIP);
+    m_glfcns.glColor4f (bordercolor(0), bordercolor(1), bordercolor(2),
+                        borderalpha);
+    draw_zoom_rect (x1, y1, x2, y2);
+    m_glfcns.glEnd ();
+
+    m_glfcns.glPopAttrib ();
+
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glPopMatrix ();
+
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPopMatrix ();
+
+#else
+
+    octave_unused_parameter (width);
+    octave_unused_parameter (height);
+    octave_unused_parameter (x1);
+    octave_unused_parameter (x2);
+    octave_unused_parameter (y1);
+    octave_unused_parameter (y2);
+    octave_unused_parameter (overlaycolor);
+    octave_unused_parameter (overlayalpha);
+    octave_unused_parameter (bordercolor);
+    octave_unused_parameter (borderalpha);
+    octave_unused_parameter (borderwidth);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
   uint8NDArray
   opengl_renderer::get_pixels (int width, int height)
   {
 #if defined (HAVE_OPENGL)
 
-    glPixelStorei (GL_PACK_ALIGNMENT, 1);
+    m_glfcns.glPixelStorei (GL_PACK_ALIGNMENT, 1);
     uint8NDArray pix(dim_vector (3, width, height), 0);
-    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
-                 pix.fortran_vec ());
+
+    m_glfcns.glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
+                          pix.fortran_vec ());
 
     // Permute and flip data
     Array<octave_idx_type> perm (dim_vector (3, 1));
@@ -1082,7 +1183,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glFinish ();
+    m_glfcns.glFinish ();
 
 #else
 
@@ -1103,31 +1204,25 @@
 
     Matrix x_zlim = props.get_transform_zlim ();
 
-    xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
-    xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
+    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);
 
     Matrix x_mat1 = props.get_opengl_matrix_1 ();
     Matrix x_mat2 = props.get_opengl_matrix_2 ();
 
-#if defined (HAVE_FRAMEWORK_OPENGL)
-    GLint vw[4];
-#else
-    int vw[4];
-#endif
-
-    glGetIntegerv (GL_VIEWPORT, vw);
-
-    glMatrixMode (GL_MODELVIEW);
-    glLoadIdentity ();
-    glScaled (1, 1, -1);
-    glMultMatrixd (x_mat1.data ());
-    glMatrixMode (GL_PROJECTION);
-    glLoadIdentity ();
-    glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
-    glMultMatrixd (x_mat2.data ());
-    glMatrixMode (GL_MODELVIEW);
-
-    glClear (GL_DEPTH_BUFFER_BIT);
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glLoadIdentity ();
+    m_glfcns.glScaled (1, 1, -1);
+    m_glfcns.glMultMatrixd (x_mat1.data ());
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glLoadIdentity ();
+
+    Matrix vp = get_viewport_scaled ();
+    m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
+    m_glfcns.glMultMatrixd (x_mat2.data ());
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+
+    m_glfcns.glClear (GL_DEPTH_BUFFER_BIT);
 
     // store axes transformation data
 
@@ -1160,36 +1255,36 @@
     double xPlaneN = props.get_xPlaneN ();
     double yPlaneN = props.get_yPlaneN ();
     double zPlaneN = props.get_zPlaneN ();
-    bool is2d = props.get_is2D ();
+    bool is2D = props.get_is2D ();
 
     // Axes planes
     set_color (axe_color);
     set_polygon_offset (true, 9.0);
 
-    glBegin (GL_QUADS);
-
-    if (! is2d)
+    m_glfcns.glBegin (GL_QUADS);
+
+    if (! is2D)
       {
         // X plane
-        glVertex3d (xPlane, yPlaneN, zPlaneN);
-        glVertex3d (xPlane, yPlane, zPlaneN);
-        glVertex3d (xPlane, yPlane, zPlane);
-        glVertex3d (xPlane, yPlaneN, zPlane);
+        m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
+        m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
+        m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
+        m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
 
         // Y plane
-        glVertex3d (xPlaneN, yPlane, zPlaneN);
-        glVertex3d (xPlane, yPlane, zPlaneN);
-        glVertex3d (xPlane, yPlane, zPlane);
-        glVertex3d (xPlaneN, yPlane, zPlane);
+        m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
+        m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
+        m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
+        m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
       }
 
     // Z plane
-    glVertex3d (xPlaneN, yPlaneN, zPlane);
-    glVertex3d (xPlane, yPlaneN, zPlane);
-    glVertex3d (xPlane, yPlane, zPlane);
-    glVertex3d (xPlaneN, yPlane, zPlane);
-
-    glEnd ();
+    m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlane);
+    m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
+    m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
+    m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
+
+    m_glfcns.glEnd ();
 
     set_polygon_offset (false);
 
@@ -1215,7 +1310,7 @@
 
     bool xySym = props.get_xySym ();
     bool layer2Dtop = props.get_layer2Dtop ();
-    bool is2d = props.get_is2D ();
+    bool is2D = props.get_is2D ();
     bool isXOrigin = props.xaxislocation_is ("origin")
                      && ! props.yscale_is ("log");
     bool isYOrigin = props.yaxislocation_is ("origin")
@@ -1242,7 +1337,7 @@
     set_linecap ("square");
     set_linestyle ("-", true, linewidth);
 
-    glBegin (GL_LINES);
+    m_glfcns.glBegin (GL_LINES);
 
     if (layer2Dtop)
       std::swap (zpTick, zpTickN);
@@ -1250,94 +1345,94 @@
     // X box
     set_color (props.get_xcolor_rgb ());
 
-    if (! isXOrigin || props.is_box() || ! is2d)
+    if (! isXOrigin || props.is_box() || ! is2D)
       {
-        glVertex3d (xPlaneN, ypTick, zpTick);
-        glVertex3d (xPlane, ypTick, zpTick);
+        m_glfcns.glVertex3d (xPlaneN, ypTick, zpTick);
+        m_glfcns.glVertex3d (xPlane, ypTick, zpTick);
       }
 
     if (props.is_box ())
       {
-        glVertex3d (xPlaneN, ypTickN, zpTick);
-        glVertex3d (xPlane, ypTickN, zpTick);
-        if (! is2d)
+        m_glfcns.glVertex3d (xPlaneN, ypTickN, zpTick);
+        m_glfcns.glVertex3d (xPlane, ypTickN, zpTick);
+        if (! is2D)
           {
-            glVertex3d (xPlaneN, ypTickN, zpTickN);
-            glVertex3d (xPlane, ypTickN, zpTickN);
+            m_glfcns.glVertex3d (xPlaneN, ypTickN, zpTickN);
+            m_glfcns.glVertex3d (xPlane, ypTickN, zpTickN);
             if (boxFull)
               {
-                glVertex3d (xPlaneN, ypTick, zpTickN);
-                glVertex3d (xPlane, ypTick, zpTickN);
+                m_glfcns.glVertex3d (xPlaneN, ypTick, zpTickN);
+                m_glfcns.glVertex3d (xPlane, ypTick, zpTickN);
               }
           }
       }
 
     // Y box
     set_color (props.get_ycolor_rgb ());
-    if (! isYOrigin || props.is_box() || ! is2d)
+    if (! isYOrigin || props.is_box() || ! is2D)
       {
-        glVertex3d (xpTick, yPlaneN, zpTick);
-        glVertex3d (xpTick, yPlane, zpTick);
+        m_glfcns.glVertex3d (xpTick, yPlaneN, zpTick);
+        m_glfcns.glVertex3d (xpTick, yPlane, zpTick);
       }
 
     if (props.is_box () && ! plotyy)
       {
-        glVertex3d (xpTickN, yPlaneN, zpTick);
-        glVertex3d (xpTickN, yPlane, zpTick);
-
-        if (! is2d)
+        m_glfcns.glVertex3d (xpTickN, yPlaneN, zpTick);
+        m_glfcns.glVertex3d (xpTickN, yPlane, zpTick);
+
+        if (! is2D)
           {
-            glVertex3d (xpTickN, yPlaneN, zpTickN);
-            glVertex3d (xpTickN, yPlane, zpTickN);
+            m_glfcns.glVertex3d (xpTickN, yPlaneN, zpTickN);
+            m_glfcns.glVertex3d (xpTickN, yPlane, zpTickN);
             if (boxFull)
               {
-                glVertex3d (xpTick, yPlaneN, zpTickN);
-                glVertex3d (xpTick, yPlane, zpTickN);
+                m_glfcns.glVertex3d (xpTick, yPlaneN, zpTickN);
+                m_glfcns.glVertex3d (xpTick, yPlane, zpTickN);
               }
           }
       }
 
     // Z box
-    if (! is2d)
+    if (! is2D)
       {
         set_color (props.get_zcolor_rgb ());
 
         if (xySym)
           {
-            glVertex3d (xPlaneN, yPlane, zPlaneN);
-            glVertex3d (xPlaneN, yPlane, zPlane);
+            m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
+            m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
           }
         else
           {
-            glVertex3d (xPlane, yPlaneN, zPlaneN);
-            glVertex3d (xPlane, yPlaneN, zPlane);
+            m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
+            m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
           }
 
         if (props.is_box ())
           {
-            glVertex3d (xPlane, yPlane, zPlaneN);
-            glVertex3d (xPlane, yPlane, zPlane);
+            m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
+            m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
 
             if (xySym)
               {
-                glVertex3d (xPlane, yPlaneN, zPlaneN);
-                glVertex3d (xPlane, yPlaneN, zPlane);
+                m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
+                m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
               }
             else
               {
-                glVertex3d (xPlaneN, yPlane, zPlaneN);
-                glVertex3d (xPlaneN, yPlane, zPlane);
+                m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
+                m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
               }
 
             if (boxFull)
               {
-                glVertex3d (xPlaneN, yPlaneN, zPlaneN);
-                glVertex3d (xPlaneN, yPlaneN, zPlane);
+                m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlaneN);
+                m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlane);
               }
           }
       }
 
-    glEnd ();
+    m_glfcns.glEnd ();
 
     set_linestyle ("-");  // Disable LineStipple
 
@@ -1451,11 +1546,11 @@
         if (is_origin)
           {
             y_axis_pos = math::max (math::min (0., y_max), y_min);
-            glBegin (GL_LINES);
+            m_glfcns.glBegin (GL_LINES);
             set_color (props.get_ycolor_rgb ());
-            glVertex3d (x_min, y_axis_pos, zpTick);
-            glVertex3d (x_max, y_axis_pos, zpTick);
-            glEnd ();
+            m_glfcns.glVertex3d (x_min, y_axis_pos, zpTick);
+            m_glfcns.glVertex3d (x_max, y_axis_pos, zpTick);
+            m_glfcns.glEnd ();
           }
 
         // minor tick marks
@@ -1634,11 +1729,11 @@
         if (is_origin)
           {
             x_axis_pos = math::max (math::min (0., x_max), x_min);
-            glBegin (GL_LINES);
+            m_glfcns.glBegin (GL_LINES);
             set_color (props.get_ycolor_rgb ());
-            glVertex3d (x_axis_pos, y_min, zpTick);
-            glVertex3d (x_axis_pos, y_max, zpTick);
-            glEnd ();
+            m_glfcns.glVertex3d (x_axis_pos, y_min, zpTick);
+            m_glfcns.glVertex3d (x_axis_pos, y_max, zpTick);
+            m_glfcns.glEnd ();
           }
 
         // minor tick marks
@@ -1896,10 +1991,10 @@
     // Disable line smoothing for axes
     GLboolean antialias;
 
-    glGetBooleanv (GL_LINE_SMOOTH, &antialias);
+    m_glfcns.glGetBooleanv (GL_LINE_SMOOTH, &antialias);
 
     if (antialias == GL_TRUE)
-      glDisable (GL_LINE_SMOOTH);
+      m_glfcns.glDisable (GL_LINE_SMOOTH);
 
     set_linecap ("butt");
     set_linewidth (props.get_linewidth ());
@@ -1911,7 +2006,7 @@
     draw_axes_z_grid (props);
 
     if (antialias == GL_TRUE)
-      glEnable (GL_LINE_SMOOTH);
+      m_glfcns.glEnable (GL_LINE_SMOOTH);
 #else
 
     octave_unused_parameter (props);
@@ -1942,17 +2037,12 @@
           {
             if (go.isa ("light") && ! selecting)
               {
-                if (num_lights < max_lights)
+                if (m_current_light-GL_LIGHT0 < m_max_lights)
                   {
-                    current_light = GL_LIGHT0 + num_lights;
                     set_clipping (p.is_clipping ());
                     draw (go);
-                    num_lights++;
+                    m_current_light++;
                   }
-                else
-                  warning_with_id ("Octave:max-lights-exceeded",
-                                   "light: Maximum number of lights (%d) in these axes is "
-                                   "exceeded.", max_lights);
               }
             else if (go.isa ("hggroup")
                      && ! (selecting && p.pickableparts_is ("none")))
@@ -1974,29 +2064,6 @@
 #endif
   }
 
-#if defined (HAVE_OPENGL)
-
-  static int
-  get_maxlights (void)
-  {
-    static int max_lights = 0;
-
-    // Check actual maximum number of lights possible
-    if (max_lights == 0)
-      {
-        for (max_lights = 0; max_lights < GL_MAX_LIGHTS; max_lights++)
-          {
-            glDisable (GL_LIGHT0 + max_lights);
-            if (glGetError ())
-              break;
-          }
-      }
-
-    return max_lights;
-  }
-
-#endif
-
   void
   opengl_renderer::draw_axes_children (const axes::properties& props)
   {
@@ -2012,18 +2079,22 @@
     // but this seems to lead to calls of OpenGL functions before the context
     // is actually initialized.  See bug #48669.
     // Check actual maximum number of lights possible
-    max_lights = get_maxlights ();
+    init_maxlights ();
 
     // Start with the last element of the array of child objects to
     // display them in the order they were added to the array.
 
-    num_lights = 0;
-    current_light = GL_LIGHT0;
+    if (props.get_num_lights () > m_max_lights)
+      warning_with_id ("Octave:max-lights-exceeded",
+                       "light: Maximum number of lights (%d) in these axes is "
+                       "exceeded.", m_max_lights);
+
+    m_current_light = GL_LIGHT0;
     draw_all_lights (props, obj_list);
 
     // disable other OpenGL lights
-    for (int i = num_lights; i < max_lights; i++)
-      glDisable (GL_LIGHT0 + i);
+    for (unsigned int i = props.get_num_lights (); i < m_max_lights; i++)
+      m_glfcns.glDisable (GL_LIGHT0 + i);
 
     // save camera position and set ambient light color before drawing
     // other objects
@@ -2033,7 +2104,7 @@
     ColumnVector ambient_color = props.get_ambientlightcolor_rgb ();
     for (int i = 0; i < 3; i++)
       cb[i] = ambient_color(i);
-    glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
+    m_glfcns.glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
 
     // 2nd pass: draw other objects (with units set to "data")
 
@@ -2057,7 +2128,7 @@
 
     // 3rd pass: draw remaining objects
 
-    glDisable (GL_DEPTH_TEST);
+    m_glfcns.glDisable (GL_DEPTH_TEST);
 
     for (it = obj_list.begin (); it != obj_list.end (); it++)
       {
@@ -2120,9 +2191,9 @@
     // depth sorting
     bool is2D = props.get_is2D (true);
     if (is2D)
-      glDisable (GL_DEPTH_TEST);
+      m_glfcns.glDisable (GL_DEPTH_TEST);
     else
-      glEnable (GL_DEPTH_TEST);
+      m_glfcns.glEnable (GL_DEPTH_TEST);
 
     draw_axes_planes (props);
 
@@ -2171,9 +2242,10 @@
     int n = static_cast<int> (std::min (std::min (x.numel (), y.numel ()),
                                         (has_z ? z.numel ()
                                          : std::numeric_limits<int>::max ())));
-    octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40);
-
-    std::vector<octave_uint8> clip (n);
+    uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
+    uint8_t clip_ok = 0x40;
+
+    std::vector<uint8_t> clip (n);
 
     if (has_z)
       for (int i = 0; i < n; i++)
@@ -2205,20 +2277,20 @@
                     if (! flag)
                       {
                         flag = true;
-                        glBegin (GL_LINE_STRIP);
-                        glVertex3d (x(i-1), y(i-1), z(i-1));
+                        m_glfcns.glBegin (GL_LINE_STRIP);
+                        m_glfcns.glVertex3d (x(i-1), y(i-1), z(i-1));
                       }
-                    glVertex3d (x(i), y(i), z(i));
+                    m_glfcns.glVertex3d (x(i), y(i), z(i));
                   }
                 else if (flag)
                   {
                     flag = false;
-                    glEnd ();
+                    m_glfcns.glEnd ();
                   }
               }
 
             if (flag)
-              glEnd ();
+              m_glfcns.glEnd ();
           }
         else
           {
@@ -2231,20 +2303,20 @@
                     if (! flag)
                       {
                         flag = true;
-                        glBegin (GL_LINE_STRIP);
-                        glVertex2d (x(i-1), y(i-1));
+                        m_glfcns.glBegin (GL_LINE_STRIP);
+                        m_glfcns.glVertex2d (x(i-1), y(i-1));
                       }
-                    glVertex2d (x(i), y(i));
+                    m_glfcns.glVertex2d (x(i), y(i));
                   }
                 else if (flag)
                   {
                     flag = false;
-                    glEnd ();
+                    m_glfcns.glEnd ();
                   }
               }
 
             if (flag)
-              glEnd ();
+              m_glfcns.glEnd ();
           }
 
         set_linewidth (0.5f);
@@ -2316,7 +2388,16 @@
     int zc = z.columns ();
 
     NDArray c;
-    const NDArray n = props.get_vertexnormals ().array_value ();
+    const NDArray vn = props.get_vertexnormals ().array_value ();
+    dim_vector vn_dims = vn.dims ();
+    bool has_vertex_normals = ((vn_dims(0) == z.rows ()) &&
+                               (vn_dims(1) == z.columns ()) &&
+                               (vn_dims(2) == 3));
+    const NDArray fn = props.get_facenormals ().array_value ();
+    dim_vector fn_dims = fn.dims ();
+    bool has_face_normals = ((fn_dims(0) == z.rows () - 1) &&
+                             (fn_dims(1) == z.columns () - 1) &&
+                             (fn_dims(2) == 3));
 
     // FIXME: handle transparency
     Matrix a;
@@ -2326,18 +2407,23 @@
                     (props.facecolor_is ("interp") ? 2 :
                      (props.facecolor_is ("texturemap") ? 3 : -1))));
     int fl_mode = (props.facelighting_is ("none") ? 0 :
-                   (props.facelighting_is ("flat") ? 1 : 2));
+                   (props.facelighting_is ("flat") ?
+                    (has_face_normals ? 1 : 0) :
+                    (has_vertex_normals ? 2 : 0)));
     int fa_mode = (props.facealpha_is_double () ? 0 :
                    (props.facealpha_is ("flat") ? 1 : 2));
     int ec_mode = (props.edgecolor_is_rgb () ? 0 :
                    (props.edgecolor_is ("flat") ? 1 :
                     (props.edgecolor_is ("interp") ? 2 : -1)));
     int el_mode = (props.edgelighting_is ("none") ? 0 :
-                   (props.edgelighting_is ("flat") ? 1 : 2));
+                   (props.edgelighting_is ("flat") ?
+                    (has_face_normals ? 1 : 0) :
+                    (has_vertex_normals ? 2 : 0)));
     int ea_mode = (props.edgealpha_is_double () ? 0 :
                    (props.edgealpha_is ("flat") ? 1 : 2));
     int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
                     (props.backfacelighting_is ("reverselit") ? 1 : 2));
+    bool do_lighting = props.get_do_lighting ();
 
     Matrix fcolor = (fc_mode == TEXTURE ? Matrix (1, 3, 1.0)
                                         : props.get_facecolor_rgb ());
@@ -2351,7 +2437,7 @@
     float scr = props.get_specularcolorreflectance ();
     float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
 
-    opengl_texture tex;
+    opengl_texture tex (m_glfcns);
 
     int i1, i2, j1, j2;
     bool x_mat = (x.rows () == z.rows ());
@@ -2385,12 +2471,12 @@
       }
 
     if (fl_mode > 0 || el_mode > 0)
-      glMaterialf (LIGHT_MODE, GL_SHININESS, se);
+      m_glfcns.glMaterialf (LIGHT_MODE, GL_SHININESS, se);
 
     // FIXME: good candidate for caching,
     //        transferring pixel data to OpenGL is time consuming.
     if (fc_mode == TEXTURE)
-      tex = opengl_texture::create (props.get_color_data ());
+      tex = opengl_texture::create (m_glfcns, props.get_color_data ());
 
     if (draw_all || ! props.facecolor_is ("none"))
       {
@@ -2399,30 +2485,30 @@
             fa = props.get_facealpha_double ();
             if (fc_mode == UNIFORM || fc_mode == TEXTURE)
               {
-                glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
+                m_glfcns.glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
                 if (fl_mode > 0)
                   {
                     for (int i = 0; i < 3; i++)
                       cb[i] = as * fcolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ds * fcolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ss * (scr + (1-scr) * fcolor(i));
-                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                   }
               }
 
-            if ((fl_mode > 0) && (num_lights > 0))
-              glEnable (GL_LIGHTING);
-            glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD)
+            if ((fl_mode > 0) && do_lighting)
+              m_glfcns.glEnable (GL_LIGHTING);
+            m_glfcns.glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD)
                           ? GL_SMOOTH : GL_FLAT);
             set_polygon_offset (true, 1.0);
             if (fc_mode == TEXTURE)
-              glEnable (GL_TEXTURE_2D);
+              m_glfcns.glEnable (GL_TEXTURE_2D);
 
             for (int i = 1; i < zc; i++)
               {
@@ -2459,7 +2545,7 @@
                         j2 = j;
                       }
 
-                    glBegin (GL_QUADS);
+                    m_glfcns.glBegin (GL_QUADS);
 
                     // Vertex 1
                     if (fc_mode == TEXTURE)
@@ -2471,27 +2557,28 @@
                         for (int k = 0; k < 3; k++)
                           cb[k] = c(j-1, i-1, k);
                         cb[3] = fa;
-                        glColor4fv (cb);
+                        m_glfcns.glColor4fv (cb);
 
                         if (fl_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] *= as;
-                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ds * c(j-1, i-1, k);
-                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ss * (scr + (1-scr) * c(j-1, i-1, k));
-                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                           }
                       }
                     if (fl_mode > 0)
-                      set_normal (bfl_mode, n, j-1, i-1);
-
-                    glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
+                      set_normal (bfl_mode, (fl_mode == GOURAUD ? vn : fn),
+                                  j-1, i-1);
+
+                    m_glfcns.glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
 
                     // Vertex 2
                     if (fc_mode == TEXTURE)
@@ -2501,28 +2588,28 @@
                         for (int k = 0; k < 3; k++)
                           cb[k] = c(j-1, i, k);
                         cb[3] = fa;
-                        glColor4fv (cb);
+                        m_glfcns.glColor4fv (cb);
 
                         if (fl_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] *= as;
-                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ds * c(j-1, i, k);
-                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
-                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                           }
                       }
 
                     if (fl_mode == GOURAUD)
-                      set_normal (bfl_mode, n, j-1, i);
-
-                    glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
+                      set_normal (bfl_mode, vn, j-1, i);
+
+                    m_glfcns.glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
 
                     // Vertex 3
                     if (fc_mode == TEXTURE)
@@ -2532,27 +2619,27 @@
                         for (int k = 0; k < 3; k++)
                           cb[k] = c(j, i, k);
                         cb[3] = fa;
-                        glColor4fv (cb);
+                        m_glfcns.glColor4fv (cb);
 
                         if (fl_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] *= as;
-                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ds * c(j, i, k);
-                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                           }
                       }
                     if (fl_mode == GOURAUD)
-                      set_normal (bfl_mode, n, j, i);
-
-                    glVertex3d (x(j2,i), y(j,i2), z(j,i));
+                      set_normal (bfl_mode, vn, j, i);
+
+                    m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
 
                     // Vertex 4
                     if (fc_mode == TEXTURE)
@@ -2562,38 +2649,38 @@
                         for (int k = 0; k < 3; k++)
                           cb[k] = c(j, i-1, k);
                         cb[3] = fa;
-                        glColor4fv (cb);
+                        m_glfcns.glColor4fv (cb);
 
                         if (fl_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] *= as;
-                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ds * c(j, i-1, k);
-                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                             for (int k = 0; k < 3; k++)
                               cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
-                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                            m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                           }
                       }
                     if (fl_mode == GOURAUD)
-                      set_normal (bfl_mode, n, j, i-1);
-
-                    glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
-
-                    glEnd ();
+                      set_normal (bfl_mode, vn, j, i-1);
+
+                    m_glfcns.glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
+
+                    m_glfcns.glEnd ();
                   }
               }
 
             set_polygon_offset (false);
             if (fc_mode == TEXTURE)
-              glDisable (GL_TEXTURE_2D);
-
-            if ((fl_mode > 0) && (num_lights > 0))
-              glDisable (GL_LIGHTING);
+              m_glfcns.glDisable (GL_TEXTURE_2D);
+
+            if ((fl_mode > 0) && do_lighting)
+              m_glfcns.glDisable (GL_LIGHTING);
           }
         else
           {
@@ -2607,26 +2694,26 @@
           {
             if (ec_mode == UNIFORM)
               {
-                glColor3dv (ecolor.data ());
+                m_glfcns.glColor3dv (ecolor.data ());
                 if (fl_mode > 0)
                   {
                     for (int i = 0; i < 3; i++)
                       cb[i] = as * ecolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ds * ecolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ss * (scr + (1-scr) * ecolor(i));
-                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                   }
               }
 
-            if ((el_mode > 0) && (num_lights > 0))
-              glEnable (GL_LIGHTING);
-            glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
+            if ((el_mode > 0) && do_lighting)
+              m_glfcns.glEnable (GL_LIGHTING);
+            m_glfcns.glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
                           ? GL_SMOOTH : GL_FLAT);
 
             set_linestyle (props.get_linestyle (), false,
@@ -2671,63 +2758,64 @@
                             j2 = j;
                           }
 
-                        glBegin (GL_LINES);
+                        m_glfcns.glBegin (GL_LINES);
 
                         // Vertex 1
                         if (ec_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] = c(j-1, i, k);
-                            glColor3fv (cb);
+                            m_glfcns.glColor3fv (cb);
 
                             if (el_mode > 0)
                               {
                                 for (int k = 0; k < 3; k++)
                                   cb[k] *= as;
-                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ds * c(j-1, i, k);
-                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
-                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                               }
                           }
                         if (el_mode > 0)
-                          set_normal (bfl_mode, n, j-1, i);
-
-                        glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
+                          set_normal (bfl_mode, (el_mode == GOURAUD ? vn : fn),
+                                      j-1, i);
+
+                        m_glfcns.glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
 
                         // Vertex 2
                         if (ec_mode == INTERP)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] = c(j, i, k);
-                            glColor3fv (cb);
+                            m_glfcns.glColor3fv (cb);
 
                             if (el_mode > 0)
                               {
                                 for (int k = 0; k < 3; k++)
                                   cb[k] *= as;
-                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ds * c(j, i, k);
-                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                               }
                           }
                         if (el_mode == GOURAUD)
-                          set_normal (bfl_mode, n, j, i);
-
-                        glVertex3d (x(j2,i), y(j,i2), z(j,i));
-
-                        glEnd ();
+                          set_normal (bfl_mode, vn, j, i);
+
+                        m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
+
+                        m_glfcns.glEnd ();
                       }
                   }
               }
@@ -2768,63 +2856,64 @@
                             i2 = i;
                           }
 
-                        glBegin (GL_LINES);
+                        m_glfcns.glBegin (GL_LINES);
 
                         // Vertex 1
                         if (ec_mode > 0)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] = c(j, i-1, k);
-                            glColor3fv (cb);
+                            m_glfcns.glColor3fv (cb);
 
                             if (el_mode > 0)
                               {
                                 for (int k = 0; k < 3; k++)
                                   cb[k] *= as;
-                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ds * c(j, i-1, k);
-                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
-                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                               }
                           }
                         if (el_mode > 0)
-                          set_normal (bfl_mode, n, j, i-1);
-
-                        glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
+                          set_normal (bfl_mode, (el_mode == GOURAUD ? vn : fn),
+                                      j, i-1);
+
+                        m_glfcns.glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
 
                         // Vertex 2
                         if (ec_mode == INTERP)
                           {
                             for (int k = 0; k < 3; k++)
                               cb[k] = c(j, i, k);
-                            glColor3fv (cb);
+                            m_glfcns.glColor3fv (cb);
 
                             if (el_mode > 0)
                               {
                                 for (int k = 0; k < 3; k++)
                                   cb[k] *= as;
-                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ds * c(j, i, k);
-                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                                 for (int k = 0; k < 3; k++)
                                   cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                               }
                           }
                         if (el_mode == GOURAUD)
-                          set_normal (bfl_mode, n, j, i);
-
-                        glVertex3d (x(j2,i), y(j,i2), z(j,i));
-
-                        glEnd ();
+                          set_normal (bfl_mode, vn, j, i);
+
+                        m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
+
+                        m_glfcns.glEnd ();
                       }
                   }
               }
@@ -2832,8 +2921,8 @@
             set_linestyle ("-");  // Disable LineStipple
             set_linewidth (0.5f);
 
-            if ((el_mode > 0) && (num_lights > 0))
-              glDisable (GL_LIGHTING);
+            if ((el_mode > 0) && do_lighting)
+              m_glfcns.glDisable (GL_LIGHTING);
           }
         else
           {
@@ -2876,6 +2965,9 @@
         init_marker (props.get_marker (), props.get_markersize (),
                      props.get_linewidth ());
 
+        uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
+        uint8_t clip_ok = 0x40;
+
         for (int i = 0; i < zc; i++)
           {
             if (y_mat)
@@ -2883,12 +2975,13 @@
 
             for (int j = 0; j < zr; j++)
               {
-                if (clip(j,i))
-                  continue;
-
                 if (x_mat)
                   j1 = j;
 
+                if ((clip_code (x(j1,i), y(j,i1), z(j,i)) & clip_mask)
+                    != clip_ok)
+                  continue;
+
                 if ((do_edge && mecolor.isempty ())
                     || (do_face && mfcolor.isempty ()))
                   {
@@ -2942,7 +3035,6 @@
     const Matrix f = props.get_faces ().matrix_value ();
     const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
     Matrix c;
-    const Matrix n = props.get_vertexnormals ().matrix_value ();
     Matrix a;
     double fa = 1.0;
 
@@ -2953,8 +3045,6 @@
     bool has_z = (v.columns () > 2);
     bool has_facecolor = false;
     bool has_facealpha = false;
-    // FIXME: remove when patch object has normal computation (patch #8951)
-    bool has_normals = (n.rows () == nv);
 
     int fc_mode = ((props.facecolor_is ("none")
                     || props.facecolor_is_rgb () || draw_all) ? 0 :
@@ -2972,6 +3062,7 @@
                    (props.edgealpha_is ("flat") ? 1 : 2));
     int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
                     (props.backfacelighting_is ("reverselit") ? 1 : 2));
+    bool do_lighting = props.get_do_lighting ();
 
     Matrix fcolor = props.get_facecolor_rgb ();
     Matrix ecolor = props.get_edgecolor_rgb ();
@@ -2982,6 +3073,11 @@
     float se = props.get_specularexponent () * 5; // to fit Matlab
     float scr = props.get_specularcolorreflectance ();
 
+    const Matrix vn = props.get_vertexnormals ().matrix_value ();
+    bool has_vertex_normals = (vn.rows () == nv);
+    const Matrix fn = props.get_facenormals ().matrix_value ();
+    bool has_face_normals = (fn.rows () == nf);
+
     boolMatrix clip (1, nv, false);
 
     if (has_z)
@@ -3055,23 +3151,37 @@
 
           Matrix vv (1, 3, 0.0);
           Matrix cc;
-          Matrix nn (1, 3, 0.0);
+          Matrix vnn (1, 3, 0.0);
+          Matrix fnn (1, 3, 0.0);
           double aa = 1.0;
 
           vv(0) = v(idx,0); vv(1) = v(idx,1);
           if (has_z)
             vv(2) = v(idx,2);
-          if (has_normals)
+          if (((fl_mode == FLAT) || (el_mode == FLAT)) && has_face_normals)
             {
               double dir = 1.0;
               if (bfl_mode > 0)
-                dir = ((n(idx,0) * view_vector(0)
-                        + n(idx,1) * view_vector(1)
-                        + n(idx,2) * view_vector(2) < 0)
+                dir = ((fn(i,0) * view_vector(0)
+                        + fn(i,1) * view_vector(1)
+                        + fn(i,2) * view_vector(2) < 0)
                        ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
-              nn(0) = dir * n(idx,0);
-              nn(1) = dir * n(idx,1);
-              nn(2) = dir * n(idx,2);
+              fnn(0) = dir * fn(i,0);
+              fnn(1) = dir * fn(i,1);
+              fnn(2) = dir * fn(i,2);
+            }
+          if (((fl_mode == GOURAUD) || (el_mode == GOURAUD)) &&
+              has_vertex_normals)
+            {
+              double dir = 1.0;
+              if (bfl_mode > 0)
+                dir = ((vn(idx,0) * view_vector(0)
+                        + vn(idx,1) * view_vector(1)
+                        + vn(idx,2) * view_vector(2) < 0)
+                       ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
+              vnn(0) = dir * vn(idx,0);
+              vnn(1) = dir * vn(idx,1);
+              vnn(2) = dir * vn(idx,2);
             }
           if (c.numel () > 0)
             {
@@ -3091,11 +3201,13 @@
                 aa = a(idx);
             }
 
-          vdata[i+j*fr] = vertex_data (vv, cc, nn, aa, as, ds, ss, se, scr);
+          vdata[i+j*fr] = vertex_data (vv, cc, vnn, fnn, aa, as, ds, ss, se, scr);
         }
 
     if (fl_mode > 0 || el_mode > 0)
-      glMaterialf (LIGHT_MODE, GL_SHININESS, se);
+      m_glfcns.glMaterialf (LIGHT_MODE, GL_SHININESS, se);
+
+    std::list<std::list<octave_idx_type>>::const_iterator it1;
 
     if (draw_all || ! props.facecolor_is ("none"))
       {
@@ -3104,91 +3216,130 @@
           {
             if (fc_mode == UNIFORM)
               {
-                glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
+                m_glfcns.glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
                 if (fl_mode > 0)
                   {
                     float cb[4] = { 0, 0, 0, 1 };
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = as * fcolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ds * fcolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ss * (scr + (1-scr) * fcolor(i));
-                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                   }
               }
 
-            if ((fl_mode > 0) && (num_lights > 0) && has_normals)
-              glEnable (GL_LIGHTING);
-
-            // NOTE: Push filled part of patch backwards to avoid Z-fighting with
-            // tesselator outline.  A value of 1.0 seems to work fine.  Value
-            // can't be too large or the patch will be pushed below the axes
-            // planes at +2.5.
+            if ((fl_mode > 0) && do_lighting)
+              m_glfcns.glEnable (GL_LIGHTING);
+
+            // NOTE: Push filled part of patch backwards to avoid Z-fighting
+            // with tesselator outline.  A value of 1.0 seems to work fine.
+            // Value can't be too large or the patch will be pushed below the
+            // axes planes at +2.5.
             patch_tesselator tess (this, fc_mode, fl_mode, 1.0);
 
+            it1 = props.coplanar_last_idx.begin ();
+            std::list<octave_idx_type>::const_iterator it2;
+            octave_idx_type i_start, i_end;
+
             for (int i = 0; i < nf; i++)
               {
                 if (clip_f(i))
                   continue;
 
-                tess.begin_polygon (true);
-                tess.begin_contour ();
-
-                // Add vertices in reverse order for Matlab compatibility
-                for (int j = count_f(i)-1; j > 0; j--)
+                bool is_non_planar = false;
+                if (props.coplanar_last_idx.size () > 0 && (*it1).size () > 1)
+                  {
+                    is_non_planar = true;
+                    it2 = (*it1).end ();
+                    it2--;
+                  }
+
+                // loop over planar subsets of face
+                do
                   {
-                    vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
-
-                    tess.add_vertex (vv->coords.fortran_vec (), vv);
-                  }
-
-                if (count_f(i) > 0)
-                  {
-                    vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
-
-                    if (fc_mode == FLAT)
+                    if (is_non_planar)
+                      {
+                        i_end = *it2;
+                        if (it2 == (*it1).begin ())
+                          i_start = 0;
+                        else
+                          {
+                            it2--;
+                            i_start = *it2 - 1;
+                          }
+                      }
+                    else
+                      {
+                        i_end = count_f(i) - 1;
+                        i_start = 0;
+                      }
+
+                    tess.begin_polygon (true);
+                    tess.begin_contour ();
+
+                    // Add vertices in reverse order for Matlab compatibility
+                    for (int j = i_end; j > i_start; j--)
                       {
-                        // For "flat" shading, use color of 1st vertex.
-                        Matrix col = vv->color;
-
-                        if (col.numel () == 3)
+                        vertex_data::vertex_data_rep *vv =
+                          vdata[i+j*fr].get_rep ();
+
+                        tess.add_vertex (vv->coords.fortran_vec (), vv);
+                      }
+
+                    if (count_f(i) > 0)
+                      {
+                        vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
+
+                        if (fc_mode == FLAT)
                           {
-                            glColor4d (col(0), col(1), col(2), fa);
-                            if (fl_mode > 0)
+                            // For "flat" shading, use color of 1st vertex.
+                            Matrix col = vv->color;
+
+                            if (col.numel () == 3)
                               {
-                                float cb[4] = { 0, 0, 0, 1 };
-
-                                for (int k = 0; k < 3; k++)
-                                  cb[k] = (vv->ambient * col(k));
-                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                                for (int k = 0; k < 3; k++)
-                                  cb[k] = (vv->diffuse * col(k));
-                                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) * col(k));
-                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                m_glfcns.glColor4d (col(0), col(1), col(2), fa);
+                                if (fl_mode > 0)
+                                  {
+                                    float cb[4] = { 0, 0, 0, 1 };
+
+                                    for (int k = 0; k < 3; k++)
+                                      cb[k] = (vv->ambient * col(k));
+                                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                    for (int k = 0; k < 3; k++)
+                                      cb[k] = (vv->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) *
+                                              col(k));
+                                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                                  }
                               }
                           }
+
+                        tess.add_vertex (vv->coords.fortran_vec (), vv);
                       }
 
-                    tess.add_vertex (vv->coords.fortran_vec (), vv);
-                  }
-
-                tess.end_contour ();
-                tess.end_polygon ();
+                    tess.end_contour ();
+                    tess.end_polygon ();
+                  } while (i_start > 0);
+
+                if (is_non_planar)
+                  it1++;
               }
 
-            if ((fl_mode > 0) && (num_lights > 0) && has_normals)
-              glDisable (GL_LIGHTING);
+            if ((fl_mode > 0) && do_lighting)
+              m_glfcns.glDisable (GL_LIGHTING);
           }
         else
           {
@@ -3204,27 +3355,27 @@
           {
             if (ec_mode == UNIFORM)
               {
-                glColor3dv (ecolor.data ());
+                m_glfcns.glColor3dv (ecolor.data ());
                 if (el_mode > 0)
                   {
                     float cb[4] = { 0, 0, 0, 1 };
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = (as * ecolor(i));
-                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ds * ecolor(i);
-                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                     for (int i = 0; i < 3; i++)
                       cb[i] = ss * (scr + (1-scr) * ecolor(i));
-                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                    m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                   }
               }
 
-            if ((el_mode > 0) && (num_lights > 0) && has_normals)
-              glEnable (GL_LIGHTING);
+            if ((el_mode > 0) && do_lighting)
+              m_glfcns.glEnable (GL_LIGHTING);
 
             double linewidth = props.get_linewidth ();
             set_linestyle (props.get_linestyle (), false, linewidth);
@@ -3239,14 +3390,20 @@
             // not supported by glPolygonOffset which is used to do Z offsets.
             patch_tesselator tess (this, ec_mode, el_mode);
 
+            it1 = props.coplanar_last_idx.begin ();
+
             for (int i = 0; i < nf; i++)
               {
-                if (clip_f(i))
+                bool is_non_planar = false;
+                if (props.coplanar_last_idx.size () > 0 && (*it1).size () > 1)
+                  is_non_planar = true;
+                if (clip_f(i) || is_non_planar)
                   {
-                    // This is an unclosed contour.  Draw it as a line.
+                    // This is an unclosed contour or a non-planar face.
+                    // Draw it as a line.
                     bool flag = false;
 
-                    glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
+                    m_glfcns.glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
                                   ? GL_SMOOTH : GL_FLAT);
 
                     // Add vertices in reverse order for Matlab compatibility
@@ -3260,21 +3417,21 @@
                             if (! flag)
                               {
                                 flag = true;
-                                glBegin (GL_LINE_STRIP);
+                                m_glfcns.glBegin (GL_LINE_STRIP);
                               }
                             if (ec_mode != UNIFORM)
                               {
                                 Matrix col = vv->color;
 
                                 if (col.numel () == 3)
-                                  glColor3dv (col.data ());
+                                  m_glfcns.glColor3dv (col.data ());
                               }
-                            glVertex3d (m(0), m(1), m(2));
+                            m_glfcns.glVertex3d (m(0), m(1), m(2));
                           }
                         else if (flag)
                           {
                             flag = false;
-                            glEnd ();
+                            m_glfcns.glEnd ();
                           }
                       }
                     // Do loop body with vertex N to "close" GL_LINE_STRIP
@@ -3290,13 +3447,13 @@
                             Matrix col = vv->color;
 
                             if (col.numel () == 3)
-                              glColor3dv (col.data ());
+                              m_glfcns.glColor3dv (col.data ());
                           }
-                        glVertex3d (m(0), m(1), m(2));
+                        m_glfcns.glVertex3d (m(0), m(1), m(2));
                       }
 
                     if (flag)
-                      glEnd ();
+                      m_glfcns.glEnd ();
                   }
                 else  // Normal edge contour drawn with tesselator
                   {
@@ -3313,13 +3470,15 @@
                     tess.end_contour ();
                     tess.end_polygon ();
                   }
+                if (is_non_planar)
+                  it1++;
               }
 
             set_linestyle ("-");  // Disable LineStipple
             set_linewidth (0.5f);
 
-            if ((el_mode > 0) && (num_lights > 0) && has_normals)
-              glDisable (GL_LIGHTING);
+            if ((el_mode > 0) && do_lighting)
+              m_glfcns.glDisable (GL_LIGHTING);
           }
         else
           {
@@ -3367,12 +3526,16 @@
         init_marker (props.get_marker (), props.get_markersize (),
                      props.get_linewidth ());
 
+        uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
+        uint8_t clip_ok = 0x40;
+
         for (int i = 0; i < nf; i++)
           for (int j = 0; j < count_f(i); j++)
             {
               int idx = int (f(i,j) - 1);
 
-              if (clip(idx))
+              if ((clip_code (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0))
+                   & clip_mask) != clip_ok)
                 continue;
 
               Matrix cc;
@@ -3414,7 +3577,7 @@
 #if defined (HAVE_OPENGL)
 
     // enable light source
-    glEnable (current_light);
+    m_glfcns.glEnable (m_current_light);
 
     // light position
     float pos[4] = { 0, 0, 0, 0 }; // X,Y,Z,infinite/local
@@ -3423,15 +3586,15 @@
       pos[i] = lpos(i);
     if (props.style_is ("local"))
       pos[3] = 1;
-    glLightfv (current_light, GL_POSITION, pos);
+    m_glfcns.glLightfv (m_current_light, GL_POSITION, pos);
 
     // light color
     float col[4] = { 1, 1, 1, 1 }; // R,G,B,ALPHA (the latter has no meaning)
     Matrix lcolor = props.get_color ().matrix_value ();
     for (int i = 0; i < 3; i++)
       col[i] = lcolor(i);
-    glLightfv (current_light, GL_DIFFUSE,  col);
-    glLightfv (current_light, GL_SPECULAR, col);
+    m_glfcns.glLightfv (m_current_light, GL_DIFFUSE,  col);
+    m_glfcns.glLightfv (m_current_light, GL_SPECULAR, col);
 
 #else
 
@@ -3463,8 +3626,7 @@
 
     // Handle clipping manually when drawing text background
     if (! props.is_clipping ()
-        || (clip_code (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0)
-            == octave_uint8 (0x40)))
+        || (clip_code (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0) == 0x40))
       {
         set_clipping (false);
         draw_text_background (props);
@@ -3475,17 +3637,17 @@
 
     const Matrix bbox = props.get_extent_matrix ();
 
-    bool blend = glIsEnabled (GL_BLEND);
-
-    glEnable (GL_BLEND);
-    glEnable (GL_ALPHA_TEST);
-    glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
-    glBitmap (0, 0, 0, 0, bbox(0), bbox(1), nullptr);
-    glDrawPixels (bbox(2), bbox(3),
-                  GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
-    glDisable (GL_ALPHA_TEST);
+    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)
-      glDisable (GL_BLEND);
+      m_glfcns.glDisable (GL_BLEND);
 
 #else
 
@@ -3511,30 +3673,23 @@
     if (bgcol.isempty () && ecol.isempty ())
       return;
 
-    Matrix pos = xform.scale (props.get_data_position ());
+    Matrix pos = props.get_data_position ();
     ColumnVector pixpos = get_transform ().transform (pos(0), pos(1),
-                                                      pos(2), false);
-    const Matrix bbox = props.get_extent_matrix ();
-
-#  if defined (HAVE_FRAMEWORK_OPENGL)
-    GLint vp[4];
-#  else
-    int vp[4];
-#  endif
-
-    glGetIntegerv (GL_VIEWPORT, vp);
+                                                      pos(2), true);
 
     // Save current transform matrices and set orthogonal window coordinates
-    glMatrixMode (GL_PROJECTION);
-    glPushMatrix ();
-    glLoadIdentity ();
-    glOrtho (0, vp[2], vp[3], 0, xZ1, xZ2);
-    glMatrixMode (GL_MODELVIEW);
-    glPushMatrix ();
-    glLoadIdentity ();
+    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 ();
 
     // Translate coordinates so that the text anchor is (0,0)
-    glTranslated (pixpos(0), pixpos(1), -pixpos(2));
+    m_glfcns.glTranslated (pixpos(0), pixpos(1), -pixpos(2));
 
     // FIXME: Only multiples of 90° are handled by the text renderer.
     //        Handle others here.
@@ -3542,28 +3697,33 @@
 
     if (do_rotate && rotation != 0.0 && rotation != 90.0
         && rotation != 180.0 && rotation != 270.0)
-      glRotated (-rotation, 0.0, 0.0, 1.0);
+      m_glfcns.glRotated (-rotation, 0.0, 0.0, 1.0);
 
     double m = props.get_margin ();
-    double x0 = bbox (0) - m;
-    double x1 = x0 + bbox(2) + 2 * m;
-    double y0 = -(bbox (1) - m);
-    double y1 = y0 - (bbox(3) + 2 * m);
+    // FIXME: Margin property should be measured in points, not pixels.
+    //        On most screens the conversion factor is 4/3.
+    //        For HiDPI this will not work.
+    m *= 4.0/3.0;
+    const Matrix bbox = props.get_extent_matrix ();
+    double x0 = bbox (0) / m_devpixratio - m;
+    double x1 = x0 + bbox(2) / m_devpixratio + 2 * m;
+    double y0 = -(bbox (1) / m_devpixratio - m);
+    double y1 = y0 - (bbox(3) / m_devpixratio + 2 * m);
 
     if (! bgcol.isempty ())
       {
-        glColor3f (bgcol(0), bgcol(1), bgcol(2));
-
-        bool depth_test = glIsEnabled (GL_DEPTH_TEST);
+        m_glfcns.glColor3f (bgcol(0), bgcol(1), bgcol(2));
+
+        bool depth_test = m_glfcns.glIsEnabled (GL_DEPTH_TEST);
         if (depth_test)
           set_polygon_offset (true, 4.0);
 
-        glBegin (GL_QUADS);
-        glVertex2d (x0, y0);
-        glVertex2d (x1, y0);
-        glVertex2d (x1, y1);
-        glVertex2d (x0, y1);
-        glEnd ();
+        m_glfcns.glBegin (GL_QUADS);
+        m_glfcns.glVertex2d (x0, y0);
+        m_glfcns.glVertex2d (x1, y0);
+        m_glfcns.glVertex2d (x1, y1);
+        m_glfcns.glVertex2d (x0, y1);
+        m_glfcns.glEnd ();
 
         if (depth_test)
           set_polygon_offset (false);
@@ -3571,26 +3731,26 @@
 
     if (! ecol.isempty ())
       {
-        glColor3f (ecol(0), ecol(1), ecol(2));
+        m_glfcns.glColor3f (ecol(0), ecol(1), ecol(2));
 
         set_linestyle (props.get_linestyle (), false, props.get_linewidth ());
         set_linewidth (props.get_linewidth ());
 
-        glBegin (GL_LINE_STRIP);
-        glVertex2d (x0, y0);
-        glVertex2d (x1, y0);
-        glVertex2d (x1, y1);
-        glVertex2d (x0, y1);
-        glVertex2d (x0, y0);
-        glEnd ();
+        m_glfcns.glBegin (GL_LINE_STRIP);
+        m_glfcns.glVertex2d (x0, y0);
+        m_glfcns.glVertex2d (x1, y0);
+        m_glfcns.glVertex2d (x1, y1);
+        m_glfcns.glVertex2d (x0, y1);
+        m_glfcns.glVertex2d (x0, y0);
+        m_glfcns.glEnd ();
 
         set_linestyle ("-");
       }
 
     // Restore previous coordinate system
-    glPopMatrix();
-    glMatrixMode (GL_PROJECTION);
-    glPopMatrix();
+    m_glfcns.glPopMatrix();
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPopMatrix();
 
 #else
 
@@ -3622,10 +3782,23 @@
     if (x.isempty () || y.isempty ())
       return;
 
-    if (w > 1 && x(1) == x(0))
+    // Sort x/ydata and mark flipped dimensions
+    bool xflip = false;
+    if (x(0) > x(1))
+      {
+        std::swap (x(0), x(1));
+        xflip = true;
+      }
+    else if (w > 1 && x(1) == x(0))
       x(1) = x(1) + (w-1);
 
-    if (h > 1 && y(1) == y(0))
+    bool yflip = false;
+    if (y(0) > y(1))
+      {
+        std::swap (y(0), y(1));
+        yflip = true;
+      }
+    else if (h > 1 && y(1) == y(0))
       y(1) = y(1) + (h-1);
 
     const ColumnVector p0 = xform.transform (x(0), y(0), 0);
@@ -3670,7 +3843,7 @@
     // OpenGL won't draw any of the image if its origin is outside the
     // viewport/clipping plane so we must do the clipping ourselves.
 
-    int j0, j1, i0, i1;
+    int j0, j1, jj, i0, i1, ii;
     j0 = 0, j1 = w;
     i0 = 0, i1 = h;
 
@@ -3678,33 +3851,51 @@
     float im_xmax = x(1) + nor_dx/2;
     float im_ymin = y(0) - nor_dy/2;
     float im_ymax = y(1) + nor_dy/2;
-    if (props.is_clipping ()) // clip to axes
-      {
-        if (im_xmin < xmin)
-          j0 += (xmin - im_xmin)/nor_dx + 1;
-        if (im_xmax > xmax)
-          j1 -= (im_xmax - xmax)/nor_dx;
-
-        if (im_ymin < ymin)
-          i0 += (ymin - im_ymin)/nor_dy + 1;
-        if (im_ymax > ymax)
-          i1 -= (im_ymax - ymax)/nor_dy;
-      }
-    else // clip to viewport
-      {
-        GLfloat vp[4];
-        glGetFloatv (GL_VIEWPORT, vp);
-        // FIXME: actually add the code to do it!
-      }
+
+    // Clip to axes or viewport
+    bool do_clip = props.is_clipping ();
+    Matrix vp = get_viewport_scaled ();
+
+    ColumnVector vp_lim_min =
+      xform.untransform (std::numeric_limits <float>::epsilon (),
+                         std::numeric_limits <float>::epsilon ());
+    ColumnVector vp_lim_max = xform.untransform (vp(2), vp(3));
+
+    if (vp_lim_min(0) > vp_lim_max(0))
+      std::swap (vp_lim_min(0), vp_lim_max(0));
+        
+    if (vp_lim_min(1) > vp_lim_max(1))
+      std::swap (vp_lim_min(1), vp_lim_max(1));
+        
+    float clip_xmin =
+      (do_clip ? (vp_lim_min(0) > xmin ? vp_lim_min(0) : xmin) : vp_lim_min(0));
+    float clip_ymin =
+      (do_clip ? (vp_lim_min(1) > ymin ? vp_lim_min(1) : ymin) : vp_lim_min(1));
+
+    float clip_xmax =
+      (do_clip ? (vp_lim_max(0) < xmax ? vp_lim_max(0) : xmax) : vp_lim_max(0));
+    float clip_ymax =
+      (do_clip ? (vp_lim_max(1) < ymax ? vp_lim_max(1) : ymax) : vp_lim_max(1));
+
+    if (im_xmin < clip_xmin)
+      j0 += (clip_xmin - im_xmin)/nor_dx + 1;
+    if (im_xmax > clip_xmax)
+      j1 -= (im_xmax - clip_xmax)/nor_dx;
+
+    if (im_ymin < clip_ymin)
+      i0 += (clip_ymin - im_ymin)/nor_dy + 1;
+    if (im_ymax > clip_ymax)
+      i1 -= (im_ymax - clip_ymax)/nor_dy;
 
     if (i0 >= i1 || j0 >= j1)
       return;
 
-    glPixelZoom (pix_dx, -pix_dy);
-    glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
+    m_glfcns.glPixelZoom (m_devpixratio * pix_dx,
+                          - m_devpixratio * pix_dy);
+    m_glfcns.glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
 
     // by default this is 4
-    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+    m_glfcns.glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
 
     // Expect RGB data
     if (dv.ndims () == 3 && dv(2) == 3)
@@ -3719,9 +3910,19 @@
               {
                 for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
                   {
-                    a[idx]   = xcdata(i,j,0);
-                    a[idx+1] = xcdata(i,j,1);
-                    a[idx+2] = xcdata(i,j,2);
+                    if (! yflip)
+                      ii = i;
+                    else
+                      ii = h - i - 1;
+
+                    if (! xflip)
+                      jj = j;
+                    else
+                      jj = w - j - 1;
+
+                    a[idx]   = xcdata(ii,jj,0);
+                    a[idx+1] = xcdata(ii,jj,1);
+                    a[idx+2] = xcdata(ii,jj,2);
                   }
               }
 
@@ -3738,9 +3939,19 @@
               {
                 for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
                   {
-                    a[idx]   = xcdata(i,j,0);
-                    a[idx+1] = xcdata(i,j,1);
-                    a[idx+2] = xcdata(i,j,2);
+                    if (! yflip)
+                      ii = i;
+                    else
+                      ii = h - i - 1;
+
+                    if (! xflip)
+                      jj = j;
+                    else
+                      jj = w - j - 1;
+
+                    a[idx]   = xcdata(ii,jj,0);
+                    a[idx+1] = xcdata(ii,jj,1);
+                    a[idx+2] = xcdata(ii,jj,2);
                   }
               }
 
@@ -3757,9 +3968,19 @@
               {
                 for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
                   {
-                    a[idx]   = xcdata(i,j,0);
-                    a[idx+1] = xcdata(i,j,1);
-                    a[idx+2] = xcdata(i,j,2);
+                    if (! yflip)
+                      ii = i;
+                    else
+                      ii = h - i - 1;
+
+                    if (! xflip)
+                      jj = j;
+                    else
+                      jj = w - j - 1;
+
+                    a[idx]   = xcdata(ii,jj,0);
+                    a[idx+1] = xcdata(ii,jj,1);
+                    a[idx+2] = xcdata(ii,jj,2);
                   }
               }
 
@@ -3776,9 +3997,19 @@
               {
                 for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
                   {
-                    a[idx]   = xcdata(i,j,0);
-                    a[idx+1] = xcdata(i,j,1);
-                    a[idx+2] = xcdata(i,j,2);
+                    if (! yflip)
+                      ii = i;
+                    else
+                      ii = h - i - 1;
+
+                    if (! xflip)
+                      jj = j;
+                    else
+                      jj = w - j - 1;
+
+                    a[idx]   = xcdata(ii,jj,0);
+                    a[idx+1] = xcdata(ii,jj,1);
+                    a[idx+2] = xcdata(ii,jj,2);
                   }
               }
 
@@ -3791,7 +4022,7 @@
     else
       warning ("opengl_renderer: invalid image size (expected MxNx3 or MxN)");
 
-    glPixelZoom (1, 1);
+    m_glfcns.glPixelZoom (1, 1);
 
 #else
 
@@ -3810,7 +4041,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glViewport (0, 0, w, h);
+    m_glfcns.glViewport (0, 0, w, h);
 
 #else
 
@@ -3825,12 +4056,41 @@
 #endif
   }
 
+  Matrix
+  opengl_renderer::get_viewport_scaled (void) const
+  {
+    Matrix retval (1, 4, 0.0);
+
+#if defined (HAVE_OPENGL)
+#if defined (HAVE_FRAMEWORK_OPENGL)
+    GLint vp[4];
+#else
+    int vp[4];
+#endif
+
+    m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
+
+    for (int i = 0; i < 4; i++)
+      retval(i) = static_cast<double> (vp[i]) / m_devpixratio;
+
+#else
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+
+    return retval;
+  }
+
   void
   opengl_renderer::draw_pixels (int width, int height, const float *data)
   {
 #if defined (HAVE_OPENGL)
 
-    glDrawPixels (width, height, GL_RGB, GL_FLOAT, data);
+    m_glfcns.glDrawPixels (width, height, GL_RGB, GL_FLOAT, data);
 
 #else
 
@@ -3851,7 +4111,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
+    m_glfcns.glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
 
 #else
 
@@ -3872,7 +4132,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_SHORT, data);
+    m_glfcns.glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_SHORT, data);
 
 #else
 
@@ -3893,7 +4153,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glColor3dv (c.data ());
+    m_glfcns.glColor3dv (c.data ());
 
     txt_renderer.set_color (c);
 
@@ -3915,7 +4175,8 @@
     txt_renderer.set_font (props.get ("fontname").string_value (),
                            props.get ("fontweight").string_value (),
                            props.get ("fontangle").string_value (),
-                           props.get ("__fontsize_points__").double_value ());
+                           props.get ("__fontsize_points__").double_value ()
+                           * m_devpixratio);
   }
 
   void
@@ -3925,14 +4186,14 @@
 
     if (on)
       {
-        glEnable (GL_POLYGON_OFFSET_FILL);
-        glEnable (GL_POLYGON_OFFSET_LINE);
-        glPolygonOffset (offset, offset);
+        m_glfcns.glEnable (GL_POLYGON_OFFSET_FILL);
+        m_glfcns.glEnable (GL_POLYGON_OFFSET_LINE);
+        m_glfcns.glPolygonOffset (offset, offset);
       }
     else
       {
-        glDisable (GL_POLYGON_OFFSET_FILL);
-        glDisable (GL_POLYGON_OFFSET_LINE);
+        m_glfcns.glDisable (GL_POLYGON_OFFSET_FILL);
+        m_glfcns.glDisable (GL_POLYGON_OFFSET_LINE);
       }
 
 #else
@@ -3953,7 +4214,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glLineWidth (w);
+    m_glfcns.glLineWidth (w * m_devpixratio);
 
 #else
 
@@ -3977,22 +4238,22 @@
 
     if (s == "-")
       {
-        glLineStipple (1, static_cast<unsigned short> (0xFFFF));
+        m_glfcns.glLineStipple (1, static_cast<unsigned short> (0xFFFF));
         solid = true;
       }
     else if (s == ":")
-      glLineStipple (linewidth, static_cast<unsigned short> (0x5555));
+      m_glfcns.glLineStipple (linewidth, static_cast<unsigned short> (0x5555));
     else if (s == "--")
-      glLineStipple (linewidth, static_cast<unsigned short> (0x0F0F));
+      m_glfcns.glLineStipple (linewidth, static_cast<unsigned short> (0x0F0F));
     else if (s == "-.")
-      glLineStipple (linewidth, static_cast<unsigned short> (0x6F6F));
+      m_glfcns.glLineStipple (linewidth, static_cast<unsigned short> (0x6F6F));
     else
-      glLineStipple (1, static_cast<unsigned short> (0x0000));
+      m_glfcns.glLineStipple (1, static_cast<unsigned short> (0x0000));
 
     if (solid && ! use_stipple)
-      glDisable (GL_LINE_STIPPLE);
+      m_glfcns.glDisable (GL_LINE_STIPPLE);
     else
-      glEnable (GL_LINE_STIPPLE);
+      m_glfcns.glEnable (GL_LINE_STIPPLE);
 
 #else
 
@@ -4025,17 +4286,17 @@
     ColumnVector p (4, 0.0);
 
     p(0) = -1; p(3) = x2;
-    glClipPlane (GL_CLIP_PLANE0, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE0, p.data ());
     p(0) = 1; p(3) = -x1;
-    glClipPlane (GL_CLIP_PLANE1, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE1, p.data ());
     p(0) = 0; p(1) = -1; p(3) = y2;
-    glClipPlane (GL_CLIP_PLANE2, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE2, p.data ());
     p(1) = 1; p(3) = -y1;
-    glClipPlane (GL_CLIP_PLANE3, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE3, p.data ());
     p(1) = 0; p(2) = -1; p(3) = z2;
-    glClipPlane (GL_CLIP_PLANE4, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE4, p.data ());
     p(2) = 1; p(3) = -z1;
-    glClipPlane (GL_CLIP_PLANE5, p.data ());
+    m_glfcns.glClipPlane (GL_CLIP_PLANE5, p.data ());
 
     xmin = x1; xmax = x2;
     ymin = y1; ymax = y2;
@@ -4063,16 +4324,16 @@
   {
 #if defined (HAVE_OPENGL)
 
-    bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
+    bool has_clipping = (m_glfcns.glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
 
     if (enable != has_clipping)
       {
         if (enable)
           for (int i = 0; i < 6; i++)
-            glEnable (GL_CLIP_PLANE0+i);
+            m_glfcns.glEnable (GL_CLIP_PLANE0+i);
         else
           for (int i = 0; i < 6; i++)
-            glDisable (GL_CLIP_PLANE0+i);
+            m_glfcns.glDisable (GL_CLIP_PLANE0+i);
       }
 
 #else
@@ -4091,21 +4352,14 @@
   opengl_renderer::init_marker (const std::string& m, double size, float width)
   {
 #if defined (HAVE_OPENGL)
-
-#  if defined (HAVE_FRAMEWORK_OPENGL)
-    GLint vw[4];
-#  else
-    int vw[4];
-#  endif
-
-    glGetIntegerv (GL_VIEWPORT, vw);
-
-    glMatrixMode (GL_PROJECTION);
-    glPushMatrix ();
-    glLoadIdentity ();
-    glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
-    glMatrixMode (GL_MODELVIEW);
-    glPushMatrix ();
+    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 ();
 
     set_clipping (false);
     set_linewidth (width);
@@ -4132,13 +4386,13 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glDeleteLists (marker_id, 1);
-    glDeleteLists (filled_marker_id, 1);
-
-    glMatrixMode (GL_MODELVIEW);
-    glPopMatrix ();
-    glMatrixMode (GL_PROJECTION);
-    glPopMatrix ();
+    m_glfcns.glDeleteLists (marker_id, 1);
+    m_glfcns.glDeleteLists (filled_marker_id, 1);
+
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glPopMatrix ();
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPopMatrix ();
     set_linewidth (0.5f);
 
 #else
@@ -4159,29 +4413,29 @@
 
     ColumnVector tmp = xform.transform (x, y, z, false);
 
-    glLoadIdentity ();
-    glTranslated (tmp(0), tmp(1), -tmp(2));
+    m_glfcns.glLoadIdentity ();
+    m_glfcns.glTranslated (tmp(0), tmp(1), -tmp(2));
 
     if (filled_marker_id > 0 && fc.numel () > 0)
       {
-        glColor3dv (fc.data ());
+        m_glfcns.glColor3dv (fc.data ());
         set_polygon_offset (true, -1.0);
-        glCallList (filled_marker_id);
+        m_glfcns.glCallList (filled_marker_id);
         if (lc.numel () > 0)
           {
-            glColor3dv (lc.data ());
-            glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
-            glEdgeFlag (GL_TRUE);
+            m_glfcns.glColor3dv (lc.data ());
+            m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+            m_glfcns.glEdgeFlag (GL_TRUE);
             set_polygon_offset (true, -2.0);
-            glCallList (filled_marker_id);
-            glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+            m_glfcns.glCallList (filled_marker_id);
+            m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
           }
         set_polygon_offset (false);
       }
     else if (marker_id > 0 && lc.numel () > 0)
       {
-        glColor3dv (lc.data ());
-        glCallList (marker_id);
+        m_glfcns.glColor3dv (lc.data ());
+        m_glfcns.glCallList (marker_id);
       }
 
 #else
@@ -4201,6 +4455,50 @@
   }
 
   void
+  opengl_renderer::init_maxlights (void)
+  {
+#if defined (HAVE_OPENGL)
+
+    // Check actual maximum number of lights possible
+    if (m_max_lights == 0)
+      {
+        for (m_max_lights = 0; m_max_lights < GL_MAX_LIGHTS; m_max_lights++)
+          {
+            m_glfcns.glDisable (GL_LIGHT0 + m_max_lights);
+            if (m_glfcns.glGetError ())
+              break;
+          }
+      }
+
+#else
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+#if defined (HAVE_OPENGL)
+
+  std::string
+  opengl_renderer::get_string (GLenum id) const
+  {
+    // This is kind of ugly, but glGetString returns a pointer to GLubyte
+    // and there is no std::string constructor that matches.  Is there a
+    // better way?
+
+    std::ostringstream buf;
+
+    buf << m_glfcns.glGetString (id);
+
+    return std::string (buf.str ());
+  }
+
+#endif
+
+  void
   opengl_renderer::set_normal (int bfl_mode, const NDArray& n, int j, int i)
   {
 #if defined (HAVE_OPENGL)
@@ -4217,7 +4515,7 @@
       dir = ((x * view_vector(0) + y * view_vector(1) + z * view_vector(2) < 0)
              ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
 
-    glNormal3d (dir*x/d, dir*y/d, dir*z/d);
+    m_glfcns.glNormal3d (dir*x/d, dir*y/d, dir*z/d);
 
 #else
 
@@ -4245,44 +4543,44 @@
     if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
       return 0;
 
-    unsigned int ID = glGenLists (1);
+    unsigned int ID = m_glfcns.glGenLists (1);
     double sz = size * toolkit.get_screen_resolution () / 72.0;
 
     // constants for the * marker
     const double sqrt2d4 = 0.35355339059327;
     double tt = sz*sqrt2d4;
 
-    glNewList (ID, GL_COMPILE);
+    m_glfcns.glNewList (ID, GL_COMPILE);
 
     switch (marker[0])
       {
       case '+':
-        glBegin (GL_LINES);
-        glVertex2d (-sz/2, 0);
-        glVertex2d (sz/2, 0);
-        glVertex2d (0, -sz/2);
-        glVertex2d (0, sz/2);
-        glEnd ();
+        m_glfcns.glBegin (GL_LINES);
+        m_glfcns.glVertex2d (-sz/2, 0);
+        m_glfcns.glVertex2d (sz/2, 0);
+        m_glfcns.glVertex2d (0, -sz/2);
+        m_glfcns.glVertex2d (0, sz/2);
+        m_glfcns.glEnd ();
         break;
       case 'x':
-        glBegin (GL_LINES);
-        glVertex2d (-sz/2, -sz/2);
-        glVertex2d (sz/2, sz/2);
-        glVertex2d (-sz/2, sz/2);
-        glVertex2d (sz/2, -sz/2);
-        glEnd ();
+        m_glfcns.glBegin (GL_LINES);
+        m_glfcns.glVertex2d (-sz/2, -sz/2);
+        m_glfcns.glVertex2d (sz/2, sz/2);
+        m_glfcns.glVertex2d (-sz/2, sz/2);
+        m_glfcns.glVertex2d (sz/2, -sz/2);
+        m_glfcns.glEnd ();
         break;
       case '*':
-        glBegin (GL_LINES);
-        glVertex2d (-sz/2, 0);
-        glVertex2d (sz/2, 0);
-        glVertex2d (0, -sz/2);
-        glVertex2d (0, sz/2);
-        glVertex2d (-tt, -tt);
-        glVertex2d (+tt, +tt);
-        glVertex2d (-tt, +tt);
-        glVertex2d (+tt, -tt);
-        glEnd ();
+        m_glfcns.glBegin (GL_LINES);
+        m_glfcns.glVertex2d (-sz/2, 0);
+        m_glfcns.glVertex2d (sz/2, 0);
+        m_glfcns.glVertex2d (0, -sz/2);
+        m_glfcns.glVertex2d (0, sz/2);
+        m_glfcns.glVertex2d (-tt, -tt);
+        m_glfcns.glVertex2d (+tt, +tt);
+        m_glfcns.glVertex2d (-tt, +tt);
+        m_glfcns.glVertex2d (+tt, -tt);
+        m_glfcns.glEnd ();
         break;
       case '.':
         {
@@ -4292,89 +4590,89 @@
           if (sz > 0 && sz < 3)
             sz = 3;
 
-          int div = static_cast <int> (M_PI * sz / 12);
+          int div = static_cast<int> (M_PI * sz / 12);
           if (! (div % 2))
             div += 1;               // ensure odd number for left/right symmetry
           div = std::max (div, 3);  // ensure at least a few vertices are drawn
           double ang_step = M_PI / div;
 
-          glBegin (GL_POLYGON);
+          m_glfcns.glBegin (GL_POLYGON);
           for (double ang = 0; ang < 2*M_PI; ang += ang_step)
-            glVertex2d (sz/6*cos (ang), sz/6*sin (ang));
-          glEnd ();
+            m_glfcns.glVertex2d (sz/6*cos (ang), sz/6*sin (ang));
+          m_glfcns.glEnd ();
         }
         break;
       case 's':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (-sz/2, -sz/2);
-        glVertex2d (-sz/2, sz/2);
-        glVertex2d (sz/2, sz/2);
-        glVertex2d (sz/2, -sz/2);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (-sz/2, -sz/2);
+        m_glfcns.glVertex2d (-sz/2, sz/2);
+        m_glfcns.glVertex2d (sz/2, sz/2);
+        m_glfcns.glVertex2d (sz/2, -sz/2);
+        m_glfcns.glEnd ();
         break;
       case 'o':
         {
-          int div = static_cast <int> (M_PI * sz / 4);
+          int div = static_cast<int> (M_PI * sz / 4);
           if (! (div % 2))
             div += 1;               // ensure odd number for left/right symmetry
           div = std::max (div, 5);  // ensure at least a few vertices are drawn
           double ang_step = M_PI / div;
 
-          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
           for (double ang = 0; ang < 2*M_PI; ang += ang_step)
-            glVertex2d (sz/2*cos (ang), sz/2*sin (ang));
-          glEnd ();
+            m_glfcns.glVertex2d (sz/2*cos (ang), sz/2*sin (ang));
+          m_glfcns.glEnd ();
         }
         break;
       case 'd':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (0, -sz/2);
-        glVertex2d (sz/2, 0);
-        glVertex2d (0, sz/2);
-        glVertex2d (-sz/2, 0);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (0, -sz/2);
+        m_glfcns.glVertex2d (sz/2, 0);
+        m_glfcns.glVertex2d (0, sz/2);
+        m_glfcns.glVertex2d (-sz/2, 0);
+        m_glfcns.glEnd ();
         break;
       case 'v':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (0, sz/2);
-        glVertex2d (sz/2, -sz/2);
-        glVertex2d (-sz/2, -sz/2);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (0, sz/2);
+        m_glfcns.glVertex2d (sz/2, -sz/2);
+        m_glfcns.glVertex2d (-sz/2, -sz/2);
+        m_glfcns.glEnd ();
         break;
       case '^':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (0, -sz/2);
-        glVertex2d (-sz/2, sz/2);
-        glVertex2d (sz/2, sz/2);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (0, -sz/2);
+        m_glfcns.glVertex2d (-sz/2, sz/2);
+        m_glfcns.glVertex2d (sz/2, sz/2);
+        m_glfcns.glEnd ();
         break;
       case '>':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (sz/2, 0);
-        glVertex2d (-sz/2, sz/2);
-        glVertex2d (-sz/2, -sz/2);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (sz/2, 0);
+        m_glfcns.glVertex2d (-sz/2, sz/2);
+        m_glfcns.glVertex2d (-sz/2, -sz/2);
+        m_glfcns.glEnd ();
         break;
       case '<':
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        glVertex2d (-sz/2, 0);
-        glVertex2d (sz/2, -sz/2);
-        glVertex2d (sz/2, sz/2);
-        glEnd ();
+        m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        m_glfcns.glVertex2d (-sz/2, 0);
+        m_glfcns.glVertex2d (sz/2, -sz/2);
+        m_glfcns.glVertex2d (sz/2, sz/2);
+        m_glfcns.glEnd ();
         break;
       case 'p':
         {
           double ang, r, dr;
           dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02;
 
-          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
           for (int i = 0; i < 2*5; i++)
             {
               ang = (-0.5 + double (i+1) / 5) * M_PI;
               r = 1.0 - (dr * fmod (double (i+1), 2.0));
-              glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
+              m_glfcns.glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
             }
-          glEnd ();
+          m_glfcns.glEnd ();
         }
         break;
       case 'h':
@@ -4382,14 +4680,14 @@
           double ang, r, dr;
           dr = 1.0 - 0.5/sin (M_PI/3)*1.02;
 
-          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
           for (int i = 0; i < 2*6; i++)
             {
               ang = (0.5 + double (i+1) / 6.0) * M_PI;
               r = 1.0 - (dr * fmod (double (i+1), 2.0));
-              glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
+              m_glfcns.glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
             }
-          glEnd ();
+          m_glfcns.glEnd ();
         }
         break;
       default:
@@ -4397,7 +4695,7 @@
         break;
       }
 
-    glEndList ();
+    m_glfcns.glEndList ();
 
     return ID;
 
@@ -4452,18 +4750,18 @@
         uint8NDArray pixels;
         text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
 
-        bool blend = glIsEnabled (GL_BLEND);
-
-        glEnable (GL_BLEND);
-        glEnable (GL_ALPHA_TEST);
-        glRasterPos3d (x, y, z);
-        glBitmap(0, 0, 0, 0, bbox(0), bbox(1), nullptr);
-        glDrawPixels (bbox(2), bbox(3),
+        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 ());
-        glDisable (GL_ALPHA_TEST);
+        m_glfcns.glDisable (GL_ALPHA_TEST);
 
         if (! blend)
-          glDisable (GL_BLEND);
+          m_glfcns.glDisable (GL_BLEND);
       }
 
     return bbox;
--- a/libinterp/corefcn/gl-render.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gl-render.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
 #include "octave-config.h"
 
 #include "graphics.h"
+#include "oct-opengl.h"
 #include "text-renderer.h"
 
 namespace octave
@@ -36,7 +37,7 @@
   {
   public:
 
-    opengl_renderer (void);
+    opengl_renderer (opengl_functions& glfcns);
 
     // No copying!
 
@@ -46,6 +47,8 @@
 
     virtual ~opengl_renderer (void) = default;
 
+    opengl_functions& get_opengl_functions (void) const { return m_glfcns; }
+
     virtual void draw (const graphics_object& go, bool toplevel = true);
 
     virtual void draw (const Matrix& hlist, bool toplevel = false)
@@ -62,9 +65,18 @@
     }
 
     virtual void set_viewport (int w, int h);
+    virtual void set_device_pixel_ratio (double dpr) { m_devpixratio = dpr; }
+    virtual Matrix get_viewport_scaled (void) const;
     virtual graphics_xform get_transform (void) const { return xform; }
     virtual uint8NDArray get_pixels (int width, int height);
 
+    virtual void draw_zoom_box (int width, int height,
+                                int x1, int y1, int x2, int y2,
+                                const Matrix& overlaycolor,
+                                double overlayalpha,
+                                const Matrix& bordercolor,
+                                double borderalpha, double borderwidth);
+
     virtual void finish (void);
 
   protected:
@@ -150,8 +162,16 @@
                                    int xyz, int ha, int va,
                                    int& wmax, int& hmax);
 
+    virtual void draw_zoom_rect (int x1, int y1, int x2, int y2);
+
   private:
 
+    void init_maxlights (void);
+
+#if defined (HAVE_OPENGL)
+    std::string get_string (GLenum id) const;
+#endif
+
     bool is_nan_or_inf (double x, double y, double z) const
     {
       return (math::isnan (x) || math::isnan (y)
@@ -160,7 +180,7 @@
               || math::isinf (z));
     }
 
-    octave_uint8 clip_code (double x, double y, double z) const
+    uint8_t clip_code (double x, double y, double z) const
     {
       return ((x < xmin ? 1 : 0)
               | (x > xmax ? 1 : 0) << 1
@@ -189,7 +209,12 @@
     void draw_all_lights (const base_properties& props,
                           std::list<graphics_object>& obj_list);
 
+  protected:
+
+    opengl_functions& m_glfcns;
+
   private:
+
     // The graphics toolkit associated with the figure being rendered.
     graphics_toolkit toolkit;
 
@@ -216,12 +241,15 @@
     text_renderer txt_renderer;
 
     // light object present and visible
-    int num_lights;
-    unsigned int current_light;
-    int max_lights;
+    unsigned int m_current_light;
+    unsigned int m_max_lights;
 
     // Indicate we are drawing for selection purpose
     bool selecting;
+
+    // Factor used for translating Octave pixels to actual device pixels
+    double m_devpixratio;
+
   private:
     class patch_tesselator;
   };
--- a/libinterp/corefcn/gl2ps-print.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gl2ps-print.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -40,6 +40,7 @@
 #include "oct-locbuf.h"
 #include "tmpfile-wrapper.h"
 #include "unistd-wrappers.h"
+#include "unistr-wrappers.h"
 #include "unwind-prot.h"
 
 #include "gl-render.h"
@@ -54,7 +55,7 @@
   safe_pclose (FILE *f)
   {
     if (f)
-      octave_pclose (f);
+      octave::pclose (f);
   }
 
   static void
@@ -70,9 +71,10 @@
   {
   public:
 
-    gl2ps_renderer (FILE *_fp, const std::string& _term)
-      : opengl_renderer () , fp (_fp), term (_term), fontsize (),
-        fontname (), buffer_overflow (false)
+    gl2ps_renderer (opengl_functions& glfcns, FILE *_fp,
+                    const std::string& _term)
+      : opengl_renderer (glfcns), fp (_fp), term (_term),
+        fontsize (), fontname (), buffer_overflow (false)
     { }
 
     ~gl2ps_renderer (void) = default;
@@ -127,7 +129,7 @@
     {
       // Initialize a sorting tree (viewport) in gl2ps for each axes
       GLint vp[4];
-      glGetIntegerv (GL_VIEWPORT, vp);
+      m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
       gl2psBeginViewport (vp);
 
 
@@ -265,14 +267,15 @@
     // Build an svg text element from a list of parsed strings.
     std::string strlist_to_svg (double x, double y, double z, Matrix box,
                                 double rotation,
-                                std::list<octave::text_renderer::string>& lst);
+                                std::list<text_renderer::string>& lst);
 
     // Build a list of postscript commands from a list of parsed strings.
     std::string strlist_to_ps (double x, double y, double z, Matrix box,
                                double rotation,
-                               std::list<octave::text_renderer::string>& lst);
+                               std::list<text_renderer::string>& lst);
 
     int alignment_to_mode (int ha, int va) const;
+
     FILE *fp;
     caseless_str term;
     double fontsize;
@@ -408,7 +411,10 @@
             const figure::properties& fprop
               = dynamic_cast<const figure::properties&> (go.get_properties ());
             Matrix c = fprop.get_color_rgb ();
-            glClearColor (c(0), c(1), c(2), 1);
+            m_glfcns.glClearColor (c(0), c(1), c(2), 1);
+
+            // Allow figures to be printed at arbitrary resolution
+            set_device_pixel_ratio (fprop.get___device_pixel_ratio__ ());
 
             // GL2PS_SILENT was removed to allow gl2ps to print errors on stderr
             GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave",
@@ -560,7 +566,7 @@
                         + (txtobj.get_x () + box(0))*sin (rot);
 
         GLint vp[4];
-        glGetIntegerv (GL_VIEWPORT, vp);
+        m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
 
         txtobj.set_x (coord_pix(0));
         txtobj.set_y (vp[3] - coord_pix(1));
@@ -781,7 +787,7 @@
   std::string
   gl2ps_renderer::strlist_to_svg (double x, double y, double z,
                                   Matrix box, double rotation,
-                                  std::list<octave::text_renderer::string>& lst)
+                                  std::list<text_renderer::string>& lst)
   {
     if (lst.empty ())
       return "";
@@ -877,7 +883,7 @@
   std::string
   gl2ps_renderer::strlist_to_ps (double x, double y, double z,
                                  Matrix box, double rotation,
-                                 std::list<octave::text_renderer::string>& lst)
+                                 std::list<text_renderer::string>& lst)
   {
     // Translate and rotate coordinates in order to use bottom-left alignment
     fix_strlist_position (x, y, z, box, rotation, lst);
@@ -886,6 +892,8 @@
     std::ostringstream ss;
     ss << "gsave\n";
 
+    static bool warned = false;
+
     for (const auto& txtobj : lst)
       {
         // Color
@@ -910,7 +918,33 @@
             fontname = select_font (txtobj.get_name (),
                                     txtobj.get_weight () == "bold",
                                     txtobj.get_angle () == "italic");
-            str = txtobj.get_string ();
+
+            // Check that the string is composed of single byte characters
+            const std::string tmpstr = txtobj.get_string ();
+            const uint8_t *c =
+              reinterpret_cast<const uint8_t *> (tmpstr.c_str ());
+
+            for (size_t i = 0; i < tmpstr.size ();)
+              {
+                int mblen = octave_u8_strmblen_wrapper (c + i);
+
+                if (mblen > 1)
+                  {
+                    str += " ";
+                    if (! warned)
+                      {
+                        warning_with_id ("Octave:print:unsupported-multibyte",
+                                         "print: only ASCII characters are "
+                                         "supported for EPS and derived "
+                                         "formats.");
+                        warned = true;
+                      }
+                  }
+                else
+                  str += tmpstr.at (i);
+
+                i += mblen;
+              }
           }
 
         escape_character ("(", str);
@@ -947,7 +981,7 @@
     std::list<text_renderer::string> lst;
 
     text_to_strlist (str, lst, bbox, ha, va, rotation);
-    glRasterPos3d (x, y, z);
+    m_glfcns.glRasterPos3d (x, y, z);
 
     // For svg/eps directly dump a preformated text element into gl2ps output
     if (term.find ("svg") != std::string::npos)
@@ -1085,8 +1119,8 @@
   // named by the rest of the string.  Otherwise, write to the named file.
 
   void
-  gl2ps_print (const graphics_object& fig, const std::string& stream,
-               const std::string& term)
+  gl2ps_print (opengl_functions& glfcns, const graphics_object& fig,
+               const std::string& stream, const std::string& term)
   {
 #if defined (HAVE_GL2PS_H) && defined (HAVE_OPENGL)
 
@@ -1105,7 +1139,7 @@
 
         std::string cmd = stream.substr (1);
 
-        fp = octave_popen (cmd.c_str (), "w");
+        fp = octave::popen (cmd.c_str (), "w");
 
         if (! fp)
           error (R"(print: failed to open pipe "%s")", stream.c_str ());
@@ -1116,7 +1150,7 @@
       {
         // Write gl2ps output directly to file.
 
-        fp = std::fopen (stream.c_str (), "w");
+        fp = octave::sys::fopen (stream.c_str (), "w");
 
         if (! fp)
           error (R"(gl2ps_print: failed to create file "%s")", stream.c_str ());
@@ -1124,7 +1158,7 @@
         frame.add_fcn (safe_fclose, fp);
       }
 
-    gl2ps_renderer rend (fp, term);
+    gl2ps_renderer rend (glfcns, fp, term);
 
     Matrix pos = fig.get ("position").matrix_value ();
     rend.set_viewport (pos(2), pos(3));
@@ -1134,11 +1168,14 @@
     rend.finish ();
 
 #else
+
+    octave_unused_parameter (glfcns);
     octave_unused_parameter (fig);
     octave_unused_parameter (stream);
     octave_unused_parameter (term);
 
     err_disabled_feature ("gl2ps_print", "gl2ps");
+
 #endif
   }
 }
--- a/libinterp/corefcn/gl2ps-print.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gl2ps-print.h	Thu Dec 20 17:18:56 2018 -0500
@@ -27,25 +27,14 @@
 
 #include <string>
 
+#include "oct-opengl.h"
 #include "graphics.h"
 
 namespace octave
 {
   extern OCTINTERP_API void
-  gl2ps_print (const graphics_object& fig, const std::string& stream,
-               const std::string& term);
-}
-
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::gl2ps_print' instead")
-inline void
-gl2ps_print (const graphics_object& fig, const std::string& stream,
-             const std::string& term)
-{
-  return octave::gl2ps_print (fig, stream, term);
+  gl2ps_print (opengl_functions& glfcns, const graphics_object& fig,
+               const std::string& stream, const std::string& term);
 }
 
 #endif
-
-#endif
--- a/libinterp/corefcn/graphics-toolkit.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/graphics-toolkit.h	Thu Dec 20 17:18:56 2018 -0500
@@ -55,6 +55,9 @@
   virtual void redraw_figure (const graphics_object&) const
   { gripe_if_tkit_invalid ("redraw_figure"); }
 
+  virtual void show_figure (const graphics_object&) const
+  { gripe_if_tkit_invalid ("show_figure"); }
+
   virtual void print_figure (const graphics_object&, const std::string&,
                              const std::string&,
                              const std::string& = "") const
@@ -175,6 +178,9 @@
   void redraw_figure (const graphics_object& go) const
   { rep->redraw_figure (go); }
 
+  void show_figure (const graphics_object& go) const
+  { rep->show_figure (go); }
+
   void print_figure (const graphics_object& go, const std::string& term,
                      const std::string& file,
                      const std::string& debug_file = "") const
--- a/libinterp/corefcn/graphics.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/graphics.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -59,6 +59,7 @@
 #include "ov-fcn-handle.h"
 #include "pager.h"
 #include "parse.h"
+#include "text-engine.h"
 #include "text-renderer.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -565,6 +566,32 @@
   return m;
 }
 
+static Matrix
+default_table_position (void)
+{
+  Matrix retval (1, 4);
+
+  retval(0) = 20;
+  retval(1) = 20;
+  retval(2) = 300;
+  retval(3) = 300;
+
+  return retval;
+}
+
+static Matrix
+default_table_backgroundcolor (void)
+{
+  Matrix retval (2, 3);
+  retval(0, 0) = 1;
+  retval(0, 1) = 1;
+  retval(0, 2) = 1;
+  retval(1, 0) = 0.94;
+  retval(1, 1) = 0.94;
+  retval(1, 2) = 0.94;
+  return retval;
+}
+
 static double
 convert_font_size (double font_size, const caseless_str& from_units,
                    const caseless_str& to_units, double parent_height = 0)
@@ -630,7 +657,7 @@
   Matrix retval (1, pos.numel ());
   double res = 0;
   bool is_rectangle = (pos.numel () == 4);
-  bool is_2d = (pos.numel () == 2);
+  bool is_2D = (pos.numel () == 2);
 
   if (from_units.compare ("pixels"))
     retval = pos;
@@ -643,7 +670,7 @@
           retval(2) = pos(2) * parent_dim(0);
           retval(3) = pos(3) * parent_dim(1);
         }
-      else if (! is_2d)
+      else if (! is_2D)
         retval(2) = 0;
     }
   else if (from_units.compare ("characters"))
@@ -666,7 +693,7 @@
               retval(2) = 0.5 * pos(2) * f;
               retval(3) = pos(3) * f;
             }
-          else if (! is_2d)
+          else if (! is_2D)
             retval(2) = 0;
         }
     }
@@ -693,7 +720,7 @@
               retval(2) = pos(2) * f;
               retval(3) = pos(3) * f;
             }
-          else if (! is_2d)
+          else if (! is_2D)
             retval(2) = 0;
         }
     }
@@ -709,7 +736,7 @@
               retval(2) /= parent_dim(0);
               retval(3) /= parent_dim(1);
             }
-          else if (! is_2d)
+          else if (! is_2D)
             retval(2) = 0;
         }
       else if (to_units.compare ("characters"))
@@ -730,7 +757,7 @@
                   retval(2) = 2 * retval(2) / f;
                   retval(3) = retval(3) / f;
                 }
-              else if (! is_2d)
+              else if (! is_2D)
                 retval(2) = 0;
             }
         }
@@ -757,12 +784,12 @@
                   retval(2) /= f;
                   retval(3) /= f;
                 }
-              else if (! is_2d)
+              else if (! is_2D)
                 retval(2) = 0;
             }
         }
     }
-  else if (! is_rectangle && ! is_2d)
+  else if (! is_rectangle && ! is_2D)
     retval(2) = 0;
 
   return retval;
@@ -869,6 +896,19 @@
                            sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2);
 }
 
+static double
+device_pixel_ratio (graphics_handle h)
+{
+  double retval = 1.0;
+
+  graphics_object fig = gh_manager::get_object (h).get_ancestor ("figure");
+
+  if (fig.valid_object ())
+    retval = fig.get ("__device_pixel_ratio__").double_value ();
+
+  return retval;
+}
+
 static void
 convert_cdata_2 (bool is_scaled, bool is_real, double clim_0, double clim_1,
                  const double *cmapv, double x, octave_idx_type lda,
@@ -1059,7 +1099,7 @@
                   pfx = name.substr (0, 7);
 
                   if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel"))
+                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len >= 9)
                     {
@@ -1141,6 +1181,8 @@
     go = new uibuttongroup (h, p);
   else if (type.compare ("uicontextmenu"))
     go = new uicontextmenu (h, p);
+  else if (type.compare ("uitable"))
+    go = new uitable (h, p);
   else if (type.compare ("uitoolbar"))
     go = new uitoolbar (h, p);
   else if (type.compare ("uipushtool"))
@@ -1459,8 +1501,12 @@
                       if (itdims(i) != vdims(i))
                         xok = false;
                     }
-                  else if (v.isempty ())
-                    break;
+                  else if (itdims(i) == 0)
+                    {
+                      if (! v.isempty ())
+                        xok = false;
+                      break;
+                    }
                 }
             }
         }
@@ -1728,13 +1774,8 @@
 void
 children_property::do_delete_children (bool clear)
 {
-  for (auto& hchild : children_list)
-    {
-      graphics_object go = gh_manager::get_object (hchild);
-
-      if (go.valid_object () && ! go.get_properties ().is_beingdeleted ())
-        gh_manager::free (hchild);
-    }
+  while (! children_list.empty ())
+    gh_manager::free (children_list.front ());
 
   if (clear)
     children_list.clear ();
@@ -2079,6 +2120,41 @@
 
   base_properties::update_handlevisibility ();
 }
+
+static void
+update_text_pos (graphics_handle h)
+{
+  graphics_object go = gh_manager::get_object (h);
+  if (go.isa ("text"))
+    {
+      text::properties& tp
+        = dynamic_cast<text::properties&> (go.get_properties ());
+      tp.update_font ();
+      tp.update_text_extent ();
+    }
+  else if (go.isa ("figure") || go.isa ("uipanel") || go.isa ("axes")
+           || go.isa ("hggroup"))
+    {
+      Matrix ch = go.get_properties ().get_all_children ();
+      for (octave_idx_type ii = 0; ii < ch.numel (); ii++)
+        update_text_pos (graphics_handle (ch(ii)));
+
+      if (go.isa ("axes"))
+        {
+          axes::properties& ap
+            = dynamic_cast<axes::properties&> (go.get_properties ());
+          ap.update_font ();
+          ap.sync_positions ();
+        }
+    }
+}
+
+void
+figure::properties::update___device_pixel_ratio__ (void)
+{
+  update_text_pos (get___myhandle__ ());
+}
+
 // ---------------------------------------------------------------------
 
 void
@@ -2112,7 +2188,7 @@
                   pfx = name.substr (0, 7);
 
                   if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel"))
+                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2185,6 +2261,8 @@
             has_property = uipanel::properties::has_core_property (pname);
           else if (pfx == "uicontextmenu")
             has_property = uicontextmenu::properties::has_core_property (pname);
+          else if (pfx == "uitable")
+            has_property = uitable::properties::has_core_property (pname);
           else if (pfx == "uitoolbar")
             has_property = uitoolbar::properties::has_core_property (pname);
           else if (pfx == "uipushtool")
@@ -2205,7 +2283,7 @@
 
           if (remove)
             {
-              pval_map_iterator p = pval_map.find (pname);
+              auto p = pval_map.find (pname);
 
               if (p != pval_map.end ())
                 pval_map.erase (p);
@@ -2252,7 +2330,7 @@
                   pfx = name.substr (0, 7);
 
                   if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel"))
+                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2318,7 +2396,7 @@
 {
   octave_scalar_map m;
 
-  for (plist_map_const_iterator p = begin (); p != end (); p++)
+  for (auto p = begin (); p != end (); p++)
     {
       std::string prefix = prefix_arg + p->first;
 
@@ -2377,7 +2455,8 @@
                       const Cell& values, octave_idx_type row)
 {
   if (pnames.numel () != values.columns ())
-    error ("set: number of names must match number of value columns (%d != %d)",
+    error ("set: number of names must match number of value columns "
+           "(%" OCTAVE_IDX_TYPE_FORMAT " != %" OCTAVE_IDX_TYPE_FORMAT ")",
            pnames.numel (), values.columns ());
 
   octave_idx_type k = pnames.columns ();
@@ -2622,7 +2701,7 @@
       // fractional part.  To avoid running out of integers, we recycle the
       // integer part but tack on a new random part each time.
 
-      free_list_iterator p = handle_free_list.begin ();
+      auto p = handle_free_list.begin ();
 
       if (p != handle_free_list.end ())
         {
@@ -2648,17 +2727,27 @@
       if (h.value () == 0)
         error ("graphics_handle::free: can't delete root figure");
 
-      iterator p = handle_map.find (h);
+      auto p = handle_map.find (h);
 
       if (p == handle_map.end ())
         error ("graphics_handle::free: invalid object %g", h.value ());
 
       base_properties& bp = p->second.get_properties ();
 
+      if (! p->second.valid_object () || bp.is_beingdeleted ())
+        return;
+
+      graphics_handle parent_h = p->second.get_parent ();
+      graphics_object parent_go = gh_manager::get_object (parent_h);
+
       bp.set_beingdeleted (true);
 
+      // delete listeners before invalidating object
+      p->second.remove_all_listeners ();
+
       bp.delete_children ();
 
+      // NOTE: Call the delete function while the object's state is still valid.
       octave_value val = bp.get_deletefcn ();
 
       bp.execute_deletefcn ();
@@ -2666,6 +2755,11 @@
       // Notify graphics toolkit.
       p->second.finalize ();
 
+      // NOTE: Call remove_child before erasing the go from the map.
+      // A callback function might have already deleted the parent
+      if (parent_go.valid_object () && h.ok ())
+        parent_go.remove_child (h);
+
       // Note: this will be valid only for first explicitly deleted
       // object.  All its children will then have an
       // unknown graphics toolkit.
@@ -2687,7 +2781,7 @@
 gh_manager::do_renumber_figure (const graphics_handle& old_gh,
                                 const graphics_handle& new_gh)
 {
-  iterator p = handle_map.find (old_gh);
+  auto p = handle_map.find (old_gh);
 
   if (p == handle_map.end ())
     error ("graphics_handle::free: invalid object %g", old_gh.value ());
@@ -2801,20 +2895,11 @@
       // Don't do recursive deleting, due to callbacks
       if (! go.get_properties ().is_beingdeleted ())
         {
-          graphics_handle parent_h = go.get_parent ();
-
-          graphics_object parent_go = gh_manager::get_object (parent_h);
-
-          // NOTE: free the handle before removing it from its parent's
-          //       children, such that the object's state is correct when the
-          //       deletefcn callback is executed
+          // NOTE: Freeing the handle also calls any deletefcn.  It also calls
+          //       the parent's delete_child function.
 
           gh_manager::free (h);
 
-          // A callback function might have already deleted the parent
-          if (parent_go.valid_object ())
-            parent_go.remove_child (h);
-
           Vdrawnow_requested = true;
         }
     }
@@ -2913,13 +2998,13 @@
 }
 
 static bool
-is_hghandle (const graphics_handle& h)
+ishghandle (const graphics_handle& h)
 {
   return h.ok ();
 }
 
 static bool
-is_hghandle (double val)
+ishghandle (double val)
 {
   graphics_handle h = gh_manager::lookup (val);
 
@@ -2927,11 +3012,11 @@
 }
 
 static octave_value
-is_hghandle (const octave_value& val)
+ishghandle (const octave_value& val)
 {
   octave_value retval = false;
 
-  if (val.is_real_scalar () && is_hghandle (val.double_value ()))
+  if (val.is_real_scalar () && ishghandle (val.double_value ()))
     retval = true;
   else if (val.isnumeric () && val.isreal ())
     {
@@ -2940,7 +3025,7 @@
       boolNDArray result (handles.dims ());
 
       for (octave_idx_type i = 0; i < handles.numel (); i++)
-        result.xelem (i) = is_hghandle (handles(i));
+        result.xelem (i) = ishghandle (handles(i));
 
       retval = result;
     }
@@ -2949,7 +3034,7 @@
 }
 
 static bool
-is_figure (double val)
+isfigure (double val)
 {
   graphics_object go = gh_manager::get_object (val);
 
@@ -3134,8 +3219,7 @@
 base_properties::set_dynamic (const caseless_str& pname,
                               const octave_value& val)
 {
-  std::map<caseless_str, property, cmp_caseless_str>::iterator it =
-    all_props.find (pname);
+  auto it = all_props.find (pname);
 
   if (it == all_props.end ())
     error (R"(set: unknown property "%s")", pname.c_str ());
@@ -3398,6 +3482,34 @@
     p.delete_listener (val, mode);
 }
 
+void
+base_properties::get_children_of_type (const caseless_str& chtype,
+                                       bool get_invisible,
+                                       bool traverse,
+                                       std::list<graphics_object> &children_list) const
+{
+  Matrix ch = get_children ();
+  for (octave_idx_type i = 0; i < ch.numel (); i++)
+    {
+      graphics_handle hkid = gh_manager::lookup (ch(i));
+
+      if (hkid.ok ())
+        {
+          graphics_object go = gh_manager::get_object (hkid);
+          if ( get_invisible || go.get_properties ().is_visible () )
+            {
+              if (go.isa (chtype))
+                children_list.push_back (go);
+              else if (traverse && go.isa ("hggroup"))
+                go.get_properties ().get_children_of_type (chtype,
+                                                           get_invisible,
+                                                           traverse,
+                                                           children_list);
+            }
+        }
+    }
+}
+
 // ---------------------------------------------------------------------
 
 void
@@ -3645,7 +3757,7 @@
 
       callbackobject = val;
     }
-  else if (is_hghandle (val))
+  else if (ishghandle (val))
     {
       if (get_callbackobject ().ok ())
         cbo_stack.push_front (get_callbackobject ());
@@ -3661,7 +3773,7 @@
 {
   graphics_handle val (v);
 
-  if (octave::math::isnan (val.value ()) || is_hghandle (val))
+  if (octave::math::isnan (val.value ()) || ishghandle (val))
     {
       currentfigure = val;
 
@@ -3724,7 +3836,18 @@
 
   double dpi = get_screenpixelsperinch ();
 
-  if (xunits == "inches")
+  if (xunits == "pixels")
+    {
+      // Most common case (default).
+      // Don't need to convert anything, but short-circuit if/else tree.
+    }
+  else if (xunits == "normalized")
+    {
+      scrn_sz = Matrix (1, 4, 1.0);
+      scrn_sz(0) = 0;
+      scrn_sz(1) = 0;
+    }
+  else if (xunits == "inches")
     {
       scrn_sz(0) = 0;
       scrn_sz(1) = 0;
@@ -3738,12 +3861,6 @@
       scrn_sz(2) *= 2.54 / dpi;
       scrn_sz(3) *= 2.54 / dpi;
     }
-  else if (xunits == "normalized")
-    {
-      scrn_sz = Matrix (1, 4, 1.0);
-      scrn_sz(0) = 0;
-      scrn_sz(1) = 0;
-    }
   else if (xunits == "points")
     {
       scrn_sz(0) = 0;
@@ -3751,6 +3868,15 @@
       scrn_sz(2) *= 72 / dpi;
       scrn_sz(3) *= 72 / dpi;
     }
+  else if (xunits == "characters")
+    {
+      scrn_sz(0) = 0;
+      scrn_sz(1) = 0;
+      // FIXME: this assumes the system font is Helvetica 10pt
+      //        (for which "x" requires 6x12 pixels at 74.951 pixels/inch)
+      scrn_sz(2) *= 74.951 / 12.0 / dpi;
+      scrn_sz(3) *= 74.951 / 12.0 / dpi;
+    }
 
   set_screensize (scrn_sz);
 }
@@ -3784,6 +3910,8 @@
 %!   assert (get (0, "screensize"), [0.0, 0.0, 1.0, 1.0]);
 %!   set (0, "units", "pixels");
 %!   assert (get (0, "screensize"), sz + [1, 1, 0, 0]);
+%!   set (0, "units", "characters");
+%!   assert (get (0, "screensize"), sz / dpi * (74.951 / 12.0), 0.5 / dpi * (74.951 / 12.0));
 %! unwind_protect_cleanup
 %!   set (0, "units", old_units);
 %! end_unwind_protect
@@ -3819,7 +3947,7 @@
 {
   graphics_handle hax (val);
 
-  if (octave::math::isnan (hax.value ()) || is_hghandle (hax))
+  if (octave::math::isnan (hax.value ()) || ishghandle (hax))
     currentaxes = hax;
   else
     err_set_invalid ("currentaxes");
@@ -3853,6 +3981,15 @@
     }
 }
 
+octave_value
+figure::properties::get_number (void) const
+{
+  if (integerhandle.is_on ())
+    return __myhandle__.value ();
+  else
+    return Matrix ();
+}
+
 graphics_toolkit
 figure::properties::get_toolkit (void) const
 {
@@ -4017,7 +4154,12 @@
     {
       if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
         {
-          execute_resizefcn ();
+          if (! get_resizefcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "resizefcn");
+
+          if (! get_sizechangedfcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "sizechangedfcn");
+
           update_boundingbox ();
         }
     }
@@ -4670,7 +4812,8 @@
 std::string
 figure::properties::get_title (void) const
 {
-  if (is_numbertitle ())
+  std::string title;
+  if (! get_number ().isempty () && is_numbertitle ())
     {
       std::ostringstream os;
       std::string nm = get_name ();
@@ -4679,10 +4822,17 @@
       if (! nm.empty ())
         os << ": " << get_name ();
 
-      return os.str ();
-    }
-  else
-    return get_name ();
+      title = os.str ();
+    }
+  else
+    title = get_name ();
+
+  // Qt will use QCoreApplication name (set in main-window.cc)
+  // if the name is empty, so force blank.
+  if (title.empty ())
+    title = " ";
+
+  return title;
 }
 
 octave_value
@@ -4884,6 +5034,11 @@
   Matrix pos = init_pos;
   graphics_object go = gh_manager::get_object (get_parent ());
   Matrix parent_bb = go.get_properties ().get_boundingbox (true);
+
+  // FIXME: The layout should be clean at this stage and we should not have to
+  //        update ticks and labels positions here again. See bug #48718.
+  update_ticklength ();
+
   Matrix ext = get_extent (true, true);
   ext(1) = parent_bb(3) - ext(1) - ext(3);
   ext(0)++;
@@ -5027,8 +5182,6 @@
 
   gh_manager::free (hp.handle_value ());
 
-  base_properties::remove_child (hp.handle_value ());
-
   hp = val;
 
   adopt (hp.handle_value ());
@@ -5326,8 +5479,6 @@
 
       if (go.valid_object ())
         gh_manager::free (h);
-
-      base_properties::remove_child (h);
     }
 
   // FIXME: is it necessary to check whether the axes object is
@@ -5349,6 +5500,11 @@
 void
 axes::properties::remove_child (const graphics_handle& h)
 {
+  graphics_object go = gh_manager::get_object (h);
+
+  if (go.isa ("light") && go.get_properties ().is_visible ())
+    decrease_num_lights ();
+
   if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
     {
       delete_text_child (xlabel);
@@ -5369,8 +5525,21 @@
       delete_text_child (title);
       update_title_position ();
     }
-  else
-    base_properties::remove_child (h);
+
+  if (go.valid_object ())
+      base_properties::remove_child (h);
+
+}
+
+void
+axes::properties::adopt (const graphics_handle& h)
+{
+  graphics_object go (gh_manager::get_object (h));
+  if (go.isa ("light") && go.get_properties ().is_visible ())
+    increase_num_lights ();
+
+  base_properties::adopt (h);
+
 }
 
 inline Matrix
@@ -5924,12 +6093,12 @@
 void
 axes::properties::update_ticklength (void)
 {
-  bool mode2d = (((xstate > AXE_DEPTH_DIR ? 1 : 0) +
+  bool mode2D = (((xstate > AXE_DEPTH_DIR ? 1 : 0) +
                   (ystate > AXE_DEPTH_DIR ? 1 : 0) +
                   (zstate > AXE_DEPTH_DIR ? 1 : 0)) == 2);
 
   if (tickdirmode_is ("auto"))
-    tickdir.set (mode2d ? "in" : "out", true);
+    tickdir.set (mode2D ? "in" : "out", true);
 
   double ticksign = (tickdir_is ("in") ? -1 : 1);
 
@@ -5938,13 +6107,18 @@
   ticklen(0) *= std::max (bbox(2), bbox(3));
   ticklen(1) *= std::max (bbox(2), bbox(3));
 
-  xticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
-  yticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
-  zticklen = ticksign * (mode2d ? ticklen(0) : ticklen(1));
-
-  xtickoffset = (mode2d ? std::max (0., xticklen) : std::abs (xticklen)) + 5;
-  ytickoffset = (mode2d ? std::max (0., yticklen) : std::abs (yticklen)) + 5;
-  ztickoffset = (mode2d ? std::max (0., zticklen) : std::abs (zticklen)) + 5;
+  xticklen = ticksign * (mode2D ? ticklen(0) : ticklen(1));
+  yticklen = ticksign * (mode2D ? ticklen(0) : ticklen(1));
+  zticklen = ticksign * (mode2D ? ticklen(0) : ticklen(1));
+
+  double offset = get___fontsize_points__ () / 2;
+  
+  xtickoffset = (mode2D ? std::max (0., xticklen) : std::abs (xticklen)) +
+                (xstate == AXE_HORZ_DIR ? offset*1.5 : offset);
+  ytickoffset = (mode2D ? std::max (0., yticklen) : std::abs (yticklen)) +
+                (ystate == AXE_HORZ_DIR ? offset*1.5 : offset);
+  ztickoffset = (mode2D ? std::max (0., zticklen) : std::abs (zticklen)) +
+                (zstate == AXE_HORZ_DIR ? offset*1.5 : offset);
 
   update_xlabel_position ();
   update_ylabel_position ();
@@ -6050,8 +6224,9 @@
                                    get_xticklabel ().string_vector_value (),
                                    get_xlim ().matrix_value ());
 
-      double wmax = ext(0);
-      double hmax = ext(1);
+      double margin = 5;
+      double wmax = ext(0) + margin;
+      double hmax = ext(1) + margin;
       double angle = 0.0;
       ColumnVector p =
         graphics_xform::xform_vector ((xpTickN + xpTick)/2, ypTick, zpTick);
@@ -6148,20 +6323,12 @@
 
       Matrix ext (1, 2, 0.0);
 
-      // The underlying get_extents() from FreeType produces mismatched values.
-      // x-extent accurately measures the width of the glyphs.
-      // y-extent instead measures from baseline-to-baseline.
-      // Pad x-extent (+4) so that it approximately matches y-extent.
-      // This keeps ylabels about the same distance from y-axis as
-      // xlabels are from x-axis.
-      // ALWAYS use an even number for padding or horizontal alignment
-      // will be off.
       ext = get_ticklabel_extents (get_ytick ().matrix_value (),
                                    get_yticklabel ().string_vector_value (),
                                    get_ylim ().matrix_value ());
-
-      double wmax = ext(0)+4;
-      double hmax = ext(1);
+      double margin = 5;
+      double wmax = ext(0) + margin;
+      double hmax = ext(1) + margin;
       double angle = 0.0;
       ColumnVector p =
         graphics_xform::xform_vector (xpTick, (ypTickN + ypTick)/2, zpTick);
@@ -6263,8 +6430,9 @@
                                    get_zticklabel ().string_vector_value (),
                                    get_zlim ().matrix_value ());
 
-      double wmax = ext(0);
-      double hmax = ext(1);
+      double margin = 5;
+      double wmax = ext(0) + margin;
+      double hmax = ext(1) + margin;
       double angle = 0.0;
       ColumnVector p;
 
@@ -6581,11 +6749,13 @@
 
     }
 
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
-                         get ("__fontsize_points__").double_value ());
+                         get ("__fontsize_points__").double_value () * dpr);
 }
 
 // The INTERNAL flag defines whether position or outerposition is used.
@@ -6670,6 +6840,13 @@
             {
               Matrix text_ext = text_props.get_extent_matrix ();
 
+              // The text extent is returned in device pixels. Unscale and
+              // work with logical pixels
+              double dpr = device_pixel_ratio (get___myhandle__ ());
+              if (dpr != 1.0)
+                for (int j = 0; j < 4; j++)
+                  text_ext(j) /= dpr;
+
               bool ignore_horizontal = false;
               bool ignore_vertical = false;
               if (only_text_height)
@@ -7050,6 +7227,205 @@
     }
 }
 
+void
+axes::properties::update_outerposition (void)
+{
+  set_activepositionproperty ("outerposition");
+  caseless_str old_units = get_units ();
+  set_units ("normalized");
+
+  Matrix outerbox = outerposition.get ().matrix_value ();
+
+  double outer_left = outerbox(0);
+  double outer_bottom = outerbox(1);
+  double outer_width = outerbox(2);
+  double outer_height = outerbox(3);
+
+  double outer_right = outer_width + outer_left;
+  double outer_top = outer_height + outer_bottom;
+
+  Matrix linset = looseinset.get ().matrix_value ();
+  Matrix tinset = tightinset.get ().matrix_value ();
+
+  double left_margin = std::max (linset(0), tinset(0));
+  double bottom_margin = std::max (linset(1), tinset(1));
+  double right_margin = std::max (linset(2), tinset(2));
+  double top_margin = std::max (linset(3), tinset(3));
+
+  double inner_left = outer_left;
+  double inner_right = outer_right;
+
+  if ((left_margin + right_margin) < outer_width)
+    {
+      inner_left += left_margin;
+      inner_right -= right_margin;
+    }
+
+  double inner_bottom = outer_bottom;
+  double inner_top = outer_top;
+
+  if ((bottom_margin + top_margin) < outer_height)
+    {
+      inner_bottom += bottom_margin;
+      inner_top -= top_margin;
+    }
+
+  double inner_width = inner_right - inner_left;
+  double inner_height = inner_top - inner_bottom;
+
+  Matrix innerbox (1, 4);
+
+  innerbox(0) = inner_left;
+  innerbox(1) = inner_bottom;
+  innerbox(2) = inner_width;
+  innerbox(3) = inner_height;
+
+  position = innerbox;
+
+  set_units (old_units);
+  update_transform ();
+}
+
+void
+axes::properties::update_position (void)
+{
+  set_activepositionproperty ("position");
+  caseless_str old_units = get_units ();
+  set_units ("normalized");
+
+  Matrix innerbox = position.get ().matrix_value ();
+
+  double inner_left = innerbox(0);
+  double inner_bottom = innerbox(1);
+  double inner_width = innerbox(2);
+  double inner_height = innerbox(3);
+
+  double inner_right = inner_width + inner_left;
+  double inner_top = inner_height + inner_bottom;
+
+  Matrix linset = looseinset.get ().matrix_value ();
+  Matrix tinset = tightinset.get ().matrix_value ();
+
+  double left_margin = std::max (linset(0), tinset(0));
+  double bottom_margin = std::max (linset(1), tinset(1));
+  double right_margin = std::max (linset(2), tinset(2));
+  double top_margin = std::max (linset(3), tinset(3));
+
+  // FIXME: do we need to place limits on any of these?
+
+  double outer_left = inner_left - left_margin;
+  double outer_bottom = inner_bottom - bottom_margin;
+  double outer_right = inner_right + right_margin;
+  double outer_top = inner_top + top_margin;
+
+  double outer_width = outer_right - outer_left;
+  double outer_height = outer_top - outer_bottom;
+
+  Matrix outerbox (1, 4);
+
+  outerbox(0) = outer_left;
+  outerbox(1) = outer_bottom;
+  outerbox(2) = outer_width;
+  outerbox(3) = outer_height;
+
+  outerposition = outerbox;
+
+  set_units (old_units);
+  update_transform ();
+}
+
+void
+axes::properties::update_looseinset (void)
+{
+  caseless_str old_units = get_units ();
+  set_units ("normalized");
+
+  Matrix linset = looseinset.get ().matrix_value ();
+  Matrix tinset = tightinset.get ().matrix_value ();
+
+  double left_margin = std::max (linset(0), tinset(0));
+  double bottom_margin = std::max (linset(1), tinset(1));
+  double right_margin = std::max (linset(2), tinset(2));
+  double top_margin = std::max (linset(3), tinset(3));
+
+  if (activepositionproperty.is ("position"))
+    {
+      Matrix innerbox = position.get ().matrix_value ();
+
+      double inner_left = innerbox(0);
+      double inner_bottom = innerbox(1);
+      double inner_width = innerbox(2);
+      double inner_height = innerbox(3);
+
+      double inner_right = inner_width + inner_left;
+      double inner_top = inner_height + inner_bottom;
+
+      // FIXME: do we need to place limits on any of these?
+
+      double outer_left = inner_left - left_margin;
+      double outer_bottom = inner_bottom - bottom_margin;
+      double outer_right = inner_right + right_margin;
+      double outer_top = inner_top + top_margin;
+
+      double outer_width = outer_right - outer_left;
+      double outer_height = outer_top = outer_bottom;
+
+      Matrix outerbox (1, 4);
+
+      outerbox(0) = outer_left;
+      outerbox(1) = outer_bottom;
+      outerbox(2) = outer_width;
+      outerbox(3) = outer_height;
+
+      outerposition = outerbox;
+    }
+  else
+    {
+      Matrix outerbox = outerposition.get ().matrix_value ();
+
+      double outer_left = outerbox(0);
+      double outer_bottom = outerbox(1);
+      double outer_width = outerbox(2);
+      double outer_height = outerbox(3);
+
+      double outer_right = outer_width + outer_left;
+      double outer_top = outer_height + outer_bottom;
+
+      double inner_left = outer_left;
+      double inner_right = outer_right;
+
+      if ((left_margin + right_margin) < outer_width)
+        {
+          inner_left += left_margin;
+          inner_right -= right_margin;
+        }
+
+      double inner_bottom = outer_bottom;
+      double inner_top = outer_top;
+
+      if ((bottom_margin + top_margin) < outer_height)
+        {
+          inner_bottom += bottom_margin;
+          inner_top -= top_margin;
+        }
+
+      double inner_width = inner_right - inner_left;
+      double inner_height = inner_top - inner_bottom;
+
+      Matrix innerbox (1, 4);
+
+      innerbox(0) = inner_left;
+      innerbox(1) = inner_bottom;
+      innerbox(2) = inner_width;
+      innerbox(3) = inner_height;
+
+      position = innerbox;
+    }
+
+  set_units (old_units);
+  update_transform ();
+}
+
 // A translation from Tom Holoryd's python code at
 // http://kurage.nimh.nih.gov/tomh/tics.py
 // FIXME: add log ticks
@@ -7622,7 +7998,11 @@
           if (exponent < 10. && (exp_max > 9 || exp_min < -9))
             os << '0';
           os << exponent << '}';
-          c(i) = os.str ();
+
+          if (ticklabelinterpreter.is ("latex"))
+            c(i) = "$" + os.str () + "$";
+          else
+            c(i) = os.str ();
         }
     }
   else
@@ -7654,6 +8034,7 @@
 {
   Matrix ext (1, 2, 0.0);
   double wmax, hmax;
+  double dpr = device_pixel_ratio (get___myhandle__ ());
   wmax = hmax = 0.0;
   int n = std::min (ticklabels.numel (), ticks.numel ());
   for (int i = 0; i < n; i++)
@@ -7671,8 +8052,8 @@
               ext = txt_renderer.get_extent (label, 0.0,
                                              get_ticklabelinterpreter ());
 
-              wmax = std::max (wmax, ext(0));
-              hmax = std::max (hmax, ext(1));
+              wmax = std::max (wmax, ext(0) / dpr);
+              hmax = std::max (hmax, ext(1) / dpr);
             }
           else
             {
@@ -8611,6 +8992,35 @@
 }
 
 void
+axes::properties::trigger_normals_calc (void)
+{
+  // Find all patch (and surface) objects within axes
+  std::list<graphics_object> children_list;
+  std::list<graphics_object>::iterator children_list_iter;
+  get_children_of_type ("patch", false, true, children_list);
+  get_children_of_type ("surface", false, true, children_list);
+
+  // trigger normals calculation for these objects
+  for (children_list_iter = children_list.begin ();
+       children_list_iter != children_list.end (); children_list_iter++)
+    {
+      graphics_object kid = *children_list_iter;
+      if (kid.isa ("patch"))
+        {
+          patch::properties& patch_props =
+              dynamic_cast<patch::properties&> (kid.get_properties ());
+          patch_props.update_normals (false);
+        }
+      else
+        {
+          surface::properties& surface_props =
+              dynamic_cast<surface::properties&> (kid.get_properties ());
+          surface_props.update_normals (false);
+        }
+    }
+}
+
+void
 axes::reset_default_properties (void)
 {
   // empty list of local defaults
@@ -8699,7 +9109,14 @@
   m(0) += p(0);
   m(1) += p(1);
 
-  return convert_text_position (m, *this, "pixels", get_units ());
+  Matrix bbox = convert_text_position (m, *this, "pixels", get_units ());
+
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+
+  for (octave_idx_type ii = 0; ii < bbox.numel (); ii++)
+    bbox(ii) = bbox(ii) / dpr;
+
+  return bbox;
 }
 
 void
@@ -8737,11 +9154,13 @@
 void
 text::properties::update_font (void)
 {
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
-                         get ("__fontsize_points__").double_value ());
+                         get ("__fontsize_points__").double_value () * dpr);
 
   txt_renderer.set_color (get_color_rgb ());
 }
@@ -8838,9 +9257,9 @@
   double fontsz = get_fontsize ();
   double parent_height = box_pix_height;
 
+  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
   if (fontunits_is ("normalized") && parent_height <= 0)
     {
-      graphics_object go (gh_manager::get_object (get___myhandle__ ()));
       graphics_object ax (go.get_ancestor ("axes"));
 
       parent_height = ax.get_properties ().get_boundingbox (true).elem (3);
@@ -8859,6 +9278,41 @@
 
 // ---------------------------------------------------------------------
 
+void
+light::initialize (const graphics_object& go)
+{
+  base_graphics_object::initialize (go);
+
+  // trigger normals calculation for the respective children of this axes object
+  axes::properties& parent_axes_prop =
+    dynamic_cast<axes::properties&> (go.get_ancestor ("axes").get_properties ());
+  parent_axes_prop.trigger_normals_calc ();
+}
+
+void
+light::properties::update_visible (void)
+{
+  graphics_object go = gh_manager::get_object (get___myhandle__ ());
+  axes::properties& ax_props = dynamic_cast<axes::properties&>
+    (go.get_ancestor ("axes").get_properties ());
+  if (is_visible ())
+    ax_props.increase_num_lights ();
+  else
+    ax_props.decrease_num_lights ();
+}
+
+// ---------------------------------------------------------------------
+
+bool
+patch::properties::get_do_lighting (void) const
+{
+  graphics_object go = gh_manager::get_object (get___myhandle__ ());
+  axes::properties& ax_props = dynamic_cast<axes::properties&>
+    (go.get_ancestor ("axes").get_properties ());
+
+  return (ax_props.get_num_lights () > 0);
+}
+
 octave_value
 patch::properties::get_color_data (void) const
 {
@@ -8995,6 +9449,53 @@
         }
     }
 
+  // check coplanarity for 3D-faces with more than 3 corners
+  int fcmax = idx.rows ();
+  if (fcmax > 3 && vert.columns () > 2)
+    {
+      for (octave_idx_type jj = 0; jj < idx.columns (); jj++)
+        {
+          if (! octave::math::isnan (idx(3,jj)))
+            {
+              // find first element that is NaN to get number of corners
+              octave_idx_type nc = 3;
+              while (! octave::math::isnan (idx(nc,jj)) && nc < fcmax)
+                nc++;
+
+              std::list<octave_idx_type> coplanar_ends;
+
+              octave_idx_type i_start = 1;
+              octave_idx_type i_end = 2;
+              while (i_end < nc - 1)
+                {
+                  // look for coplanar subsets
+                  for (i_end = nc-1; i_end > i_start+1; i_end--)
+                    {
+                      Matrix fc = Matrix (i_end - i_start + 1, 3, 0.0);
+                      for (octave_idx_type j = 0; j <= i_end-i_start; j++)
+                        for (octave_idx_type i = 0; i < 3; i++)
+                          fc(j,i) = vert(idx(j + i_start,jj)-1,i)
+                                    - vert(idx(0,jj)-1,i);
+
+                      // calculate rank of matrix
+                      octave::math::svd<Matrix> result
+                        (fc,
+                         octave::math::svd<Matrix>::Type::sigma_only,
+                         octave::math::svd<Matrix>::Driver::GESVD);
+                      DiagMatrix sigma = result.singular_values ();
+                      double tol = nc * sigma(0,0)
+                                   * std::numeric_limits<double>::epsilon ();
+                      if (sigma(2,2) < tol)
+                        break;
+                    }
+                  coplanar_ends.push_back (i_end);
+                  i_start = i_end;
+                }
+              coplanar_last_idx.push_back (coplanar_ends);
+            }
+        }
+    }
+
   // Build cdata
   dim_vector dv = dim_vector::alloc (3);
   NDArray cd;
@@ -9047,6 +9548,9 @@
         }
     }
 
+  // Update normals
+  update_normals (true);
+
   octave::unwind_protect frame;
   frame.protect_var (updating_patch_data);
   updating_patch_data = true;
@@ -9057,14 +9561,6 @@
   set_cdata (cd);
 }
 
-// ---------------------------------------------------------------------
-
-octave_value
-surface::properties::get_color_data (void) const
-{
-  return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
-}
-
 inline void
 cross_product (double x1, double y1, double z1,
                double x2, double y2, double z2,
@@ -9076,9 +9572,393 @@
 }
 
 void
-surface::properties::update_vertex_normals (void)
-{
-  if (vertexnormalsmode_is ("auto"))
+patch::properties::calc_face_normals (Matrix& fn)
+{
+  Matrix v = get_vertices ().matrix_value ();
+  Matrix f = get_faces ().matrix_value ();
+
+  bool is_3D = (v.columns () == 3);   // 2D or 3D patches
+  octave_idx_type num_f = f.rows ();  // number of faces
+  octave_idx_type max_nc = f.columns ();  // max. number of polygon corners
+
+  // In which cases can we skip updating the normals?
+  if (max_nc < 3)
+    {
+      fn = Matrix ();
+      return;
+    }
+
+  // Calculate normals for all faces
+  std::list<std::list<octave_idx_type>>::const_iterator
+    cp_it = coplanar_last_idx.begin ();
+  octave_idx_type i1, i2, i3;
+  octave_idx_type j1, j2;
+  for (octave_idx_type i = 0; i < num_f; i++)
+    {
+      bool is_coplanar = true;
+      if (coplanar_last_idx.size () > 0)
+        {
+          if ((*cp_it).size () > 1)
+          {
+            is_coplanar = false;
+          }
+          cp_it++;
+        }
+
+      // get number of corners
+      octave_idx_type nc = 3;
+      if (max_nc > 3)
+        {
+          while (! octave::math::isnan (f(i,nc)) && nc < max_nc)
+            nc++;
+        }
+
+      RowVector fnc (3, 0.0);
+      double& nx = fnc(0);
+      double& ny = fnc(1);
+      double& nz = fnc(2);
+
+      if (is_coplanar)
+        {
+          // fast way for coplanar polygons
+          i1 = f(i,0) - 1; i2 = f(i,1) - 1; i3 = f(i,nc-1) - 1;
+
+          if (is_3D)
+            cross_product
+              (v(i3,0) - v(i1,0), v(i3,1) - v(i1,1), v(i3,2) - v(i1,2),
+               v(i2,0) - v(i1,0), v(i2,1) - v(i1,1), v(i2,2) - v(i1,2),
+               nx, ny, nz);
+          else
+            {
+              nz = (v(i2,0) - v(i1,0)) * (v(i3,1) - v(i1,1)) -
+                   (v(i2,1) - v(i1,1)) * (v(i3,0) - v(i1,0));
+              // 2-d vertices always point towards +z
+              nz = (nz < 0) ? -nz : nz;
+            }
+        }
+      else
+        {
+          // more general for non-planar polygons
+
+          // calculate face normal with Newell's method
+          // https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal#Newell.27s_Method
+
+          j1 = nc - 1; j2 = 0;
+          i1 = f(i,j1) - 1; i2 = f(i,j2) - 1;
+
+          nx = (v(i2,1) - v(i1,1)) * (v(i1,2) + v(i2,2));
+          ny = (v(i2,2) - v(i1,2)) * (v(i1,0) + v(i2,0));
+          nz = (v(i2,0) - v(i1,0)) * (v(i1,1) + v(i2,1));
+
+          for (octave_idx_type j = 1; j < nc; j++)
+            {
+              j1 = j-1; j2 = j;
+              i1 = f(i,j1) - 1; i2 = f(i,j2) - 1;
+
+              nx += (v(i2,1) - v(i1,1)) * (v(i1,2) + v(i2,2));
+              ny += (v(i2,2) - v(i1,2)) * (v(i1,0) + v(i2,0));
+              nz += (v(i2,0) - v(i1,0)) * (v(i1,1) + v(i2,1));
+            }
+        }
+
+      // normalize normal vector
+      double n_len = sqrt (nx*nx+ny*ny+nz*nz);
+
+      // assign normal to current face
+      if ( n_len < std::numeric_limits<double>::epsilon () )
+        for (octave_idx_type j = 0; j < 3; j++)
+          fn(i,j) = 0.0;
+      else
+        for (octave_idx_type j = 0; j < 3; j++)
+          fn(i,j) = fnc(j) / n_len;
+    }
+}
+
+void
+patch::properties::update_face_normals (bool reset, bool force)
+{
+  if (updating_patch_data || ! facenormalsmode_is ("auto"))
+    return;
+
+  if (force || ((facelighting_is ("flat") || edgelighting_is ("flat")) &&
+                get_do_lighting ()))
+    {
+      Matrix f = get_faces ().matrix_value ();
+
+      octave_idx_type num_f = f.rows ();  // number of faces
+      Matrix fn (num_f, 3, 0.0);
+
+      calc_face_normals (fn);
+      facenormals = fn;
+    }
+  else if (reset)
+    facenormals = Matrix ();
+}
+
+void
+patch::properties::update_vertex_normals (bool reset, bool force)
+{
+  if (updating_patch_data || ! vertexnormalsmode_is ("auto"))
+    return;
+
+  if (force || ((facelighting_is ("gouraud") || facelighting_is ("phong")
+                 || edgelighting_is ("gouraud") || edgelighting_is ("phong"))
+                && get_do_lighting ()))
+    {
+      Matrix v = get_vertices ().matrix_value ();
+      Matrix f = get_faces ().matrix_value ();
+
+      octave_idx_type num_v = v.rows ();  // number of vertices
+      octave_idx_type num_f = f.rows ();  // number of faces
+      octave_idx_type max_nc = f.columns ();  // max. number of polygon corners
+
+      // In which cases can we skip updating the normals?
+      if (max_nc < 3)
+        return;
+
+      // First step: Calculate the normals for all faces
+      Matrix fn = get_facenormals ().matrix_value ();
+      if ( fn.isempty () )
+        {
+          // calculate facenormals here
+          fn = Matrix (num_f, 3, 0.0);
+          calc_face_normals (fn);
+        }
+
+      // Second step: assign normals to the respective vertices
+      std::vector<RowVector> vec_vn [num_v];  // list of normals for vertices
+      for (octave_idx_type i = 0; i < num_f; i++)
+        {
+          // get number of corners
+          octave_idx_type nc = 3;
+          if (max_nc > 3)
+            {
+              while (! octave::math::isnan (f(i,nc)) && nc < max_nc)
+                nc++;
+            }
+
+          for (octave_idx_type j = 0; j < nc; j++)
+            vec_vn[static_cast<octave_idx_type> (f(i,j) - 1)].push_back (fn.row (i));
+        }
+
+      // Third step: Calculate the normal for the vertices taking the average
+      // of the normals determined from all adjacent faces
+      Matrix vn (num_v, 3, 0.0);
+      for (octave_idx_type i = 0; i < num_v; i++)
+        {
+          std::vector<RowVector>::iterator it = vec_vn[i].begin ();
+
+          // The normal of unused vertices is NaN.
+          RowVector vn0 (3, octave_NaN);
+
+          if (it != vec_vn[i].end ())
+            {
+              // FIXME: Currently, the first vector also determines the
+              // direction of the normal.  How to determine the inner and outer
+              // faces of all parts of the patch and point the normals outwards?
+              // (Necessary for correct lighting with "backfacelighting" set to
+              // "lit" or "unlit".) Matlab does not seem to do it correctly
+              // either.  So bother here?
+
+              vn0 = *it;
+
+              for (++it; it != vec_vn[i].end (); ++it)
+                {
+                  RowVector vn1 = *it;
+                  // Use sign of dot product to point vectors in a similar
+                  // direction before taking the average.
+                  double dir =
+                    (vn0(0)*vn1(0) + vn0(1)*vn1(1) + vn0(2)*vn1(2) < 0) ? -1
+                                                                        : 1;
+                  for (octave_idx_type j = 0; j < 3; j++)
+                    vn0(j) += dir * vn1(j);
+                }
+
+              // normalize normal vector
+              double n_len = sqrt (vn0(0)*vn0(0)+vn0(1)*vn0(1)+vn0(2)*vn0(2));
+
+              // save normal in matrix
+              for (octave_idx_type j = 0; j < 3; j++)
+                vn(i,j) = vn0(j)/n_len;
+            }
+        }
+
+      vertexnormals = vn;
+    }
+  else if (reset)
+    vertexnormals = Matrix ();
+}
+
+void
+patch::initialize (const graphics_object& go)
+{
+  base_graphics_object::initialize (go);
+
+  // calculate normals for default data
+  // This is done because the normals for the default data do not match
+  // get(0, "DefaultPatchVertexNormals") in Matlab.
+  xproperties.update_normals (true);
+}
+
+
+void
+patch::reset_default_properties (void)
+{
+  // empty list of local defaults
+  default_properties = property_list ();
+  xreset_default_properties (get_handle (), xproperties.factory_defaults ());
+
+  // calculate normals for default data
+  // This is done because the normals for the default data do not match
+  // get(0, "DefaultPatchVertexNormals") in Matlab.
+  xproperties.update_normals (true);
+}
+
+// ---------------------------------------------------------------------
+
+octave_value
+surface::properties::get_color_data (void) const
+{
+  return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
+}
+
+bool
+surface::properties::get_do_lighting (void) const
+{
+  graphics_object go = gh_manager::get_object (get___myhandle__ ());
+  axes::properties& ax_prop = dynamic_cast<axes::properties&>
+    (go.get_ancestor ("axes").get_properties ());
+
+  return (ax_prop.get_num_lights () > 0);
+}
+
+void
+surface::properties::update_face_normals (bool reset, bool force)
+{
+  if (! facenormalsmode_is ("auto"))
+    return;
+
+  if (force || ((facelighting_is ("flat") || edgelighting_is ("flat")) &&
+                get_do_lighting ()))
+    {
+      Matrix x = get_xdata ().matrix_value ();
+      Matrix y = get_ydata ().matrix_value ();
+      Matrix z = get_zdata ().matrix_value ();
+
+      int p = z.columns ();
+      int q = z.rows ();
+
+      // FIXME: There might be a cleaner way to do this.  When data is changed
+      // the update_xdata, update_ydata, update_zdata routines are called in a
+      // serial fashion.  Until the final call to update_zdata the matrices
+      // will be of mismatched dimensions which can cause an out-of-bound
+      // indexing in the code below.  This one-liner prevents calculating
+      // normals until dimensions match.
+      if (x.columns () != p || y.rows () != q)
+        return;
+
+      bool x_mat = (x.rows () == q);
+      bool y_mat = (y.columns () == p);
+
+      NDArray n (dim_vector (q-1, p-1, 3), 1);
+
+      int i1, i2, j1, j2;
+      i1 = i2 = 0;
+      j1 = j2 = 0;
+      double x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3;
+      double x1m0, x2m1, x3m2, x0m3, y1m0, y2m1, y3m2, y0m3;
+      double x1p0, x2p1, x3p2, x0p3, y1p0, y2p1, y3p2, y0p3;
+      x3m2 = y0m3 = -1;
+      x2m1 = x0m3 = y1m0 = y3m2 = 0;
+      x1m0 = y2m1 = 1;
+      x0p3 = y1p0 = 0;
+      x1p0 = x3p2 = y2p1 = y0p3 = 1;
+      x2p1 = y3p2 = 2;
+
+      for (int i = 0; i < p-1; i++)
+        {
+          if (y_mat)
+            {
+              i1 = i;
+              i2 = i + 1;
+            }
+
+          for (int j = 0; j < q-1; j++)
+            {
+              if (x_mat)
+                {
+                  j1 = j;
+                  j2 = j + 1;
+                }
+
+              if (x_mat || y_mat)
+                {
+                  x0 = x(j1,i1);
+                  x1 = x(j1,i2);
+                  x2 = x(j2,i2);
+                  x3 = x(j2,i1);
+                  x1m0 = x1 - x0;
+                  x2m1 = x2 - x1;
+                  x3m2 = x3 - x2;
+                  x0m3 = x0 - x3;
+                  x1p0 = x1 + x0;
+                  x2p1 = x2 + x1;
+                  x3p2 = x3 + x2;
+                  x0p3 = x0 + x3;
+                  y0 = y(j1,i1);
+                  y1 = y(j1,i2);
+                  y2 = y(j2,i2);
+                  y3 = y(j2,i1);
+                  y1m0 = y1 - y0;
+                  y2m1 = y2 - y1;
+                  y3m2 = y3 - y2;
+                  y0m3 = y0 - y3;
+                  y1p0 = y1 + y0;
+                  y2p1 = y2 + y1;
+                  y3p2 = y3 + y2;
+                  y0p3 = y0 + y3;
+                }
+
+              double& nx = n(j,i,0);
+              double& ny = n(j,i,1);
+              double& nz = n(j,i,2);
+
+              z0 = z(j1,i1);
+              z1 = z(j1,i2);
+              z2 = z(j2,i2);
+              z3 = z(j2,i1);
+
+              // calculate face normal with Newell's method
+              // https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal#Newell.27s_Method
+
+              nx = y1m0 * (z1 + z0) + y2m1 * (z2 + z1)
+                   + y3m2 * (z3 + z2) + y0m3 * (z0 + z3);
+              ny = (z1 - z0) * x1p0 + (z2 - z1) * x2p1
+                   + (z3 - z2) * x3p2 + (z0 - z3) * x0p3;
+              nz = x1m0 * y1p0 + x2m1 * y2p1 + x3m2 * y3p2 + x0m3 * y0p3;
+
+              double d = std::max (std::max (fabs (nx), fabs (ny)), fabs (nz));
+
+              nx /= d;
+              ny /= d;
+              nz /= d;
+            }
+        }
+      facenormals = n;
+    }
+  else if (reset)
+    facenormals = Matrix ();
+}
+
+void
+surface::properties::update_vertex_normals (bool reset, bool force)
+{
+  if (! vertexnormalsmode_is ("auto"))
+    return;
+
+  if (force || ((facelighting_is ("gouraud") || facelighting_is ("phong") ||
+      edgelighting_is ("gouraud") || edgelighting_is ("phong")) &&
+      get_do_lighting ()))
     {
       Matrix x = get_xdata ().matrix_value ();
       Matrix y = get_ydata ().matrix_value ();
@@ -9164,11 +10044,108 @@
         }
       vertexnormals = n;
     }
-}
+  else if (reset)
+    vertexnormals = Matrix ();
+}
+
+DEFUN (__update_normals__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __update_normals__ (@var{h})
+Update FaceNormals and VertexNormals of the patch or surface referred to by
+@var{h}.
+
+@end deftypefn */)
+{
+  gh_manager::auto_lock guard;
+
+  if (args.length () != 1)
+    print_usage ();
+
+  octave_value val = args(0);
+
+  graphics_object go = gh_manager::get_object (val);
+
+  if (go.isa ("surface"))
+    {
+      surface::properties& props =
+        dynamic_cast <surface::properties&> (go.get_properties ());
+      props.update_normals (false, true);
+    }
+  else if (go.isa ("patch"))
+    {
+      patch::properties& props =
+        dynamic_cast <patch::properties&> (go.get_properties ());
+      props.update_normals (false, true);
+    }
+  else
+    error ("__update_normals__: "
+           "H must be a handle to a valid surface or patch object.");
+
+  return ovl ();
+}
+
+/*
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   Z = peaks ();
+%!   hs = surf (Z, "facelighting", "none");
+%!   assert (isempty (get (hs, "vertexnormals")));
+%!   assert (isempty (get (hs, "facenormals")));
+%!   __update_normals__ (hs);
+%!   assert (! isempty (get (hs, "vertexnormals")));
+%!   assert (! isempty (get (hs, "facenormals")));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hp = patch ("facelighting", "none");
+%!   assert (isempty (get (hp, "vertexnormals")));
+%!   assert (isempty (get (hp, "facenormals")));
+%!   __update_normals__ (hp);
+%!   assert (! isempty (get (hp, "vertexnormals")));
+%!   assert (! isempty (get (hp, "facenormals")));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+*/
 
 // ---------------------------------------------------------------------
 
 void
+hggroup::properties::remove_child (const graphics_handle& h)
+{
+  graphics_object go = gh_manager::get_object (h);
+  if (go.isa ("light") && go.get_properties ().is_visible ())
+    {
+      axes::properties& ax_props =
+        dynamic_cast<axes::properties&>
+        (go.get_ancestor ("axes").get_properties ());
+      ax_props.decrease_num_lights ();
+    }
+  base_properties::remove_child (h);
+  update_limits ();
+}
+
+void
+hggroup::properties::adopt (const graphics_handle& h)
+{
+  graphics_object go = gh_manager::get_object (h);
+  if (go.isa ("light") && go.get_properties ().is_visible ())
+    {
+      axes::properties& ax_props =
+        dynamic_cast<axes::properties&>
+        (go.get_ancestor ("axes").get_properties ());
+      ax_props.increase_num_lights ();
+    }
+  base_properties::adopt (h);
+  update_limits (h);
+}
+
+void
 hggroup::properties::update_limits (void) const
 {
   graphics_object go = gh_manager::get_object (__myhandle__);
@@ -9463,14 +10440,14 @@
 void
 uicontrol::properties::update_text_extent (void)
 {
-  text_element *elt;
+  octave::text_element *elt;
   octave::text_renderer txt_renderer;
   Matrix box;
 
   // FIXME: parsed content should be cached for efficiency
   // FIXME: support multiline text
 
-  elt = text_parser::parse (get_string_string (), "none");
+  elt = octave::text_parser::parse (get_string_string (), "none");
 
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get_fontname (), get_fontweight (),
@@ -9509,9 +10486,6 @@
 void
 uicontrol::properties::set_style (const octave_value& st)
 {
-  if (! get___object__ ().isempty ())
-    error ("set: cannot change the style of a uicontrol object after creation.");
-
   style = st;
 
   // if we know know what we are, can override value for listbox and popupmenu
@@ -9658,6 +10632,37 @@
 }
 
 void
+uibuttongroup::properties::set_position (const octave_value& v)
+{
+  Matrix old_bb, new_bb;
+  bool modified = false;
+
+  old_bb = get_boundingbox (true);
+  modified = position.set (v, false);
+  new_bb = get_boundingbox (true);
+
+  if (old_bb != new_bb)
+    {
+      if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
+        {
+          if (! get_resizefcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "resizefcn");
+
+          if (! get_sizechangedfcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "sizechangedfcn");
+
+          update_boundingbox ();
+        }
+    }
+
+  if (modified)
+    {
+      position.run_listeners (POSTSET);
+      mark_modified ();
+    }
+}
+
+void
 uibuttongroup::properties::set_units (const octave_value& val)
 {
   caseless_str old_units = get_units ();
@@ -9829,6 +10834,38 @@
 }
 
 void
+uipanel::properties::set_position (const octave_value& v)
+{
+  Matrix old_bb, new_bb;
+  bool modified = false;
+
+  old_bb = get_boundingbox (true);
+  modified = position.set (v, false);
+  new_bb = get_boundingbox (true);
+
+  if (old_bb != new_bb)
+    {
+      if (old_bb(2) != new_bb(2) || old_bb(3) != new_bb(3))
+        {
+          if (! get_resizefcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "resizefcn");
+
+          if (! get_sizechangedfcn ().isempty ())
+            gh_manager::post_callback (__myhandle__, "sizechangedfcn");
+
+          update_boundingbox ();
+        }
+    }
+
+  if (modified)
+    {
+      position.run_listeners (POSTSET);
+      mark_modified ();
+    }
+}
+
+
+void
 uipanel::properties::set_units (const octave_value& val)
 {
   caseless_str old_units = get_units ();
@@ -9891,6 +10928,239 @@
 
 // ---------------------------------------------------------------------
 
+Matrix
+uitable::properties::get_boundingbox (bool,
+                                      const Matrix& parent_pix_size) const
+{
+  Matrix pos = get_position ().matrix_value ();
+  Matrix parent_size (parent_pix_size);
+
+  if (parent_size.isempty ())
+    {
+      graphics_object go = gh_manager::get_object (get_parent ());
+
+      parent_size =
+        go.get_properties ().get_boundingbox (true).extract_n (0, 2, 1, 2);
+    }
+
+  pos = convert_position (pos, get_units (), "pixels", parent_size);
+
+  pos(0)--;
+  pos(1)--;
+  pos(1) = parent_size(1) - pos(1) - pos(3);
+
+  return pos;
+}
+
+void
+uitable::properties::set_columnformat (const octave_value& val)
+{
+  /* Matlab only allows certain values for ColumnFormat. Here we only check the
+   * structure of the argument.  Values will be checked in Table.cc */
+
+  if (val.iscellstr ())
+    {
+      if (columnformat.set (val, true))
+        mark_modified ();
+    }
+  else if (val.iscell ())
+    {
+      Cell cell_value = val.cell_value ();
+
+      for (int i = 0; i < cell_value.numel (); i++)
+        {
+          octave_value v = cell_value(i);
+          if (v.iscell ())
+            {
+              /* We are in a pop-up menu selection.
+               * Matlab only allows non-empty strings here. */
+              Cell popup = v.cell_value ();
+              for (int j = 0; j < popup.numel (); j++)
+                {
+                  octave_value p = popup(j);
+                  if (! p.is_string () || p.isempty ())
+                    error ("set: pop-up menu definitions must be non-empty strings.");
+                }
+            }
+          else if (! (v.is_string () || v.isempty ()))
+            {
+              error ("set: columnformat definintions must be a cellstr of "
+                     "either 'char', 'short [e|g|eng]?', 'long [e|g|eng]?', "
+                     "'numeric', 'bank', '+', 'rat', 'logical', "
+                     "or a cellstr of non-empty pop-up menu definitions.");
+            }
+        }
+
+      if (columnformat.set (val, true))
+        mark_modified ();
+    }
+  else if (val.isempty ())
+    {
+      if (columnformat.set (Cell (), true))
+        mark_modified ();
+    }
+  else
+    {
+      error ("set: expecting cell of strings.");
+    }
+}
+
+void
+uitable::properties::set_columnwidth (const octave_value& val)
+{
+  bool error_exists = false;
+
+  if (val.is_string () && val.string_value (false) == "auto")
+    error_exists = false;
+  else if (val.iscell ())
+    {
+      Cell cell_value = val.cell_value ();
+      for (int i = 0; i < cell_value.numel (); i++)
+        {
+          octave_value v = cell_value(i);
+          if (v.is_string ())
+            {
+              if (v.string_value (false) != "auto")
+                error_exists = true;
+            }
+          else if (v.iscell ())
+            {
+              error_exists = true;
+            }
+          else if (! v.is_scalar_type ())
+            {
+              error_exists = true;
+            }
+        }
+    }
+  else
+    error_exists = true;
+
+  if (error_exists)
+    error ("set: expecting either 'auto' or a cell of pixel values or auto.");
+  else
+    {
+      if (columnwidth.set (val, true))
+        mark_modified ();
+    }
+}
+
+void
+uitable::properties::set_units (const octave_value& val)
+{
+  caseless_str old_units = get_units ();
+
+  if (units.set (val, true))
+    {
+      update_units (old_units);
+      mark_modified ();
+    }
+}
+
+void
+uitable::properties::update_units (const caseless_str& old_units)
+{
+  Matrix pos = get_position ().matrix_value ();
+
+  graphics_object parent_go = gh_manager::get_object (get_parent ());
+  Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
+  Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
+
+  pos = convert_position (pos, old_units, get_units (), parent_size);
+  set_position (pos);
+}
+
+void
+uitable::properties::set_fontunits (const octave_value& val)
+{
+  caseless_str old_fontunits = get_fontunits ();
+
+  if (fontunits.set (val, true))
+    {
+      update_fontunits (old_fontunits);
+      mark_modified ();
+    }
+}
+
+void
+uitable::properties::update_fontunits (const caseless_str& old_units)
+{
+  caseless_str new_units = get_fontunits ();
+  double parent_height = get_boundingbox (false).elem (3);
+  double fontsz = get_fontsize ();
+
+  fontsz = convert_font_size (fontsz, old_units, new_units, parent_height);
+
+  set_fontsize (octave_value (fontsz));
+}
+
+double
+uitable::properties::get___fontsize_points__ (double box_pix_height) const
+{
+  double fontsz = get_fontsize ();
+  double parent_height = box_pix_height;
+
+  if (fontunits_is ("normalized") && parent_height <= 0)
+    parent_height = get_boundingbox (false).elem (3);
+
+  return convert_font_size (fontsz, get_fontunits (), "points", parent_height);
+}
+
+double
+uitable::properties::get_fontsize_pixels (double box_pix_height) const
+{
+  double fontsz = get_fontsize ();
+  double parent_height = box_pix_height;
+
+  if (fontunits_is ("normalized") && parent_height <= 0)
+    parent_height = get_boundingbox (false).elem (3);
+
+  return convert_font_size (fontsz, get_fontunits (), "pixels", parent_height);
+}
+
+Matrix
+uitable::properties::get_backgroundcolor_rgb (void)
+{
+  Matrix bg = backgroundcolor.get ().matrix_value ();
+  return bg.row (0);
+}
+
+Matrix
+uitable::properties::get_alternatebackgroundcolor_rgb (void)
+{
+  int i = 0;
+  Matrix bg = backgroundcolor.get ().matrix_value ();
+  if (bg.rows () > 1)
+    i = 1;
+
+  return bg.row (i);
+}
+
+Matrix
+uitable::properties::get_extent_matrix (void) const
+{
+  return extent.get ().matrix_value ();
+}
+
+octave_value
+uitable::properties::get_extent (void) const
+{
+  // FIXME: Is it really acceptable to just let the toolkit update the extent?
+  Matrix m = extent.get ().matrix_value ();
+  graphics_object parent_go = gh_manager::get_object (get_parent ());
+  if (parent_go)
+    {
+      Matrix parent_bbox = parent_go.get_properties ().get_boundingbox (true);
+      Matrix parent_size = parent_bbox.extract_n (0, 2, 1, 2);
+
+      return convert_position (m, "pixels", get_units (), parent_size);
+    }
+
+  return m;
+}
+
+// ---------------------------------------------------------------------
+
 octave_value
 uitoolbar::get_default (const caseless_str& pname) const
 {
@@ -10065,13 +11335,15 @@
 {
 public:
   callback_event (const graphics_handle& h, const std::string& name,
-                  const octave_value& data = Matrix ())
-    : base_graphics_event (), handle (h), callback_name (name),
+                  const octave_value& data = Matrix (),
+                  int busyaction = base_graphics_event::QUEUE)
+    : base_graphics_event (busyaction), handle (h), callback_name (name),
       callback (), callback_data (data) { }
 
   callback_event (const graphics_handle& h, const octave_value& cb,
-                  const octave_value& data = Matrix ())
-    : base_graphics_event (), handle (h), callback_name (),
+                  const octave_value& data = Matrix (),
+                  int busyaction = base_graphics_event::QUEUE)
+    : base_graphics_event (busyaction), handle (h), callback_name (),
       callback (cb), callback_data (data) { }
 
   void execute (void)
@@ -10164,17 +11436,19 @@
 graphics_event
 graphics_event::create_callback_event (const graphics_handle& h,
                                        const std::string& name,
-                                       const octave_value& data)
-{
-  return graphics_event (new callback_event (h, name, data));
+                                       const octave_value& data,
+                                       int busyaction)
+{
+  return graphics_event (new callback_event (h, name, data, busyaction));
 }
 
 graphics_event
 graphics_event::create_callback_event (const graphics_handle& h,
                                        const octave_value& cb,
-                                       const octave_value& data)
-{
-  return graphics_event (new callback_event (h, cb, data));
+                                       const octave_value& data,
+                                       int busyaction)
+{
+  return graphics_event (new callback_event (h, cb, data, busyaction));
 }
 
 graphics_event
@@ -10271,7 +11545,10 @@
 
           try
             {
-              octave::eval_string (s, false, status, 0);
+              octave::interpreter& interp
+                = octave::__get_interpreter__ ("gh_manager::do_execute_callback");
+
+              interp.eval_string (s, false, status, 0);
             }
           catch (octave::execution_exception&)
             {
@@ -10350,36 +11627,25 @@
 
   if (go.valid_object ())
     {
-      if (callback_objects.empty ())
-        do_post_event (graphics_event::create_callback_event (h, name, data));
-      else
-        {
-          const graphics_object& current = callback_objects.front ();
-
-          if (current.get_properties ().is_interruptible ())
-            do_post_event (graphics_event::create_callback_event (h, name,
-                                                                  data));
-          else
-            {
-              std::string busy_action (go.get_properties ().get_busyaction ());
-
-              if (busy_action == "queue")
-                do_post_event (graphics_event::create_callback_event (h, name,
-                                                                      data));
-              else
-                {
-                  caseless_str cname (name);
-
-                  if (cname.compare ("deletefcn")
-                      || cname.compare ("createfcn")
-                      || (go.isa ("figure")
-                          && (cname.compare ("closerequestfcn")
-                              || cname.compare ("resizefcn"))))
-                    do_post_event (
-                      graphics_event::create_callback_event (h, name, data));
-                }
-            }
-        }
+      caseless_str cname (name);
+      int busyaction = base_graphics_event::QUEUE;
+
+      if (cname.compare ("deletefcn")
+          || cname.compare ("createfcn")
+          || (go.isa ("figure")
+              && cname.compare ("closerequestfcn"))
+          || ((go.isa ("figure")
+               || go.isa ("uipanel")
+               || go.isa ("uibuttongroup"))
+              && (cname.compare ("resizefcn")
+                  || cname.compare ("sizechangedfcn"))))
+        busyaction = base_graphics_event::INTERRUPT;
+      else if (go.get_properties ().get_busyaction () == "cancel")
+        busyaction = base_graphics_event::CANCEL;
+
+
+      do_post_event (graphics_event::create_callback_event (h, name, data,
+                                                            busyaction));
     }
 }
 
@@ -10433,6 +11699,26 @@
 
                     event_queue.pop_front ();
                   }
+                else
+                  {
+                    std::list<graphics_event>::iterator p =
+                      event_queue.begin ();
+
+                    while (p != event_queue.end ())
+                      if (p->get_busyaction () == base_graphics_event::CANCEL)
+                        {
+                          p = event_queue.erase (p);
+                        }
+                      else if (p->get_busyaction ()
+                               == base_graphics_event::INTERRUPT)
+                        {
+                          e = (*p);
+                          event_queue.erase (p);
+                          break;
+                        }
+                      else
+                        p++;
+                  }
               }
           }
       }
@@ -10465,6 +11751,60 @@
   return 0;
 }
 
+
+/*
+## Test interruptible/busyaction properties
+%!function cb (h)
+%! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
+%! drawnow ();
+%! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
+%!endfunction
+%!
+%!testif HAVE_OPENGL, HAVE_FLTK; have_window_system
+%! hf = figure ("visible", "off", "resizefcn", @cb);
+%! unwind_protect
+%!   ## Default
+%!   hui1 = uicontrol ("parent", hf, "interruptible", "on", "callback", @cb);
+%!   hui2 = uicontrol ("parent", hf, "busyaction", "queue", "callback", @cb);
+%!   hui3 = uicontrol ("parent", hf, "busyaction", "queue", "callback", @cb);
+%!   __go_post_callback__ (hui1, "callback");
+%!   __go_post_callback__ (hui2, "callback");
+%!   __go_post_callback__ (hui3, "callback");
+%!
+%!   assert (getappdata (hf, "cb_exec"), []);
+%!   drawnow ();
+%!   assert (getappdata (hf, "cb_exec"), [hui1 hui2 hui3 hui3 hui2 hui1]);
+%!
+%!   ## Interruptible off
+%!   setappdata (hf, "cb_exec", []);
+%!   set (hui1, "interruptible", "off");
+%!   __go_post_callback__ (hui1, "callback");
+%!   __go_post_callback__ (hui2, "callback");
+%!   __go_post_callback__ (hui3, "callback");
+%!   drawnow ();
+%!   assert (getappdata (hf, "cb_exec"), [hui1 hui1 hui2 hui3 hui3 hui2]);
+%!
+%!   ## "resizefcn" callback interrupts regardless of interruptible property
+%!   setappdata (hf, "cb_exec", []);
+%!   __go_post_callback__ (hui1, "callback");
+%!   __go_post_callback__ (hf, "resizefcn");
+%!   drawnow ();
+%!   assert (getappdata (hf, "cb_exec"), [hui1 hf hf hui1]);
+%!
+%!   ## test "busyaction" "cancel"
+%!   setappdata (hf, "cb_exec", []);
+%!   set (hui2, "busyaction", "cancel");
+%!   __go_post_callback__ (hui1, "callback");
+%!   __go_post_callback__ (hui2, "callback");
+%!   __go_post_callback__ (hui3, "callback");
+%!   __go_post_callback__ (hf, "resizefcn");
+%!   drawnow ();
+%!   assert (getappdata (hf, "cb_exec"), [hui1 hf hui3 hui3 hf hui1]);
+%! unwind_protect_cleanup
+%!   close (hf)
+%! end_unwind_protect
+*/
+
 void
 gh_manager::do_enable_event_processing (bool enable)
 {
@@ -10529,7 +11869,7 @@
   if (args.length () != 1)
     print_usage ();
 
-  return ovl (is_hghandle (args(0)));
+  return ovl (ishghandle (args(0)));
 }
 
 /*
@@ -10842,7 +12182,9 @@
           else if (hcv.numel () == args(2).cell_value ().rows ())
             go.set (args(1).cellstr_value (), args(2).cell_value (), n);
           else
-            error ("set: number of graphics handles must match number of value rows (%d != %d)",
+            error ("set: number of graphics handles must match number of "
+                   "value rows (%" OCTAVE_IDX_TYPE_FORMAT " != "
+                   "%" OCTAVE_IDX_TYPE_FORMAT ")",
                    hcv.numel (), args(2).cell_value ().rows ());
         }
       else if (nargin == 2 && args(1).isstruct ())
@@ -11173,7 +12515,7 @@
 
   octave_value retval;
 
-  if (is_figure (val))
+  if (isfigure (val))
     {
       graphics_handle h = gh_manager::lookup (val);
 
@@ -11421,6 +12763,15 @@
   GO_BODY (uicontextmenu);
 }
 
+DEFUN (__go_uitable__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __go_uitable__ (@var{parent})
+Undocumented internal function.
+@end deftypefn */)
+{
+  GO_BODY (uitable);
+}
+
 DEFUN (__go_uitoolbar__, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} __go_uitoolbar__ (@var{parent})
@@ -11544,6 +12895,40 @@
   return ovl ();
 }
 
+DEFUN (__go_post_callback__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {} __go_post_callback__ (@var{h}, @var{name})
+@deftypefnx {} {} __go_post_callback__ (@var{h}, @var{name}, @var{param})
+Undocumented internal function.
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin < 2 || nargin > 3)
+    print_usage ();
+
+  const NDArray vals = args(0).xarray_value ("__go_post_callback__: invalid graphics object");
+
+  std::string name = args(1).xstring_value ("__go_post_callback__: invalid callback name");
+
+  for (octave_idx_type i = 0; i < vals.numel (); i++)
+    {
+      double val = vals(i);
+
+      graphics_handle h = gh_manager::lookup (val);
+
+      if (! h.ok ())
+        error ("__go_execute_callback__: invalid graphics object (= %g)", val);
+
+      if (nargin == 2)
+        gh_manager::post_callback (h, name);
+      else
+        gh_manager::post_callback (h, name, args(2));
+    }
+
+  return ovl ();
+}
+
 DEFUN (__image_pixel_size__, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{sz} =} __image_pixel_size__ (@var{h})
@@ -11617,6 +13002,32 @@
   return ovl (gtk_mgr.loaded_toolkits_list ());
 }
 
+DEFUN (__show_figure__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __show_figure__ (@var{n})
+Undocumented internal function.
+@end deftypefn */)
+{
+  if (args.length () != 1)
+    print_usage ();
+
+  double h = args(0).xdouble_value ("__show_figure__: invalid handle H");
+
+  graphics_handle gh = gh_manager::lookup (h);
+
+  if (! gh.ok ())
+    error ("__show_figure__: invalid graphics object (= %g)", h);
+
+  graphics_object go = gh_manager::get_object (gh);
+
+  figure::properties& fprops
+    = dynamic_cast<figure::properties&> (go.get_properties ());
+
+  fprops.get_toolkit ().show_figure (go);
+
+  return ovl ();
+}
+
 DEFUN (drawnow, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} drawnow ()
@@ -11634,7 +13045,11 @@
 @seealso{refresh}
 @end deftypefn */)
 {
-  static int drawnow_executing = 0;
+  // Disallow recursion when using gnuplot ASCII charts, i.e., with
+  // --no-window-system option.
+
+  static bool do_recursion = octave::display_info::display_available ();
+  static bool drawnow_executing = false;
 
   if (args.length () > 3)
     print_usage ();
@@ -11644,15 +13059,42 @@
   frame.protect_var (Vdrawnow_requested, false);
   frame.protect_var (drawnow_executing);
 
-  // Redraw, unless we are in the middle of an existing redraw or deletion.
-  if (++drawnow_executing <= 1 && ! delete_executing)
-    {
+  // Redraw unless we are in the middle of a deletion.
+
+  if (! delete_executing && (do_recursion || ! drawnow_executing))
+    {
+      drawnow_executing = true;
+
       gh_manager::auto_lock guard;
 
-      if (args.length () == 0 || args.length () == 1)
-        {
+      if (args.length () <= 1)
+        {
+          // First process events so that the redraw happens when all
+          // objects are in their definite state.
+          bool do_events = true;
+
+          if (args.length () == 1)
+            {
+              caseless_str val (args(0).xstring_value ("drawnow: first argument must be a string"));
+
+              if (val.compare ("expose"))
+                do_events = false;
+              else
+                error ("drawnow: invalid argument, 'expose' is only valid option");
+            }
+
+          if (do_events)
+            {
+              gh_manager::unlock ();
+
+              gh_manager::process_events ();
+
+              gh_manager::lock ();
+            }
+
           Matrix hlist = gh_manager::figure_handle_list (true);
 
+          // Redraw modified figures
           for (int i = 0; i < hlist.numel (); i++)
             {
               graphics_handle h = gh_manager::lookup (hlist(i));
@@ -11677,27 +13119,7 @@
                       fprops.set_modified (false);
                     }
                 }
-            }
-
-          bool do_events = true;
-
-          if (args.length () == 1)
-            {
-              caseless_str val (args(0).xstring_value ("drawnow: first argument must be a string"));
-
-              if (val.compare ("expose"))
-                do_events = false;
-              else
-                error ("drawnow: invalid argument, 'expose' is only valid option");
-            }
-
-          if (do_events)
-            {
-              gh_manager::unlock ();
-
-              gh_manager::process_events ();
-
-              gh_manager::lock ();
+
             }
         }
       else if (args.length () >= 2 && args.length () <= 3)
@@ -12149,7 +13571,8 @@
 call is pending at the top-level.
 
 In the first form, program execution is suspended until the graphics object
-@var{h} is destroyed.  If the graphics handle is invalid, the function
+@var{h} is destroyed.  If the graphics handle is invalid or if @var{h} is
+the root figure handle and no property @var{prop} was provided, the function
 returns immediately.
 
 In the second form, execution is suspended until the graphics object is
@@ -12185,6 +13608,9 @@
 
   double h = args(0).xdouble_value ("waitfor: invalid handle value");
 
+  if (! ishghandle (h) || (h == 0 && args.length () == 1))
+    return ovl ();
+
   caseless_str pname;
 
   octave::unwind_protect frame;
@@ -12356,7 +13782,7 @@
             break;
         }
 
-      octave_sleep (0.1); // FIXME: really needed?
+      octave::sleep (0.1);  // FIXME: really needed?
 
       octave_quit ();
 
--- a/libinterp/corefcn/graphics.in.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/graphics.in.h	Thu Dec 20 17:18:56 2018 -0500
@@ -1326,7 +1326,7 @@
   const std::string& current_value (void) const
   {
     if (current_type != radio_t)
-      error ("%s: property has no radio value");
+      error ("%s: property has no radio value", get_name ().c_str ());
 
     return current_val;
   }
@@ -2287,6 +2287,10 @@
     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;
+
   void set_modified (const octave_value& val) { set___modified__ (val); }
 
   void set___modified__ (const octave_value& val) { __modified__ = val; }
@@ -2320,7 +2324,7 @@
 
   static property_list::pval_map_type factory_defaults (void);
 
-  // FIXME: these functions should be generated automatically by the
+  // FIXME: These functions should be generated automatically by the
   //        genprops.awk script.
   //
   // EMIT_BASE_PROPERTIES_GET_FUNCTIONS
@@ -2374,7 +2378,7 @@
     string_property type frs , ty
     handle_property uicontextmenu u , graphics_handle ()
     any_property userdata , Matrix ()
-    bool_property visible , "on"
+    bool_property visible u , "on"
 
     // Octave-specific properties
     bool_property __modified__ hs , "on"
@@ -2383,6 +2387,8 @@
 
   virtual void update_handlevisibility (void);
 
+  virtual void update_visible (void) { };
+
 protected:
   struct cmp_caseless_str
   {
@@ -2809,7 +2815,7 @@
 
   operator bool (void) const { return rep->valid_object (); }
 
-  // FIXME: these functions should be generated automatically by the
+  // FIXME: These functions should be generated automatically by the
   //        genprops.awk script.
   //
   // EMIT_GRAPHICS_OBJECT_GET_FUNCTIONS
@@ -2857,6 +2863,8 @@
                                  listener_mode mode = POSTSET)
   { rep->delete_property_listener (nm, v, mode); }
 
+  void remove_all_listeners (void) { rep->remove_all_listeners (); }
+
   void initialize (void) { rep->initialize (*this); }
 
   void finalize (void) { rep->finalize (*this); }
@@ -2916,7 +2924,7 @@
       double_property screenpixelsperinch r , default_screenpixelsperinch ()
       array_property screensize r , default_screensize ()
       bool_property showhiddenhandles , "off"
-      radio_property units U , "inches|centimeters|normalized|points|{pixels}"
+      radio_property units U , "{pixels}|inches|centimeters|points|normalized|characters"
       // Hide base properties which don't make sense for root object
       //radio_property beingdeleted h , "{off}|on"
     END_PROPERTIES
@@ -3102,7 +3110,6 @@
 
     // 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 (figure)
@@ -3124,8 +3131,7 @@
       callback_property keyreleasefcn , Matrix ()
       radio_property menubar , "{figure}|none"
       string_property name , ""
-      // FIXME: Need RO property which returns current figure number.
-      // double_property number r ,
+      array_property number rG , Matrix ()
       radio_property nextplot , "{add}|new|replace|replacechildren"
       bool_property numbertitle , "on"
       array_property outerposition s , Matrix (1, 4, -1.0)
@@ -3143,8 +3149,8 @@
       radio_property renderer m , "{opengl}|painters"
       radio_property renderermode , "{auto}|manual"
       bool_property resize , "on"
-      // FIXME: resizefcn has been deprecated by Matlab, and
-      //        replaced with sizechangedfcn
+      // FIXME: "resizefcn" is no longer recommended by Matlab,
+      //        and has been replaced with "sizechangedfcn"
       //        Eventually this will need to be hidden, and then removed.
       callback_property resizefcn , Matrix ()
       radio_property selectiontype , "{normal}|extend|alt|open"
@@ -3178,10 +3184,11 @@
       any_property __plot_stream__ h , Matrix ()
       any_property __rotate_mode__ h , Matrix ()
       any_property __zoom_mode__ h , Matrix ()
+      double_property __device_pixel_ratio__ hU , 1.0
 
       // Obsolete properties: doublebuffer, mincolormap, wvisual, wvisualmode,
       //                      xdisplay, xvisual, xvisualmode
-      // FIXME: DEPRECATED: Remove in version 5.
+      // FIXME: DEPRECATED: Remove in version 6.
       bool_property doublebuffer hd , "on"
       double_property mincolormap hd , 64
       string_property wvisual hmd , ""
@@ -3196,6 +3203,7 @@
     {
       alphamap.add_constraint (dim_vector (-1, 1));
       colormap.add_constraint (dim_vector (-1, 3));
+      colormap.add_constraint (dim_vector (0, 0));
       outerposition.add_constraint (dim_vector (1, 4));
       outerposition.add_constraint (FINITE);
       paperposition.add_constraint (dim_vector (1, 4));
@@ -3401,6 +3409,8 @@
 
     void remove_child (const graphics_handle& h);
 
+    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; }
@@ -3522,8 +3532,14 @@
 
     void update_units (const caseless_str& old_units);
 
+    void update_font (std::string prop = "");
+
     void update_fontunits (const caseless_str& old_fontunits);
 
+    void increase_num_lights (void) { num_lights++; }
+    void decrease_num_lights (void) { num_lights--; }
+    unsigned int get_num_lights (void) const { return num_lights; }
+
   private:
 
     scaler sx = scaler ();
@@ -3581,6 +3597,8 @@
     bool zSign = false;
     bool nearhoriz = false;
 
+    unsigned int num_lights = 0;
+
     // Text renderer, used for calculation of text (tick labels) size
     octave::text_renderer txt_renderer;
 
@@ -3591,7 +3609,6 @@
 
     // 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)
@@ -3652,7 +3669,7 @@
       radio_property tickdir mu , "{in}|out"
       radio_property tickdirmode u , "{auto}|manual"
       // FIXME: Added recently to Matlab, should replace interpreter property.
-      radio_property ticklabelinterpreter , "{tex}|latex|none"
+      radio_property ticklabelinterpreter u , "{tex}|latex|none"
       array_property ticklength u , default_axes_ticklength ()
       array_property tightinset r , Matrix (1, 4, 0.0)
       handle_property title SOf , gh_manager::make_graphics_handle ("text", __myhandle__, false, false, false)
@@ -3661,8 +3678,7 @@
       // FIXME: uicontextmenu should be moved here.
       radio_property units SU , "{normalized}|inches|centimeters|points|pixels|characters"
       array_property view u , default_axes_view ()
-      // FIXME: DEPRECATED: Remove "zero" in version 5.
-      radio_property xaxislocation u , "{bottom}|top|origin|zero"
+      radio_property xaxislocation u , "{bottom}|top|origin"
       color_property xcolor mu , color_values (0.15, 0.15, 0.15)
       radio_property xcolormode , "{auto}|manual"
       radio_property xdir u , "{normal}|reverse"
@@ -3679,8 +3695,7 @@
       radio_property xticklabelmode u , "{auto}|manual"
       double_property xticklabelrotation , 0.0
       radio_property xtickmode u , "{auto}|manual"
-      // FIXME: DEPRECATED: Remove "zero" in version 5.
-      radio_property yaxislocation u , "{left}|right|origin|zero"
+      radio_property yaxislocation u , "{left}|right|origin"
       color_property ycolor mu , color_values (0.15, 0.15, 0.15)
       radio_property ycolormode , "{auto}|manual"
       radio_property ydir u , "{normal}|reverse"
@@ -3822,11 +3837,6 @@
     }
     void update_yaxislocation (void)
     {
-      // FIXME: DEPRECATED: Remove warning with "zero" in version 5.
-      if (yaxislocation_is ("zero"))
-        warning_with_id ("Octave:deprecated-property",
-                         "Setting 'yaxislocation' to 'zero' is deprecated, "
-                         "set to 'origin' instead.");
       sync_positions ();
       update_axes_layout ();
       if (xticklabelmode.is ("auto"))
@@ -3847,11 +3857,6 @@
     }
     void update_xaxislocation (void)
     {
-      // FIXME: DEPRECATED: Remove warning with "zero" in version 5.
-      if (xaxislocation_is ("zero"))
-        warning_with_id ("Octave:deprecated-property",
-                         "Setting 'xaxislocation' to 'zero' is deprecated, "
-                         "set to 'origin' instead.");
       sync_positions ();
       update_axes_layout ();
       if (xticklabelmode.is ("auto"))
@@ -3879,6 +3884,13 @@
     void update_tickdir (void) { update_ticklength (); }
     void update_tickdirmode (void) { update_ticklength (); }
 
+    void update_ticklabelinterpreter (void)
+    {
+      update_xtick ();
+      update_ytick ();
+      update_ztick ();
+    }
+    
     void update_xtick (void)
     {
       calc_ticks_and_lims (xlim, xtick, xminortickvalues, xlimmode.is ("auto"),
@@ -3956,7 +3968,6 @@
         calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
     }
 
-    void update_font (std::string prop = "");
     void update_fontname (void)
     {
       update_font ("fontname");
@@ -3996,85 +4007,9 @@
       sync_positions ();
     }
 
-    void update_outerposition (void)
-    {
-      set_activepositionproperty ("outerposition");
-      caseless_str old_units = get_units ();
-      set_units ("normalized");
-      Matrix outerbox = outerposition.get ().matrix_value ();
-      Matrix innerbox = position.get ().matrix_value ();
-      Matrix linset = looseinset.get ().matrix_value ();
-      Matrix tinset = tightinset.get ().matrix_value ();
-      outerbox(2) = outerbox(2) + outerbox(0);
-      outerbox(3) = outerbox(3) + outerbox(1);
-      innerbox(0) = outerbox(0) + std::max (linset(0), tinset(0));
-      innerbox(1) = outerbox(1) + std::max (linset(1), tinset(1));
-      innerbox(2) = outerbox(2) - std::max (linset(2), tinset(2));
-      innerbox(3) = outerbox(3) - std::max (linset(3), tinset(3));
-      innerbox(2) = innerbox(2) - innerbox(0);
-      innerbox(3) = innerbox(3) - innerbox(1);
-      position = innerbox;
-      set_units (old_units);
-      update_transform ();
-    }
-
-    void update_position (void)
-    {
-      set_activepositionproperty ("position");
-      caseless_str old_units = get_units ();
-      set_units ("normalized");
-      Matrix outerbox = outerposition.get ().matrix_value ();
-      Matrix innerbox = position.get ().matrix_value ();
-      Matrix linset = looseinset.get ().matrix_value ();
-      Matrix tinset = tightinset.get ().matrix_value ();
-      innerbox(2) = innerbox(2) + innerbox(0);
-      innerbox(3) = innerbox(3) + innerbox(1);
-      outerbox(0) = innerbox(0) - std::max (linset(0), tinset(0));
-      outerbox(1) = innerbox(1) - std::max (linset(1), tinset(1));
-      outerbox(2) = innerbox(2) + std::max (linset(2), tinset(2));
-      outerbox(3) = innerbox(3) + std::max (linset(3), tinset(3));
-      outerbox(2) = outerbox(2) - outerbox(0);
-      outerbox(3) = outerbox(3) - outerbox(1);
-      outerposition = outerbox;
-      set_units (old_units);
-      update_transform ();
-    }
-
-    void update_looseinset (void)
-    {
-      caseless_str old_units = get_units ();
-      set_units ("normalized");
-      Matrix innerbox = position.get ().matrix_value ();
-      innerbox(2) = innerbox(2) + innerbox(0);
-      innerbox(3) = innerbox(3) + innerbox(1);
-      Matrix outerbox = outerposition.get ().matrix_value ();
-      outerbox(2) = outerbox(2) + outerbox(0);
-      outerbox(3) = outerbox(3) + outerbox(1);
-      Matrix linset = looseinset.get ().matrix_value ();
-      Matrix tinset = tightinset.get ().matrix_value ();
-      if (activepositionproperty.is ("position"))
-        {
-          outerbox(0) = innerbox(0) - std::max (linset(0), tinset(0));
-          outerbox(1) = innerbox(1) - std::max (linset(1), tinset(1));
-          outerbox(2) = innerbox(2) + std::max (linset(2), tinset(2));
-          outerbox(3) = innerbox(3) + std::max (linset(3), tinset(3));
-          outerbox(2) = outerbox(2) - outerbox(0);
-          outerbox(3) = outerbox(3) - outerbox(1);
-          outerposition = outerbox;
-        }
-      else
-        {
-          innerbox(0) = outerbox(0) + std::max (linset(0), tinset(0));
-          innerbox(1) = outerbox(1) + std::max (linset(1), tinset(1));
-          innerbox(2) = outerbox(2) - std::max (linset(2), tinset(2));
-          innerbox(3) = outerbox(3) - std::max (linset(3), tinset(3));
-          innerbox(2) = innerbox(2) - innerbox(0);
-          innerbox(3) = innerbox(3) - innerbox(1);
-          position = innerbox;
-        }
-      set_units (old_units);
-      update_transform ();
-    }
+    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,
@@ -4188,6 +4123,8 @@
       update_axes_layout ();
     }
 
+    void trigger_normals_calc (void);
+
   };
 
 private:
@@ -4300,9 +4237,6 @@
     BEGIN_PROPERTIES (line)
       color_property color , color_property (color_values (0, 0, 0), radio_values ("none"))
       string_property displayname , ""
-      // FIXME: DEPRECATED: Remove erasemode property in version 5
-      // (rm all instances in file).
-      radio_property erasemode h , "{normal}|none|xor|background"
       // FIXME: DEPRECATED: Remove interpreter property in version 6.
       radio_property interpreter hd , "{tex}|none|latex"
       radio_property linejoin , "{round}|miter|chamfer"
@@ -4385,6 +4319,10 @@
   public:
     double get___fontsize_points__ (double box_pix_height = 0) const;
 
+    void update_text_extent (void);
+
+    void update_font (void);
+
     void set_position (const octave_value& val)
     {
       octave_value new_val (val);
@@ -4409,14 +4347,15 @@
 
     // 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 (text)
       color_property backgroundcolor , color_property (radio_values ("{none}"), color_values (1, 1, 1))
       color_property color u , color_values (0, 0, 0)
       color_property edgecolor , color_property (radio_values ("{none}"), color_values (0, 0, 0))
       bool_property editing , "off"
-      radio_property erasemode h , "{normal}|none|xor|background"
       array_property extent rG , Matrix (1, 4, 0.0)
+      // FIXME: DEPRECATED: Remove "oblique" in version 7.
       radio_property fontangle u , "{normal}|italic|oblique"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
@@ -4426,7 +4365,7 @@
       radio_property interpreter u , "{tex}|none|latex"
       radio_property linestyle , "{-}|--|:|-.|none"
       double_property linewidth , 0.5
-      double_property margin , 2
+      double_property margin , 3
       array_property position smu , Matrix (1, 3, 0.0)
       double_property rotation mu , 0
       text_label_property string u , ""
@@ -4494,15 +4433,12 @@
         set_zliminclude ("off");
     }
 
-    void update_text_extent (void);
-
     void request_autopos (void);
     void update_positionmode (void) { request_autopos (); }
     void update_rotationmode (void) { request_autopos (); }
     void update_horizontalalignmentmode (void) { request_autopos (); }
     void update_verticalalignmentmode (void) { request_autopos (); }
 
-    void update_font (void);
     void update_string (void) { request_autopos (); update_text_extent (); }
     void update_rotation (void) { update_text_extent (); }
     void update_color (void) { update_font (); update_text_extent (); }
@@ -4514,8 +4450,7 @@
     {
       update_font ();
       update_text_extent ();
-      // FIXME: DEPRECATED: Remove warning with demi and light in
-      // version 6.
+      // FIXME: DEPRECATED: Remove warning with demi and light in version 6.
       if (fontweight.is ("demi") || fontweight.is ("light"))
         warning_with_id ("Octave:deprecated-property",
                          "Setting 'fontweight' to '%s' is deprecated, \
@@ -4592,7 +4527,6 @@
       radio_property alphadatamapping al , "{none}|direct|scaled"
       array_property cdata u , default_image_cdata ()
       radio_property cdatamapping al , "scaled|{direct}"
-      radio_property erasemode h , "{normal}|none|xor|background"
       row_vector_property xdata mu , Matrix ()
       row_vector_property ydata mu , Matrix ()
       // hidden properties for limit computation
@@ -4624,9 +4558,9 @@
       cdata.add_constraint ("real");
       cdata.add_constraint (dim_vector (-1, -1));
       cdata.add_constraint (dim_vector (-1, -1, 3));
-      alphadata.add_constraint (dim_vector (-1, -1));
       alphadata.add_constraint ("double");
       alphadata.add_constraint ("uint8");
+      alphadata.add_constraint (dim_vector (-1, -1));
     }
 
   private:
@@ -4792,6 +4726,9 @@
     {
       position.add_constraint (dim_vector (1, 3));
     }
+
+  private:
+    void update_visible (void);
   };
 
 private:
@@ -4817,6 +4754,9 @@
       retval = base_properties::has_readonly_property (pname);
     return retval;
   }
+
+protected:
+  void initialize (const graphics_object& go);
 };
 
 // ---------------------------------------------------------------------
@@ -4847,6 +4787,10 @@
     std::string get_climinclude (void) const
     { return climinclude.current_value (); }
 
+    bool get_do_lighting (void) const;
+
+    std::list<std::list<octave_idx_type>> coplanar_last_idx;
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -4861,13 +4805,12 @@
       string_property displayname , ""
       double_radio_property edgealpha , double_radio_property (1.0, radio_values ("flat|interp"))
       color_property edgecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
-      radio_property edgelighting , "{none}|flat|gouraud|phong"
-      radio_property erasemode h , "{normal}|none|xor|background"
+      radio_property edgelighting u , "{none}|flat|gouraud|phong"
       double_radio_property facealpha , double_radio_property (1.0, radio_values ("flat|interp"))
       color_property facecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
-      radio_property facelighting , "none|{flat}|gouraud|phong"
+      radio_property facelighting u , "none|{flat}|gouraud|phong"
       array_property facenormals m , Matrix ()
-      radio_property facenormalsmode , "{auto}|manual"
+      radio_property facenormalsmode u , "{auto}|manual"
       array_property faces u , default_patch_faces ()
       array_property facevertexalphadata , Matrix ()
       array_property facevertexcdata u , Matrix ()
@@ -4879,12 +4822,11 @@
       color_property markeredgecolor , color_property (radio_values ("none|{auto}|flat"), color_values (0, 0, 0))
       color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
       double_property markersize , 6
-      radio_property normalmode hsg , "{auto}|manual"
       double_property specularcolorreflectance , 1.0
       double_property specularexponent , 10.0
       double_property specularstrength , 0.9
       array_property vertexnormals m , Matrix ()
-      radio_property vertexnormalsmode , "{auto}|manual"
+      radio_property vertexnormalsmode u , "{auto}|manual"
       array_property vertices u , default_patch_vertices ()
       array_property xdata u , default_patch_xdata ()
       array_property ydata u , default_patch_ydata ()
@@ -4916,7 +4858,9 @@
       cdata.add_constraint (dim_vector (-1, -1, 3));
       facevertexcdata.add_constraint (dim_vector (-1, 1));
       facevertexcdata.add_constraint (dim_vector (-1, 3));
+      facevertexcdata.add_constraint (dim_vector (0, 0));
       facevertexalphadata.add_constraint (dim_vector (-1, 1));
+      facevertexalphadata.add_constraint (dim_vector (0, 0));
       facenormals.add_constraint (dim_vector (-1, 3));
       facenormals.add_constraint (dim_vector (0, 0));
       vertexnormals.add_constraint (dim_vector (-1, 3));
@@ -4935,12 +4879,20 @@
       specularstrength.add_constraint ("max", 1.0, true);
     }
 
+  public:
+    void update_normals (bool reset, bool force = false)
+    {
+      update_face_normals (reset, force);
+      update_vertex_normals (reset, force);
+    }
+
+
   private:
     std::string bad_data_msg;
 
     void update_faces (void) { update_data ();}
 
-    void update_vertices (void)  { update_data ();}
+    void update_vertices (void) { update_data ();}
 
     void update_facevertexcdata (void) { update_data ();}
 
@@ -4959,7 +4911,10 @@
           set_faces (Matrix ());
         }
       else
-        update_fvc ();
+        {
+          update_fvc ();
+          update_normals (true);
+        }
 
       set_xlim (xdata.get_limits ());
     }
@@ -4974,7 +4929,10 @@
           set_faces (Matrix ());
         }
       else
-        update_fvc ();
+        {
+          update_fvc ();
+          update_normals (true);
+        }
 
       set_ylim (ydata.get_limits ());
     }
@@ -4982,12 +4940,14 @@
     void update_zdata (void)
     {
       update_fvc ();
+      update_normals (true);
       set_zlim (zdata.get_limits ());
     }
 
     void update_cdata (void)
     {
       update_fvc ();
+      update_normals (false);
 
       if (cdatamapping_is ("scaled"))
         set_clim (cdata.get_limits ());
@@ -4997,25 +4957,40 @@
 
     void update_data (void);
 
-    void set_normalmode (const octave_value& val)
+    void calc_face_normals (Matrix& normals);
+    void update_face_normals (bool reset, bool force = false);
+    void update_vertex_normals (bool reset, bool force = false);
+
+    void update_edgelighting (void)
     {
-      warning_with_id ("Octave:deprecated-property",
-        "patch: Property 'normalmode' is deprecated and will be removed "
-        "from a future version of Octave.  Use 'vertexnormalsmode' instead.");
-      set_vertexnormalsmode (val);
+      update_normals (false);
+    }
+
+    void update_facelighting (void)
+    {
+      update_normals (false);
     }
 
-    std::string get_normalmode (void) const
+    void update_facenormalsmode (void)
+    {
+      update_face_normals (false);
+    }
+
+    void update_vertexnormalsmode (void)
     {
-      warning_with_id ("Octave:deprecated-property",
-        "patch: Property 'normalmode' is deprecated and will be removed "
-        "from a future version of Octave.  Use 'vertexnormalsmode' instead.");
-      return vertexnormalsmode.current_value ();
+      update_vertex_normals (false);
+    }
+
+    void update_visible (void)
+    {
+      if (is_visible ())
+        update_normals (false);
     }
   };
 
 private:
   properties xproperties;
+  property_list default_properties;
 
 public:
   patch (const graphics_handle& mh, const graphics_handle& p)
@@ -5037,6 +5012,12 @@
       retval = base_properties::has_readonly_property (pname);
     return retval;
   }
+
+  void reset_default_properties (void);
+
+protected:
+  void initialize (const graphics_object& go);
+
 };
 
 // ---------------------------------------------------------------------
@@ -5059,6 +5040,8 @@
     std::string get_climinclude (void) const
     { return climinclude.current_value (); }
 
+    bool get_do_lighting (void) const;
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -5075,13 +5058,12 @@
       string_property displayname , ""
       double_radio_property edgealpha , double_radio_property (1.0, radio_values ("flat|interp"))
       color_property edgecolor , color_property (color_values (0, 0, 0), radio_values ("none|flat|interp"))
-      radio_property edgelighting , "{none}|flat|gouraud|phong"
-      radio_property erasemode h , "{normal}|none|xor|background"
+      radio_property edgelighting u , "{none}|flat|gouraud|phong"
       double_radio_property facealpha , double_radio_property (1.0, radio_values ("flat|interp|texturemap"))
       color_property facecolor , color_property (radio_values ("none|{flat}|interp|texturemap"), color_values (0, 0, 0))
-      radio_property facelighting , "none|{flat}|gouraud|phong"
+      radio_property facelighting u , "none|{flat}|gouraud|phong"
       array_property facenormals m , Matrix ()
-      radio_property facenormalsmode , "{auto}|manual"
+      radio_property facenormalsmode u , "{auto}|manual"
       // FIXME: DEPRECATED: Remove interpreter property in version 6.
       radio_property interpreter hd , "{tex}|none|latex"
       radio_property linestyle , "{-}|--|:|-.|none"
@@ -5091,7 +5073,6 @@
       color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
       double_property markersize , 6
       radio_property meshstyle , "{both}|row|column"
-      radio_property normalmode hsg , "{auto}|manual"
       double_property specularcolorreflectance , 1
       double_property specularexponent , 10
       double_property specularstrength , 0.9
@@ -5148,6 +5129,14 @@
       specularstrength.add_constraint ("max", 1.0, true);
     }
 
+  public:
+    void update_normals (bool reset, bool force = false)
+    {
+      update_face_normals (reset, force);
+      update_vertex_normals (reset, force);
+    }
+
+
   private:
     void update_alphadata (void)
     {
@@ -5167,42 +5156,43 @@
 
     void update_xdata (void)
     {
-      update_vertex_normals ();
+      update_normals (true);
       set_xlim (xdata.get_limits ());
     }
 
     void update_ydata (void)
     {
-      update_vertex_normals ();
+      update_normals (true);
       set_ylim (ydata.get_limits ());
     }
 
     void update_zdata (void)
     {
-      update_vertex_normals ();
+      update_normals (true);
       set_zlim (zdata.get_limits ());
     }
 
-    void update_vertex_normals (void);
+    void update_face_normals (bool reset, bool force = false);
+    void update_vertex_normals (bool reset, bool force = false);
+
+    void update_facenormalsmode (void)
+    { update_face_normals (false); }
 
     void update_vertexnormalsmode (void)
-    { update_vertex_normals (); }
-
-    void set_normalmode (const octave_value& val)
+    { update_vertex_normals (false); }
+
+    void update_edgelighting (void)
+    { update_normals (false); }
+
+    void update_facelighting (void)
+    { update_normals (false); }
+
+    void update_visible (void)
     {
-      warning_with_id ("Octave:deprecated-property",
-        "surface: Property 'normalmode' is deprecated and will be removed "
-        "from a future version of Octave.  Use 'vertexnormalsmode' instead.");
-      set_vertexnormalsmode (val);
+      if (is_visible ())
+        update_normals (false);
     }
 
-    std::string get_normalmode (void) const
-    {
-      warning_with_id ("Octave:deprecated-property",
-        "surface: Property 'normalmode' is deprecated and will be removed "
-        "from a future version of Octave.  Use 'vertexnormalsmode' instead.");
-      return vertexnormalsmode.current_value ();
-    }
   };
 
 private:
@@ -5238,18 +5228,9 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h)
-    {
-      base_properties::remove_child (h);
-      update_limits ();
-    }
-
-    void adopt (const graphics_handle& h)
-    {
-
-      base_properties::adopt (h);
-      update_limits (h);
-    }
+    void remove_child (const graphics_handle& h);
+
+    void adopt (const graphics_handle& h);
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5257,7 +5238,6 @@
 
     BEGIN_PROPERTIES (hggroup)
       string_property displayname , ""
-      radio_property erasemode h , "{normal}|none|xor|background"
 
       // hidden properties for limit computation
       row_vector_property alim hr , Matrix ()
@@ -5470,12 +5450,13 @@
     // Programming note: Keep property list sorted if new ones are added.
 
     BEGIN_PROPERTIES (uicontrol)
-      color_property backgroundcolor , color_values (1, 1, 1)
+      color_property backgroundcolor , color_values (0.94, 0.94, 0.94)
       callback_property callback , Matrix ()
       array_property cdata , Matrix ()
       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"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
@@ -5497,6 +5478,7 @@
       radio_property verticalalignment , "top|{middle}|bottom"
 
       // Octave-specific properties
+      bool_property __focus__ h , "off"
       any_property __object__ h , Matrix ()
     END_PROPERTIES
 
@@ -5508,7 +5490,9 @@
     {
       cdata.add_constraint ("double");
       cdata.add_constraint ("single");
+      cdata.add_constraint ("uint8");
       cdata.add_constraint (dim_vector (-1, -1, 3));
+      cdata.add_constraint (dim_vector (0, 0));
       position.add_constraint (dim_vector (1, 4));
       sliderstep.add_constraint (dim_vector (1, 2));
       fontsize.add_constraint ("min", 0.0, false);
@@ -5525,8 +5509,7 @@
     void update_fontweight (void)
     {
       update_text_extent ();
-      // FIXME: DEPRECATED: Remove warning with demi and light in
-      // version 6.
+      // FIXME: DEPRECATED: Remove warning with demi and light in version 6.
       if (fontweight.is ("demi") || fontweight.is ("light"))
         warning_with_id ("Octave:deprecated-property",
                          "Setting 'fontweight' to '%s' is deprecated, \
@@ -5582,10 +5565,11 @@
     // Programming note: Keep property list sorted if new ones are added.
 
     BEGIN_PROPERTIES (uibuttongroup)
-      color_property backgroundcolor , color_values (1, 1, 1)
+      color_property backgroundcolor , color_values (0.94, 0.94, 0.94)
       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"
       string_property fontname , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize , 10
@@ -5593,11 +5577,14 @@
       radio_property fontweight u , "light|{normal}|demi|bold"
       color_property foregroundcolor , color_values (0, 0, 0)
       color_property highlightcolor , color_values (1, 1, 1)
-      array_property position , default_panel_position ()
+      array_property position S , default_panel_position ()
+      // FIXME: "resizefcn" is no longer recommended by Matlab,
+      //        and has been replaced with "sizechangedfcn"
+      //        Eventually this will need to be hidden, and then removed.
       callback_property resizefcn , Matrix ()
       handle_property selectedobject S , graphics_handle ()
       callback_property selectionchangedfcn , Matrix ()
-      color_property shadowcolor , color_values (0, 0, 0)
+      color_property shadowcolor , color_values (0.7, 0.7, 0.7)
       callback_property sizechangedfcn , Matrix ()
       radio_property units S , "{normalized}|inches|centimeters|points|pixels|characters"
       string_property title , ""
@@ -5623,7 +5610,7 @@
 
     void update_fontweight (void)
     {
-      // FIXME: DEPRECATED: Remove this warning in version 6.
+      // FIXME: DEPRECATED: Remove warning with demi and light in version 6.
       if (fontweight.is ("demi") || fontweight.is ("light"))
         warning_with_id ("Octave:deprecated-property",
                          "Setting 'fontweight' to '%s' is deprecated, \
@@ -5679,9 +5666,10 @@
     // Programming note: Keep property list sorted if new ones are added.
 
     BEGIN_PROPERTIES (uipanel)
-      color_property backgroundcolor , color_values (1, 1, 1)
+      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"
       string_property fontname , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize , 10
@@ -5689,9 +5677,13 @@
       radio_property fontweight u , "light|{normal}|demi|bold"
       color_property foregroundcolor , color_values (0, 0, 0)
       color_property highlightcolor , color_values (1, 1, 1)
-      array_property position , default_panel_position ()
+      array_property position S , default_panel_position ()
+      // FIXME: "resizefcn" is no longer recommended by Matlab,
+      //        and has been replaced with "sizechangedfcn"
+      //        Eventually this will need to be hidden, and then removed.
       callback_property resizefcn , Matrix ()
-      color_property shadowcolor , color_values (0, 0, 0)
+      color_property shadowcolor , color_values (0.7, 0.7, 0.7)
+      callback_property sizechangedfcn , Matrix ()
       string_property title , ""
       radio_property titleposition , "{lefttop}|centertop|righttop|leftbottom|centerbottom|rightbottom"
       radio_property units S , "{normalized}|inches|centimeters|points|pixels|characters"
@@ -5712,7 +5704,7 @@
 
     void update_fontweight (void)
     {
-      // FIXME: DEPRECATED: Remove this warning in version 6.
+      // FIXME: DEPRECATED: Remove warning with demi and light in version 6.
       if (fontweight.is ("demi") || fontweight.is ("light"))
         warning_with_id ("Octave:deprecated-property",
                          "Setting 'fontweight' to '%s' is deprecated, \
@@ -5747,6 +5739,118 @@
 
 // ---------------------------------------------------------------------
 
+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;
+
+    // See the genprops.awk script for an explanation of the
+    // properties declarations.
+    // Programming note: Keep property list sorted if new ones are added.
+
+    // FIXME: keypressfcn, keyreleasefcn, rearrangeablecolumns properties
+    //        seem to have been removed from Matlab.
+
+    BEGIN_PROPERTIES (uitable)
+      any_property __object__ h , Matrix ()
+      array_property backgroundcolor , default_table_backgroundcolor ()
+      callback_property celleditcallback , Matrix ()
+      callback_property cellselectioncallback , Matrix ()
+      row_vector_property columneditable , Matrix ()
+      any_property columnformat S , Cell ()
+      any_property columnname , "numbered"
+      any_property columnwidth S , "auto"
+      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"
+      string_property fontname u , OCTAVE_DEFAULT_FONTNAME
+      double_property fontsize u , 10
+      radio_property fontunits S , "inches|centimeters|normalized|{points}|pixels"
+      radio_property fontweight u , "light|{normal}|demi|bold"
+      color_property foregroundcolor , color_values (0, 0, 0)
+      callback_property keypressfcn , Matrix ()
+      callback_property keyreleasefcn , Matrix ()
+      array_property position , default_table_position ()
+      bool_property rearrangeablecolumns , "off"
+      any_property rowname , "numbered"
+      bool_property rowstriping , "on"
+      string_property tooltipstring , ""
+      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);
+
+  protected:
+    void init (void)
+    {
+      position.add_constraint (dim_vector (1, 4));
+      extent.add_constraint (dim_vector (1, 4));
+      backgroundcolor.add_constraint ("double");
+      backgroundcolor.add_constraint (dim_vector (-1, 3));
+      columneditable.add_constraint ("logical");
+    }
+
+    void update_units (const caseless_str& old_units);
+    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 (); }
+    void update_fontsize (void) { update_table_extent (); }
+    void update_fontangle (void) { update_table_extent (); }
+
+    void update_fontweight (void)
+    {
+      // FIXME: DEPRECATED: Remove warning with demi and light in version 6.
+      if (fontweight.is ("demi") || fontweight.is ("light"))
+        warning_with_id ("Octave:deprecated-property",
+                         "Setting 'fontweight' to '%s' is deprecated, \
+use 'normal' or 'bold'.", fontweight.current_value ().c_str ());
+
+      update_table_extent ();
+    }
+  };
+
+private:
+  properties xproperties;
+
+public:
+  uitable (const graphics_handle& mh, const graphics_handle& p)
+    : base_graphics_object (), xproperties (mh, p)
+  { }
+
+  ~uitable (void) { }
+
+  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;
+  }
+};
+
+// ---------------------------------------------------------------------
+
 class OCTINTERP_API uitoolbar : public base_graphics_object
 {
 public:
@@ -5874,7 +5978,9 @@
     {
       cdata.add_constraint ("double");
       cdata.add_constraint ("single");
+      cdata.add_constraint ("uint8");
       cdata.add_constraint (dim_vector (-1, -1, 3));
+      cdata.add_constraint (dim_vector (0, 0));
     }
   };
 
@@ -5935,7 +6041,9 @@
     {
       cdata.add_constraint ("double");
       cdata.add_constraint ("single");
+      cdata.add_constraint ("uint8");
       cdata.add_constraint (dim_vector (-1, -1, 3));
+      cdata.add_constraint (dim_vector (0, 0));
     }
   };
 
@@ -5982,14 +6090,26 @@
 base_graphics_event
 {
 public:
+  enum priority { INTERRUPT, QUEUE, CANCEL };
 
   friend class graphics_event;
 
-  base_graphics_event (void) = default;
+  base_graphics_event (void)
+    : m_busyaction (QUEUE)
+  { };
+
+  base_graphics_event (int busyaction)
+    : m_busyaction (busyaction)
+  { };
 
   virtual ~base_graphics_event (void) = default;
 
+  int get_busyaction (void) { return m_busyaction; };
+
   virtual void execute (void) = 0;
+
+ private:
+  int m_busyaction;
 };
 
 class
@@ -6009,6 +6129,14 @@
 
   graphics_event& operator = (const graphics_event&) = default;
 
+  int get_busyaction (void)
+  {
+    if (ok ())
+      return rep->get_busyaction ();
+    else
+      error ("graphics_event::busyaction: invalid graphics_event");
+  }
+
   void execute (void)
   {
     if (ok ())
@@ -6020,12 +6148,14 @@
   static graphics_event
   create_callback_event (const graphics_handle& h,
                          const std::string& name,
-                         const octave_value& data = Matrix ());
+                         const octave_value& data = Matrix (),
+                         int busyaction = base_graphics_event::QUEUE);
 
   static graphics_event
   create_callback_event (const graphics_handle& h,
                          const octave_value& cb,
-                         const octave_value& data = Matrix ());
+                         const octave_value& data = Matrix (),
+                         int busyaction = base_graphics_event::QUEUE);
 
   static graphics_event
   create_function_event (event_fcn fcn, void *data = nullptr);
--- a/libinterp/corefcn/gripes.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,467 +0,0 @@
-/*
-
-Copyright (C) 1993-2018 John W. Eaton
-
-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/>.
-
-*/
-
-// FIXME: All gripe_XXX functions deprecated in 4.2.  Remove file in
-// version 5.
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include "defun.h"
-#include "error.h"
-#include "gripes.h"
-#include "ovl.h"
-#include "utils.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// Alphabetized list of gripes.
-////////////////////////////////////////////////////////////////////////////////
-
-void
-gripe_2_or_3_dim_plot (void)
-{
-  error ("plot: can only plot in 2 or 3 dimensions");
-}
-
-void
-gripe_data_conversion (const char *from, const char *to)
-{
-  error ("unable to convert from %s to %s format", from, to);
-}
-
-void
-gripe_data_file_in_path (const std::string& fcn, const std::string& file)
-{
-  warning_with_id ("Octave:data-file-in-path",
-                   "%s: '%s' found by searching load path",
-                   fcn.c_str (), file.c_str ());
-}
-
-void
-gripe_disabled_feature (const std::string& fcn, const std::string& feature,
-                        const std::string& pkg /*="Octave"*/)
-{
-  error ("%s: support for %s was unavailable or disabled when %s was built",
-         fcn.c_str (), feature.c_str (), pkg.c_str ());
-}
-
-void
-gripe_divide_by_zero (void)
-{
-  warning_with_id ("Octave:divide-by-zero", "division by zero");
-}
-
-void
-gripe_empty_arg (const char *name, bool is_error)
-{
-  if (is_error)
-    error ("%s: empty matrix is invalid as an argument", name);
-  else
-    warning ("%s: argument is empty matrix", name);
-}
-
-void
-gripe_implicit_conversion (const char *id, const char *from, const char *to)
-{
-  warning_with_id (id, "implicit conversion from %s to %s", from, to);
-}
-
-void
-gripe_implicit_conversion (const std::string& id,
-                           const std::string& from, const std::string& to)
-{
-  warning_with_id (id.c_str (),
-                   "implicit conversion from %s to %s",
-                   from.c_str (), to.c_str ());
-}
-
-void
-gripe_indexed_cs_list (void)
-{
-  error ("a cs-list cannot be further indexed");
-}
-
-void
-gripe_invalid_conversion (const std::string& from, const std::string& to)
-{
-  error ("invalid conversion from %s to %s", from.c_str (), to.c_str ());
-}
-
-void
-gripe_invalid_inquiry_subscript (void)
-{
-  error ("invalid dimension inquiry of a non-existent value");
-}
-
-void
-gripe_invalid_value_specified (const char *name)
-{
-  warning ("invalid value specified for '%s'", name);
-}
-
-void
-gripe_logical_conversion (void)
-{
-  warning_with_id ("Octave:logical-conversion",
-                   "value not equal to 1 or 0 converted to logical 1");
-}
-
-void
-gripe_nonbraced_cs_list_assignment (void)
-{
-  error ("invalid assignment to cs-list outside multiple assignment");
-}
-
-void
-gripe_nonconformant (void)
-{
-  error ("nonconformant matrices");
-}
-
-void
-gripe_nonconformant (octave_idx_type r1, octave_idx_type c1,
-                     octave_idx_type r2, octave_idx_type c2)
-{
-  error ("nonconformant matrices (op1 is %dx%d, op2 is %dx%d)",
-         r1, c1, r2, c2);
-}
-
-void
-gripe_not_implemented (const char *fcn)
-{
-  error ("%s: not implemented", fcn);
-}
-
-void
-gripe_not_supported (const char *fcn)
-{
-  error ("%s: not supported on this system", fcn);
-}
-
-void
-gripe_range_invalid (void)
-{
-  error ("range constant used in invalid context");
-}
-
-void
-gripe_square_matrix_required (const char *name)
-{
-  error ("%s: argument must be a square matrix", name);
-}
-
-void
-gripe_string_invalid (void)
-{
-  error ("std::string constant used in invalid context");
-}
-
-void
-gripe_unrecognized_data_fmt (const char *warn_for)
-{
-  error ("%s: unrecognized data format requested", warn_for);
-}
-
-void
-gripe_unrecognized_float_fmt (void)
-{
-  error ("unrecognized floating point format requested");
-}
-
-void
-gripe_user_returned_invalid (const char *name)
-{
-  error ("%s: user-supplied function returned invalid value", name);
-}
-
-void
-gripe_user_supplied_eval (const char *name)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_user_supplied_eval (e, name);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_user_supplied_eval (octave::execution_exception& e,
-                          const char *name)
-{
-  error (e, "%s: evaluation of user-supplied function failed", name);
-}
-
-void
-gripe_warn_complex_cmp (void)
-{
-  warning_with_id ("Octave:language-extension",
-                   "comparing complex numbers is not supported in Matlab");
-}
-
-void
-gripe_wrong_type_arg (const char *name, const char *s, bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, s, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const char *s, bool is_error)
-{
-  if (is_error)
-    error (e, "%s: wrong type argument '%s'", name, s);
-  else
-    warning ("%s: wrong type argument '%s'", name, s);
-}
-
-void
-gripe_wrong_type_arg (const char *name, const std::string& s, bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, s.c_str (), is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const std::string& s, bool is_error)
-{
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, s.c_str (), is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (const char *name, const octave_value& tc,
-                      bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, tc, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const octave_value& tc,
-                      bool is_error)
-{
-  std::string type = tc.type_name ();
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, type, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (const std::string& name, const octave_value& tc,
-                      bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name, tc, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const std::string& name, const octave_value& tc,
-                      bool is_error)
-{
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, name.c_str (), tc, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (const char *s, bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, s, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *s, bool is_error)
-{
-  if (is_error)
-    error (e, "wrong type argument '%s'", s);
-  else
-    warning ("wrong type argument '%s'", s);
-}
-
-void
-gripe_wrong_type_arg (const std::string& s, bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, s, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const std::string& s, bool is_error)
-{
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, s.c_str (), is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (const octave_value& tc, bool is_error)
-{
-  octave::execution_exception e;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, tc, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const octave_value& tc, bool is_error)
-{
-  std::string type = tc.type_name ();
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_wrong_type_arg (e, type, is_error);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_wrong_type_arg_for_binary_op (const octave_value& op)
-{
-  std::string type = op.type_name ();
-  error ("invalid operand '%s' for binary operator", type.c_str ());
-}
-
-void
-gripe_wrong_type_arg_for_unary_op (const octave_value& op)
-{
-  std::string type = op.type_name ();
-  error ("invalid operand '%s' for unary operator", type.c_str ());
-}
--- a/libinterp/corefcn/gripes.h	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/*
-
-Copyright (C) 1993-2018 John W. Eaton
-
-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/>.
-
-*/
-
-// FIXME: All gripe_XXX functions deprecated in 4.2.  Remove file in
-// version 5.
-
-#if ! defined (octave_gripes_h)
-#define octave_gripes_h 1
-
-#include "octave-config.h"
-
-#include <string>
-
-#include "lo-array-gripes.h"
-
-class octave_value;
-namespace octave
-{
-  class execution_exception;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Alphabetized list of gripes.
-////////////////////////////////////////////////////////////////////////////////
-
-OCTAVE_DEPRECATED (4.2, "use 'err_2_or_3_dim_plot' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_2_or_3_dim_plot (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_data_conversion' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_data_conversion (const char *from, const char *to);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_data_file_in_path' instead")
-OCTINTERP_API extern void
-gripe_data_file_in_path (const std::string& fcn, const std::string& file);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_disabled_feature' or 'warn_disabled_feature' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_disabled_feature (const std::string& fcn,
-                        const std::string& feature,
-                        const std::string& pkg="Octave");
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_divide_by_zero' instead")
-OCTINTERP_API extern void
-gripe_divide_by_zero (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_empty_arg' instead")
-OCTINTERP_API extern void
-gripe_empty_arg (const char *name, bool is_error);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_implicit_conversion' instead")
-OCTINTERP_API extern void
-gripe_implicit_conversion (const char *id, const char *from, const char *to);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_implicit_conversion' instead")
-OCTINTERP_API extern void
-gripe_implicit_conversion (const std::string& id, const std::string& from,
-                           const std::string& to);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_indexed_cs_list' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_indexed_cs_list (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_invalid_conversion' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_invalid_conversion (const std::string& from, const std::string& to);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_invalid_inquiry_subscript' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_invalid_inquiry_subscript (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_invalid_value_specified' instead")
-OCTINTERP_API extern void
-gripe_invalid_value_specified (const char *name);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_logical_conversion' instead")
-OCTINTERP_API extern void
-gripe_logical_conversion (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_nonbraced_cs_list_assignment' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_nonbraced_cs_list_assignment (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_nonconformant' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_nonconformant (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_nonconformant' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_nonconformant (octave_idx_type r1, octave_idx_type c1,
-                     octave_idx_type r2, octave_idx_type c2);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_not_implemented' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_not_implemented (const char *);
-
-// FIXME: DEPRECATED: Deprecated in 4.2, remove in 5.0
-OCTAVE_DEPRECATED (4.2, "use 'err_disabled_feature' or 'warn_disabled_feature' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_not_supported (const char *);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_range_invalid' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_range_invalid (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_square_matrix_required' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_square_matrix_required (const char *name);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_string_invalid' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_string_invalid (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_unrecognized_data_fmt' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_unrecognized_data_fmt (const char *warn_for);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_unrecognized_float_fmt' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_unrecognized_float_fmt (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_user_returned_invalid' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_user_returned_invalid (const char *name);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_user_supplied_eval' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_user_supplied_eval (const char *name);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_user_supplied_eval' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_user_supplied_eval (octave::execution_exception& e, const char *name);
-
-OCTAVE_DEPRECATED (4.2, "use 'warn_complex_cmp' instead")
-OCTINTERP_API extern void
-gripe_warn_complex_cmp (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const char *name, const char *s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const char *s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const char *name, const std::string& s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const std::string& s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' or 'warn_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const char *name, const octave_value& tc,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const char *name, const octave_value& tc,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const std::string& name, const octave_value& tc,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e,
-                      const std::string& name, const octave_value& tc,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const char *s, bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e, const char *s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const std::string& s, bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e, const std::string& s,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (const octave_value& tc, bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg' instead")
-OCTINTERP_API extern void
-gripe_wrong_type_arg (octave::execution_exception& e, const octave_value& tc,
-                      bool is_error = true);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg_for_binary_op' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_wrong_type_arg_for_binary_op (const octave_value& op);
-
-OCTAVE_DEPRECATED (4.2, "use 'err_wrong_type_arg_for_unary_op' instead")
-OCTAVE_NORETURN OCTINTERP_API extern void
-gripe_wrong_type_arg_for_unary_op (const octave_value& op);
-
-#endif
--- a/libinterp/corefcn/gsvd.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gsvd.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -180,29 +180,29 @@
         {
           if (argA.is_single_type () || argB.is_single_type ())
             {
-              retval(0) = float_identity_matrix (nc, nc);
-              retval(1) = float_identity_matrix (nc, nc);
+              retval(0) = octave::float_identity_matrix (nc, nc);
+              retval(1) = octave::float_identity_matrix (nc, nc);
               if (nargout > 2)
-                retval(2) = float_identity_matrix (nr, nr);
+                retval(2) = octave::float_identity_matrix (nr, nr);
               if (nargout > 3)
                 retval(3) = FloatMatrix (nr, nc);
               if (nargout > 4)
-                retval(4) = float_identity_matrix (nr, nr);
+                retval(4) = octave::float_identity_matrix (nr, nr);
               if (nargout > 5)
-                retval(5) = float_identity_matrix (nr, nr);
+                retval(5) = octave::float_identity_matrix (nr, nr);
             }
           else
             {
-              retval(0) = identity_matrix (nc, nc);
-              retval(1) = identity_matrix (nc, nc);
+              retval(0) = octave::identity_matrix (nc, nc);
+              retval(1) = octave::identity_matrix (nc, nc);
               if (nargout > 2)
-                retval(2) = identity_matrix (nr, nr);
+                retval(2) = octave::identity_matrix (nr, nr);
               if (nargout > 3)
                 retval(3) = Matrix (nr, nc);
               if (nargout > 4)
-                retval(4) = identity_matrix (nr, nr);
+                retval(4) = octave::identity_matrix (nr, nr);
               if (nargout > 5)
-                retval(5) = identity_matrix (nr, nr);
+                retval(5) = octave::identity_matrix (nr, nr);
             }
         }
     }
--- a/libinterp/corefcn/gtk-manager.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gtk-manager.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -52,7 +52,7 @@
 
         octave_value_list args;
         args(0) = dtk;
-        octave::feval ("graphics_toolkit", args);
+        feval ("graphics_toolkit", args);
 
         pl = loaded_toolkits.find (dtk);
 
@@ -89,18 +89,18 @@
           dtk.clear ();
         else
           {
-            const_available_toolkits_iterator pa = available_toolkits.begin ();
+            auto pa = available_toolkits.cbegin ();
 
             dtk = *pa++;
 
-            while (pa != available_toolkits.end ())
+            while (pa != available_toolkits.cend ())
               {
                 std::string tk_name = *pa++;
 
                 if (tk_name == "qt"
                     || (tk_name == "fltk"
                         && (available_toolkits.find ("qt")
-                            == available_toolkits.end ())))
+                            == available_toolkits.cend ())))
                   dtk = tk_name;
               }
           }
--- a/libinterp/corefcn/gtk-manager.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/gtk-manager.h	Thu Dec 20 17:18:56 2018 -0500
@@ -97,7 +97,7 @@
     {
       while (! loaded_toolkits.empty ())
         {
-          loaded_toolkits_iterator p = loaded_toolkits.begin ();
+          auto p = loaded_toolkits.begin ();
 
           std::string name = p->first;
 
--- a/libinterp/corefcn/help.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/help.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,7 +29,7 @@
 
 #include <algorithm>
 #include <fstream>
-#include <iostream>
+#include <istream>
 #include <map>
 #include <sstream>
 #include <string>
@@ -37,6 +37,7 @@
 #include "cmd-edit.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
 #include "str-vec.h"
@@ -61,7 +62,6 @@
 #include "parse.h"
 #include "pathsearch.h"
 #include "procstream.h"
-#include "pt-pr-code.h"
 #include "quit.h"
 #include "sighandlers.h"
 #include "symtab.h"
@@ -554,7 +554,7 @@
   {
     bool retval = false;
 
-    h = octave::get_help_from_file (nm, symbol_found, file);
+    h = get_help_from_file (nm, symbol_found, file);
 
     if (h.length () > 0)
       retval = true;
@@ -582,7 +582,10 @@
 
     if (! initialized)
       {
-        std::ifstream file (m_built_in_docstrings_file.c_str (),
+        std::string ascii_fname
+          = octave::sys::get_ASCII_filename (m_built_in_docstrings_file);
+
+        std::ifstream file (ascii_fname.c_str (),
                             std::ios::in | std::ios::binary);
 
         if (! file)
@@ -665,7 +668,10 @@
         std::streampos beg = txt_limits.first;
         std::streamoff len = txt_limits.second;
 
-        std::ifstream file (m_built_in_docstrings_file.c_str (),
+        std::string ascii_fname
+          = octave::sys::get_ASCII_filename (m_built_in_docstrings_file);
+
+        std::ifstream file (ascii_fname.c_str (),
                             std::ios::in | std::ios::binary);
 
         if (! file)
@@ -693,8 +699,7 @@
 
   string_vector make_name_list (void)
   {
-    octave::help_system& help_sys
-      = octave::__get_help_system__ ("make_name_list");
+    help_system& help_sys = __get_help_system__ ("make_name_list");
 
     return help_sys.make_name_list ();
   }
--- a/libinterp/corefcn/hex2num.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/hex2num.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -68,7 +68,7 @@
   const size_t nchars = 2 * nbytes;
 
   if (nc > nchars)
-    error ("hex2num: S must be no more than %d characters", nchars);
+    error ("hex2num: S must be no more than %zd characters", nchars);
 
   size_t j = 0;
 
--- a/libinterp/corefcn/hook-fcn.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/hook-fcn.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,6 +25,7 @@
 #endif
 
 #include "hook-fcn.h"
+#include "parse.h"
 
 hook_function::hook_function (const octave_value& f, const octave_value& d)
 {
@@ -41,3 +42,24 @@
   else
     error ("invalid hook function");
 }
+
+void named_hook_function::eval (const octave_value_list& initial_args)
+{
+  octave_value_list args = initial_args;
+
+  if (data.is_defined ())
+    args.append (data);
+
+  octave::feval (name, args, 0);
+}
+
+void fcn_handle_hook_function::eval (const octave_value_list& initial_args)
+{
+  octave_value_list args = initial_args;
+
+  if (data.is_defined ())
+    args.append (data);
+
+  octave::feval (fcn_handle, args, 0);
+}
+
--- a/libinterp/corefcn/hook-fcn.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/hook-fcn.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,7 +30,6 @@
 #include "ovl.h"
 #include "ov.h"
 #include "ov-fcn-handle.h"
-#include "parse.h"
 #include "variables.h"
 
 class
@@ -46,9 +45,9 @@
 
   virtual ~base_hook_function (void) = default;
 
-  virtual std::string id (void) { return ""; }
+  virtual std::string id (void) const { return ""; }
 
-  virtual bool is_valid (void) { return false; }
+  virtual bool is_valid (void) const { return false; }
 
   virtual void eval (const octave_value_list&) { }
 
@@ -98,9 +97,9 @@
     return *this;
   }
 
-  std::string id (void) { return rep->id (); }
+  std::string id (void) const { return rep->id (); }
 
-  bool is_valid (void) { return rep->is_valid (); }
+  bool is_valid (void) const { return rep->is_valid (); }
 
   void eval (const octave_value_list& initial_args)
   {
@@ -121,19 +120,11 @@
     : name (n), data (d)
   { }
 
-  void eval (const octave_value_list& initial_args)
-  {
-    octave_value_list args = initial_args;
-
-    if (data.is_defined ())
-      args.append (data);
+  void eval (const octave_value_list& initial_args);
 
-    octave::feval (name, args, 0);
-  }
+  std::string id (void) const { return name; }
 
-  std::string id (void) { return name; }
-
-  bool is_valid (void) { return is_valid_function (name); }
+  bool is_valid (void) const { return is_valid_function (name); }
 
 private:
 
@@ -162,19 +153,11 @@
       }
   }
 
-  void eval (const octave_value_list& initial_args)
-  {
-    octave_value_list args = initial_args;
-
-    if (data.is_defined ())
-      args.append (data);
+  void eval (const octave_value_list& initial_args);
 
-    octave::feval (fcn_handle, args, 0);
-  }
+  std::string id (void) const { return ident; }
 
-  std::string id (void) { return ident; }
-
-  bool is_valid (void) { return valid; }
+  bool is_valid (void) const { return valid; }
 
 private:
 
@@ -240,14 +223,14 @@
 
   void run (const octave_value_list& initial_args = octave_value_list ())
   {
-    iterator p = fcn_map.begin ();
+    auto p = fcn_map.begin ();
 
     while (p != fcn_map.end ())
       {
         std::string hook_fcn_id = p->first;
         hook_function hook_fcn = p->second;
 
-        iterator q = p++;
+        auto q = p++;
 
         if (hook_fcn.is_valid ())
           hook_fcn.eval (initial_args);
--- a/libinterp/corefcn/input.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/input.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -37,10 +37,12 @@
 
 #include "cmd-edit.h"
 #include "file-ops.h"
+#include "iconv-wrappers.h"
+#include "localcharset-wrapper.h"
 #include "quit.h"
 #include "str-vec.h"
+#include "uniconv-wrappers.h"
 
-#include "bp-table.h"
 #include "builtin-defun-decls.h"
 #include "call-stack.h"
 #include "defun.h"
@@ -74,18 +76,9 @@
 #include "utils.h"
 #include "variables.h"
 
-// Primary prompt string.
-static std::string VPS1;
-
-// Secondary prompt string.
-static std::string VPS2;
-
 // The time we last printed a prompt.
 octave::sys::time Vlast_prompt_time = 0.0;
 
-// Character to append after successful command-line completion attempts.
-static char Vcompletion_append_char = ' ';
-
 // TRUE after a call to completion_matches.
 bool octave_completion_matches_called = false;
 
@@ -101,92 +94,807 @@
 // the terminal.
 bool Vtrack_line_num = true;
 
-// If we are in debugging mode, this is the last command entered, so
-// that we can repeat the previous command if the user just types RET.
-static std::string last_debugging_command = "\n";
+static std::string
+quoting_filename (const std::string& text, int, char quote)
+{
+  if (quote)
+    return text;
+  else
+    return ("'" + text);
+}
 
-// TRUE if we are running in the Emacs GUD mode.
-static bool Vgud_mode = false;
+// Try to parse a partial command line in reverse, excluding trailing TEXT.
+// If it appears a variable has been indexed by () or {},
+// return that expression,
+// to allow autocomplete of field names of arrays of structures.
+static std::string
+find_indexed_expression (const std::string& text)
+{
+  std::string line = octave::command_editor::get_line_buffer ();
+
+  int pos = line.length () - text.length ();
+  int curly_count = 0;
+  int paren_count = 0;
+
+  int last = --pos;
+
+  while (pos >= 0 && (line[pos] == ')' || line[pos] == '}'))
+    {
+      if (line[pos] == ')')
+        paren_count++;
+      else if (line[pos] == '}')
+        curly_count++;
 
-static hook_function_list input_event_hook_functions;
+      while (curly_count + paren_count > 0 && --pos >= 0)
+        {
+          if (line[pos] == ')')
+            paren_count++;
+          else if (line[pos] == '(')
+            paren_count--;
+          else if (line[pos] == '}')
+            curly_count++;
+          else if (line[pos] == '{')
+            curly_count--;
+        }
+
+      while (--pos >= 0 && line[pos] == ' ')
+        ;
+    }
+
+  while (pos >= 0 && (isalnum (line[pos]) || line[pos] == '_'))
+    pos--;
 
-// For octave_quit.
-void
-remove_input_event_hook_functions (void)
+  if (++pos >= 0)
+    return (line.substr (pos, last + 1 - pos));
+  else
+    return std::string ();
+}
+
+static inline bool
+is_variable (octave::symbol_table& symtab, const std::string& name)
 {
-  input_event_hook_functions.clear ();
+  bool retval = false;
+
+  if (! name.empty ())
+    {
+      octave::symbol_scope scope = symtab.current_scope ();
+
+      octave_value val = scope ? scope.varval (name) : octave_value ();
+
+      retval = val.is_defined ();
+    }
+
+  return retval;
 }
 
-void
-set_default_prompts (void)
+static string_vector
+generate_struct_completions (const std::string& text,
+                             std::string& prefix, std::string& hint)
 {
-  // Use literal "octave" instead of "\\s" to avoid setting the prompt
-  // to "octave.exe" or "octave-gui", etc.
+  string_vector names;
+
+  size_t pos = text.rfind ('.');
+  bool array = false;
+
+  if (pos != std::string::npos)
+    {
+      if (pos == text.length ())
+        hint = "";
+      else
+        hint = text.substr (pos+1);
+
+      prefix = text.substr (0, pos);
+
+      if (prefix == "")
+        {
+          array = true;
+          prefix = find_indexed_expression (text);
+        }
+
+      std::string base_name = prefix;
+
+      pos = base_name.find_first_of ("{(. ");
+
+      if (pos != std::string::npos)
+        base_name = base_name.substr (0, pos);
+
+      octave::interpreter& interp
+        = octave::__get_interpreter__ ("generate_struct_completions");
+
+      octave::symbol_table& symtab = interp.get_symbol_table ();
+
+      if (is_variable (symtab, base_name))
+        {
+          int parse_status;
+
+          octave::unwind_protect frame;
+
+          frame.protect_var (discard_error_messages);
+          frame.protect_var (discard_warning_messages);
+
+          discard_error_messages = true;
+          discard_warning_messages = true;
+
+          try
+            {
+              octave_value tmp
+                = interp.eval_string (prefix, true, parse_status);
+
+              frame.run ();
+
+              if (tmp.is_defined ()
+                  && (tmp.isstruct () || tmp.isjava () || tmp.is_classdef_object ()))
+                names = tmp.map_keys ();
+            }
+          catch (const octave::execution_exception&)
+            {
+              octave::interpreter::recover_from_exception ();
+            }
+        }
+    }
 
-  VPS1 = R"(octave:\#> )";
-  VPS2 = "> ";
-  std::string VPS4 = "+ ";
+  // Undo look-back that found the array expression,
+  // but insert an extra "." to distinguish from the non-struct case.
+  if (array)
+    prefix = ".";
+
+  return names;
+}
+
+// FIXME: this will have to be much smarter to work "correctly".
+static bool
+looks_like_struct (const std::string& text, char prev_char)
+{
+  bool retval = (! text.empty ()
+                 && (text != "." || prev_char == ')' || prev_char == '}')
+                 && text.find_first_of (octave::sys::file_ops::dir_sep_chars ()) == std::string::npos
+                 && text.find ("..") == std::string::npos
+                 && text.rfind ('.') != std::string::npos);
+
+  return retval;
+}
+
+// FIXME: make this generate filenames when appropriate.
+
+static string_vector
+generate_possible_completions (const std::string& text, std::string& prefix,
+                               std::string& hint, bool& deemed_struct)
+{
+  string_vector names;
+
+  prefix = "";
+
+  char prev_char = octave::command_editor::get_prev_char (text.length ());
+  deemed_struct = looks_like_struct (text, prev_char);
 
-  octave_link::set_default_prompts (VPS1, VPS2, VPS4);
+  if (deemed_struct)
+    names = generate_struct_completions (text, prefix, hint);
+  else
+    names = octave::make_name_list ();
+
+  // Sort and remove duplicates.
+
+  names.sort (true);
+
+  return names;
+}
+
+static bool
+is_completing_dirfns (void)
+{
+  static std::string dirfns_commands[] = {"cd", "isfile", "isfolder", "ls"};
+  static const size_t dirfns_commands_length = 4;
+
+  bool retval = false;
+
+  std::string line = octave::command_editor::get_line_buffer ();
+
+  for (size_t i = 0; i < dirfns_commands_length; i++)
+    {
+      int index = line.find (dirfns_commands[i] + ' ');
+
+      if (index == 0)
+        {
+          retval = true;
+          break;
+        }
+    }
+
+  return retval;
 }
 
 static std::string
-gnu_readline (const std::string& s, bool& eof)
+generate_completion (const std::string& text, int state)
 {
-  octave_quit ();
+  std::string retval;
+
+  static std::string prefix;
+  static std::string hint;
+
+  static size_t hint_len = 0;
+
+  static int list_index = 0;
+  static int name_list_len = 0;
+  static int name_list_total_len = 0;
+  static string_vector name_list;
+  static string_vector file_name_list;
+
+  static int matches = 0;
+
+  if (state == 0)
+    {
+      list_index = 0;
+
+      prefix = "";
+
+      hint = text;
+
+      // No reason to display symbols while completing a
+      // file/directory operation.
+
+      bool deemed_struct = false;
+
+      if (is_completing_dirfns ())
+        name_list = string_vector ();
+      else
+        name_list = generate_possible_completions (text, prefix, hint,
+                                                   deemed_struct);
+
+      name_list_len = name_list.numel ();
+
+      // If the line was something like "a{1}." then text = "." but
+      // we don't want to expand all the . files.
+      if (! deemed_struct)
+        {
+
+          file_name_list = octave::command_editor::generate_filename_completions (text);
+
+          name_list.append (file_name_list);
+
+        }
 
-  eof = false;
+      name_list_total_len = name_list.numel ();
+
+      hint_len = hint.length ();
+
+      matches = 0;
+
+      for (int i = 0; i < name_list_len; i++)
+        if (hint == name_list[i].substr (0, hint_len))
+          matches++;
+    }
+
+  if (name_list_total_len > 0 && matches > 0)
+    {
+      while (list_index < name_list_total_len)
+        {
+          std::string name = name_list[list_index];
+
+          list_index++;
 
-  std::string retval = octave::command_editor::readline (s, eof);
+          if (hint == name.substr (0, hint_len))
+            {
+              // Special case: array reference forces prefix="."
+              //               in generate_struct_completions ()
+              if (list_index <= name_list_len && ! prefix.empty ())
+                retval = (prefix == "." ? "" : prefix) + '.' + name;
+              else
+                retval = name;
+
+              char prev_char = octave::command_editor::get_prev_char
+                                                       (text.length ());
+              if (matches == 1 && looks_like_struct (retval, prev_char))
+                {
+                  // Don't append anything, since we don't know
+                  // whether it should be '(' or '.'.
 
-  if (! eof && retval.empty ())
-    retval = "\n";
+                  octave::command_editor::set_completion_append_character ('\0');
+                }
+              else
+                {
+                  octave::input_system& input_sys
+                    = octave::__get_input_system__ ("generate_completion");
+
+                  octave::command_editor::set_completion_append_character
+                    (input_sys.completion_append_char ());
+                }
+
+              break;
+            }
+        }
+    }
 
   return retval;
 }
 
-static inline std::string
-interactive_input (const std::string& s, bool& eof)
+namespace octave
 {
-  Vlast_prompt_time.stamp ();
+  // Use literal "octave" in default setting for PS1 instead of
+  // "\\s" to avoid setting the prompt to "octave.exe" or
+  // "octave-gui", etc.
 
-  if (Vdrawnow_requested && octave::application::interactive ())
+  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 ("utf-8"), m_last_debugging_command ("\n"),
+      m_input_event_hook_functions ()
+  {
+#if defined (OCTAVE_USE_WINDOWS_API)
+    m_mfile_encoding = "system";
+#endif
+  }
+
+    void input_system::initialize (bool line_editing)
     {
-      bool eval_error = false;
-
-      try
+// Force default line editor if we don't want readline editing.
+      if (! line_editing)
         {
-          Fdrawnow ();
-        }
-      catch (const octave::execution_exception& e)
-        {
-          eval_error = true;
-
-          std::string stack_trace = e.info ();
-
-          if (! stack_trace.empty ())
-            std::cerr << stack_trace;
-
-          if (octave::application::interactive ())
-            octave::interpreter::recover_from_exception ();
+          command_editor::force_default_editor ();
+          return;
         }
 
-      octave::flush_stdout ();
+      // If we are using readline, this allows conditional parsing of the
+      // .inputrc file.
+
+      octave::command_editor::set_name ("Octave");
+
+      // FIXME: this needs to include a comma too, but that
+      // causes trouble for the new struct element completion code.
+
+      static const char *s = "\t\n !\"\'*+-/:;<=>(){}[\\]^`~";
+
+      octave::command_editor::set_basic_word_break_characters (s);
+
+      octave::command_editor::set_completer_word_break_characters (s);
+
+      octave::command_editor::set_basic_quote_characters (R"(")");
+
+      octave::command_editor::set_filename_quote_characters (" \t\n\\\"'@<>=;|&()#$`?*[!:{");
+
+      octave::command_editor::set_completer_quote_characters (R"('")");
+
+      octave::command_editor::set_completion_function (generate_completion);
+
+      octave::command_editor::set_quoting_function (quoting_filename);
+  }
+
+  octave_value
+  input_system::PS1 (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_PS1, args, nargout, "PS1");
+  }
+
+  octave_value
+  input_system::PS2 (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_PS2, args, nargout, "PS2");
+  }
+
+  octave_value
+  input_system::completion_append_char (const octave_value_list& args,
+                                        int nargout)
+  {
+    return set_internal_variable (m_completion_append_char, args, nargout,
+                                  "completion_append_char");
+  }
+
+  octave_value
+  input_system::gud_mode (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_gud_mode, args, nargout, "__gud_mode__");
+  }
+
+  octave_value
+  input_system::mfile_encoding (const octave_value_list& args, int nargout)
+  {
+    // Save current value in case there is an error in the additional
+    // validation below.
+
+    std::string saved_encoding = m_mfile_encoding;
+
+    // We must pass the actual variable to change here for temporary
+    // "local" settings to work properly.
+
+    octave_value retval
+      = set_internal_variable (m_mfile_encoding, args, nargout,
+                               "__mfile_encoding__");
+
+    // Additional validation if the encoding has changed.
+
+    if (m_mfile_encoding != saved_encoding)
+      {
+        if (m_mfile_encoding.empty ())
+          {
+#if defined (OCTAVE_USE_WINDOWS_API)
+            m_mfile_encoding = "system";
+#else
+            m_mfile_encoding = "utf-8";
+#endif
+          }
+        else
+          {
+            std::transform (m_mfile_encoding.begin (),
+                            m_mfile_encoding.end (),
+                            m_mfile_encoding.begin (), ::tolower);
+
+            std::string codepage = (m_mfile_encoding.compare ("system") == 0)
+              ? octave_locale_charset_wrapper () : m_mfile_encoding;
+
+            // Check for valid codepage.
+            void *codec
+              = octave_iconv_open_wrapper (codepage.c_str (), "utf-8");
+
+            if (errno == EINVAL)
+              {
+                m_mfile_encoding = saved_encoding;
+
+                error ("__mfile_encoding__: conversion from codepage '%s' not supported",
+                       codepage.c_str ());
+              }
+
+            octave_iconv_close_wrapper (codec);
+          }
+
+      }
+
+    // Synchronize the related gui preference for editor encoding
+    octave::feval ("__octave_link_gui_preference__",
+                   ovl ("editor/default_encoding", m_mfile_encoding));
+
+    return retval;
+  }
 
-      // We set Vdrawnow_requested to false even if there is an error in
-      // drawnow so that the error doesn't reappear at every prompt.
+  bool input_system::yes_or_no (const std::string& prompt)
+  {
+    std::string prompt_string = prompt + "(yes or no) ";
+
+    while (1)
+      {
+        bool eof = false;
+
+        std::string input_buf = interactive_input (prompt_string, eof);
+
+        if (input_buf == "yes")
+          return true;
+        else if (input_buf == "no")
+          return false;
+        else
+          message (nullptr, "Please answer yes or no.");
+      }
+  }
+
+  std::string input_system::interactive_input (const std::string& s, bool& eof)
+  {
+    Vlast_prompt_time.stamp ();
+
+    if (Vdrawnow_requested && octave::application::interactive ())
+      {
+        bool eval_error = false;
+
+        try
+          {
+            Fdrawnow ();
+          }
+        catch (const octave::execution_exception& e)
+          {
+            eval_error = true;
+
+            std::string stack_trace = e.info ();
+
+            if (! stack_trace.empty ())
+              std::cerr << stack_trace;
+
+            if (octave::application::interactive ())
+              octave::interpreter::recover_from_exception ();
+          }
+
+        octave::flush_stdout ();
+
+        // We set Vdrawnow_requested to false even if there is an error in
+        // drawnow so that the error doesn't reappear at every prompt.
+
+        Vdrawnow_requested = false;
+
+        if (eval_error)
+          return "\n";
+      }
+
+    return gnu_readline (s, eof);
+  }
 
-      Vdrawnow_requested = false;
+  // If the user simply hits return, this will produce an empty matrix.
+
+  octave_value_list
+  input_system::get_user_input (const octave_value_list& args, int nargout)
+  {
+    octave_value_list retval;
+
+    int read_as_string = 0;
+
+    if (args.length () == 2)
+      read_as_string++;
+
+    std::string prompt = args(0).xstring_value ("input: unrecognized argument");
+
+    output_system& output_sys = __get_output_system__ ("do_sync");
+
+    output_sys.reset ();
+
+    octave_diary << prompt;
+
+    bool eof = false;
+
+    std::string input_buf = interactive_input (prompt.c_str (), eof);
+
+    if (input_buf.empty ())
+      error ("input: reading user-input failed!");
+
+    size_t len = input_buf.length ();
+
+    octave_diary << input_buf;
+
+    if (input_buf[len - 1] != '\n')
+      octave_diary << "\n";
+
+    if (len < 1)
+      return read_as_string ? octave_value ("") : octave_value (Matrix ());
+
+    if (read_as_string)
+      {
+        // FIXME: fix gnu_readline and octave_gets instead!
+        if (input_buf.length () == 1 && input_buf[0] == '\n')
+          retval(0) = "";
+        else
+          retval(0) = input_buf;
+      }
+    else
+      {
+        int parse_status = 0;
+
+        retval
+          = m_interpreter.eval_string (input_buf, true, parse_status, nargout);
+
+        if (! Vdebugging && retval.empty ())
+          retval(0) = Matrix ();
+      }
+
+    return retval;
+  }
 
-      if (eval_error)
-        return "\n";
-    }
+  octave_value input_system::keyboard (const octave_value_list& args)
+  {
+    octave_value retval;
+
+    int nargin = args.length ();
+
+    assert (nargin == 0 || nargin == 1);
+
+    octave::unwind_protect frame;
+
+    frame.add_fcn (octave::command_history::ignore_entries,
+                   octave::command_history::ignoring_entries ());
+
+    octave::command_history::ignore_entries (false);
+
+    frame.protect_var (Vdebugging);
+
+    octave::call_stack& cs = m_interpreter.get_call_stack ();
+
+    frame.add_method (cs, &octave::call_stack::restore_frame,
+                      cs.current_frame ());
+
+    // FIXME: probably we just want to print one line, not the
+    // entire statement, which might span many lines...
+    //
+    // tree_print_code tpc (octave_stdout);
+    // stmt.accept (tpc);
+
+    Vdebugging = true;
+    Vtrack_line_num = false;
+
+    std::string prompt = "debug> ";
+    if (nargin > 0)
+      prompt = args(0).string_value ();
+
+    get_debug_input (prompt);
+
+    return retval;
+  }
+
+  bool input_system::have_input_event_hooks (void) const
+  {
+    return ! m_input_event_hook_functions.empty ();
+  }
+
+  void input_system::add_input_event_hook (const hook_function& hook_fcn)
+  {
+    m_input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
+  }
+
+  bool input_system::remove_input_event_hook (const std::string& hook_fcn_id)
+  {
+    hook_function_list::iterator p
+      = m_input_event_hook_functions.find (hook_fcn_id);
+
+    if (p == m_input_event_hook_functions.end ())
+      return false;
+
+    m_input_event_hook_functions.erase (p);
+    return true;
+  }
+
+  void input_system::clear_input_event_hooks (void)
+  {
+    m_input_event_hook_functions.clear ();
+  }
+
+  void input_system::run_input_event_hooks (void)
+  {
+    m_input_event_hook_functions.run ();
+  }
+
+  std::string
+  input_system::gnu_readline (const std::string& s, bool& eof) const
+  {
+    octave_quit ();
+
+    eof = false;
+
+    std::string retval = octave::command_editor::readline (s, eof);
+
+    if (! eof && retval.empty ())
+      retval = "\n";
+
+    return retval;
+  }
+
+  static void
+  execute_in_debugger_handler (const std::pair<std::string, int>& arg)
+  {
+    octave_link::execute_in_debugger_event (arg.first, arg.second);
+  }
+
+  void input_system::get_debug_input (const std::string& prompt)
+  {
+    octave::unwind_protect frame;
+
+    octave::tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+    bool silent = tw.quiet_breakpoint_flag (false);
+
+    octave::call_stack& cs = m_interpreter.get_call_stack ();
+
+    octave_user_code *caller = cs.caller_user_code ();
+    std::string nm;
+    int curr_debug_line;
+
+    if (caller)
+      {
+        nm = caller->fcn_file_name ();
+
+        if (nm.empty ())
+          nm = caller->name ();
 
-  return gnu_readline (s, eof);
-}
+        curr_debug_line = cs.caller_user_code_line ();
+      }
+    else
+      curr_debug_line = cs.current_line ();
+
+    std::ostringstream buf;
+
+    if (! nm.empty ())
+      {
+        if (m_gud_mode)
+          {
+            static char ctrl_z = 'Z' & 0x1f;
+
+            buf << ctrl_z << ctrl_z << nm << ':' << curr_debug_line;
+          }
+        else
+          {
+            // FIXME: we should come up with a clean way to detect
+            // that we are stopped on the no-op command that marks the
+            // end of a function or script.
+
+            if (! silent)
+              {
+                buf << "stopped in " << nm;
+
+                if (curr_debug_line > 0)
+                  buf << " at line " << curr_debug_line;
+              }
+
+            octave_link::enter_debugger_event (nm, curr_debug_line);
+
+            octave_link::set_workspace ();
+
+            frame.add_fcn (execute_in_debugger_handler,
+                           std::pair<std::string, int> (nm, curr_debug_line));
+
+            if (! silent)
+              {
+                std::string line_buf;
+
+                if (caller)
+                  line_buf = caller->get_code_line (curr_debug_line);
+
+                if (! line_buf.empty ())
+                  buf << "\n" << curr_debug_line << ": " << line_buf;
+              }
+          }
+      }
+
+    if (silent)
+      octave::command_editor::erase_empty_line (true);
+
+    std::string msg = buf.str ();
+
+    if (! msg.empty ())
+      std::cerr << msg << std::endl;
+
+    frame.add_method (*this, &octave::input_system::set_PS1, m_PS1);
+    m_PS1 = prompt;
 
-namespace octave
-{
+    // FIXME: should debugging be possible in an embedded interpreter?
+
+    octave::application *app = octave::application::app ();
+
+    if (! app->interactive ())
+      {
+
+        frame.add_method (app, &octave::application::interactive,
+                          app->interactive ());
+
+        frame.add_method (app, &octave::application::forced_interactive,
+                          app->forced_interactive ());
+
+        app->interactive (true);
+
+        app->forced_interactive (true);
+      }
+
+    octave::parser curr_parser (m_interpreter);
+
+    while (Vdebugging)
+      {
+        try
+          {
+            Vtrack_line_num = false;
+
+            reset_error_handler ();
+
+            curr_parser.reset ();
+
+            int retval = curr_parser.run ();
+
+            if (octave::command_editor::interrupt (false))
+              break;
+            else
+              {
+                if (retval == 0 && curr_parser.m_stmt_list)
+                  {
+                    curr_parser.m_stmt_list->accept (tw);
+
+                    if (octave_completion_matches_called)
+                      octave_completion_matches_called = false;
+                  }
+
+                octave_quit ();
+              }
+          }
+        catch (const octave::execution_exception& e)
+          {
+            std::string stack_trace = e.info ();
+
+            if (! stack_trace.empty ())
+              std::cerr << stack_trace;
+
+            // Ignore errors when in debugging mode;
+            octave::interpreter::recover_from_exception ();
+          }
+      }
+  }
+
   std::string base_reader::octave_gets (bool& eof)
   {
     octave_quit ();
@@ -210,20 +918,21 @@
 
     bool history_skip_auto_repeated_debugging_command = false;
 
-    std::string ps = (m_pflag > 0) ? VPS1 : VPS2;
+    input_system& input_sys = __get_input_system__ ("base_reader::octave_gets");
+
+    std::string ps = (m_pflag > 0) ? input_sys.PS1 () : input_sys.PS2 ();
 
     std::string prompt = command_editor::decode_prompt_string (ps);
 
     pipe_handler_error_count = 0;
 
-    flush_stdout ();
+    output_system& output_sys = __get_output_system__ ("do_sync");
 
-    pager_stream::reset ();
-    diary_stream::reset ();
+    output_sys.reset ();
 
     octave_diary << prompt;
 
-    retval = interactive_input (prompt, eof);
+    retval = input_sys.interactive_input (prompt, eof);
 
     // There is no need to update the load_path cache if there is no
     // user input.
@@ -235,13 +944,13 @@
         lp.update ();
 
         if (Vdebugging)
-          last_debugging_command = retval;
+          input_sys.last_debugging_command (retval);
         else
-          last_debugging_command = "\n";
+          input_sys.last_debugging_command ("\n");
       }
     else if (Vdebugging)
       {
-        retval = last_debugging_command;
+        retval = input_sys.last_debugging_command ();
         history_skip_auto_repeated_debugging_command = true;
       }
 
@@ -359,401 +1068,7 @@
   input_reader::input_reader (const std::string& str, base_lexer *lxr)
     : m_rep (new eval_string_reader (str, lxr))
   { }
-}
 
-// 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 ();
-}
-
-// FIXME: make this generate filenames when appropriate.
-
-static string_vector
-generate_possible_completions (const std::string& text, std::string& prefix,
-                               std::string& hint, bool& deemed_struct)
-{
-  string_vector names;
-
-  prefix = "";
-
-  char prev_char = octave::command_editor::get_prev_char (text.length ());
-  deemed_struct = looks_like_struct (text, prev_char);
-
-  if (deemed_struct)
-    names = generate_struct_completions (text, prefix, hint);
-  else
-    names = octave::make_name_list ();
-
-  // Sort and remove duplicates.
-
-  names.sort (true);
-
-  return names;
-}
-
-static bool
-is_completing_dirfns (void)
-{
-  static std::string dirfns_commands[] = {"cd", "ls"};
-  static const size_t dirfns_commands_length = 2;
-
-  bool retval = false;
-
-  std::string line = octave::command_editor::get_line_buffer ();
-
-  for (size_t i = 0; i < dirfns_commands_length; i++)
-    {
-      int index = line.find (dirfns_commands[i] + ' ');
-
-      if (index == 0)
-        {
-          retval = true;
-          break;
-        }
-    }
-
-  return retval;
-}
-
-static std::string
-generate_completion (const std::string& text, int state)
-{
-  std::string retval;
-
-  static std::string prefix;
-  static std::string hint;
-
-  static size_t hint_len = 0;
-
-  static int list_index = 0;
-  static int name_list_len = 0;
-  static int name_list_total_len = 0;
-  static string_vector name_list;
-  static string_vector file_name_list;
-
-  static int matches = 0;
-
-  if (state == 0)
-    {
-      list_index = 0;
-
-      prefix = "";
-
-      hint = text;
-
-      // No reason to display symbols while completing a
-      // file/directory operation.
-
-      bool deemed_struct = false;
-
-      if (is_completing_dirfns ())
-        name_list = string_vector ();
-      else
-        name_list = generate_possible_completions (text, prefix, hint,
-                                                   deemed_struct);
-
-      name_list_len = name_list.numel ();
-
-      // If the line was something like "a{1}." then text = "." but
-      // we don't want to expand all the . files.
-      if (! deemed_struct)
-        {
-
-          file_name_list = octave::command_editor::generate_filename_completions (text);
-
-          name_list.append (file_name_list);
-
-        }
-
-      name_list_total_len = name_list.numel ();
-
-      hint_len = hint.length ();
-
-      matches = 0;
-
-      for (int i = 0; i < name_list_len; i++)
-        if (hint == name_list[i].substr (0, hint_len))
-          matches++;
-    }
-
-  if (name_list_total_len > 0 && matches > 0)
-    {
-      while (list_index < name_list_total_len)
-        {
-          std::string name = name_list[list_index];
-
-          list_index++;
-
-          if (hint == name.substr (0, hint_len))
-            {
-              // Special case: array reference forces prefix="."
-              //               in generate_struct_completions ()
-              if (list_index <= name_list_len && ! prefix.empty ())
-                retval = (prefix == "." ? "" : prefix) + '.' + name;
-              else
-                retval = name;
-
-              char prev_char = octave::command_editor::get_prev_char
-                                                       (text.length ());
-              if (matches == 1 && looks_like_struct (retval, prev_char))
-                {
-                  // Don't append anything, since we don't know
-                  // whether it should be '(' or '.'.
-
-                  octave::command_editor::set_completion_append_character ('\0');
-                }
-              else
-                octave::command_editor::set_completion_append_character
-                  (Vcompletion_append_char);
-
-              break;
-            }
-        }
-    }
-
-  return retval;
-}
-
-static std::string
-quoting_filename (const std::string& text, int, char quote)
-{
-  if (quote)
-    return text;
-  else
-    return ("'" + text);
-}
-
-// Try to parse a partial command line in reverse, excluding trailing TEXT.
-// If it appears a variable has been indexed by () or {},
-// return that expression,
-// to allow autocomplete of field names of arrays of structures.
-std::string
-find_indexed_expression (const std::string& text)
-{
-  std::string line = octave::command_editor::get_line_buffer ();
-
-  int pos = line.length () - text.length ();
-  int curly_count = 0;
-  int paren_count = 0;
-
-  int last = --pos;
-
-  while (pos >= 0 && (line[pos] == ')' || line[pos] == '}'))
-    {
-      if (line[pos] == ')')
-        paren_count++;
-      else if (line[pos] == '}')
-        curly_count++;
-
-      while (curly_count + paren_count > 0 && --pos >= 0)
-        {
-          if (line[pos] == ')')
-            paren_count++;
-          else if (line[pos] == '(')
-            paren_count--;
-          else if (line[pos] == '}')
-            curly_count++;
-          else if (line[pos] == '{')
-            curly_count--;
-        }
-
-      while (--pos >= 0 && line[pos] == ' ')
-        ;
-    }
-
-  while (pos >= 0 && (isalnum (line[pos]) || line[pos] == '_'))
-    pos--;
-
-  if (++pos >= 0)
-    return (line.substr (pos, last + 1 - pos));
-  else
-    return std::string ();
-}
-
-void
-initialize_command_input (void)
-{
-  // If we are using readline, this allows conditional parsing of the
-  // .inputrc file.
-
-  octave::command_editor::set_name ("Octave");
-
-  // FIXME: this needs to include a comma too, but that
-  // causes trouble for the new struct element completion code.
-
-  static const char *s = "\t\n !\"\'*+-/:;<=>(){}[\\]^`~";
-
-  octave::command_editor::set_basic_word_break_characters (s);
-
-  octave::command_editor::set_completer_word_break_characters (s);
-
-  octave::command_editor::set_basic_quote_characters (R"(")");
-
-  octave::command_editor::set_filename_quote_characters (" \t\n\\\"'@<>=;|&()#$`?*[!:{");
-  octave::command_editor::set_completer_quote_characters (R"('")");
-
-  octave::command_editor::set_completion_function (generate_completion);
-
-  octave::command_editor::set_quoting_function (quoting_filename);
-}
-
-static void
-execute_in_debugger_handler (const std::pair<std::string, int>& arg)
-{
-  octave_link::execute_in_debugger_event (arg.first, arg.second);
-}
-
-static void
-get_debug_input (octave::interpreter& interp, const std::string& prompt)
-{
-  octave::unwind_protect frame;
-
-  bool silent = octave::tree_evaluator::quiet_breakpoint_flag;
-  octave::tree_evaluator::quiet_breakpoint_flag = false;
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  octave_user_code *caller = cs.caller_user_code ();
-  std::string nm;
-  int curr_debug_line;
-
-  if (caller)
-    {
-      nm = caller->fcn_file_name ();
-
-      if (nm.empty ())
-        nm = caller->name ();
-
-      curr_debug_line = cs.caller_user_code_line ();
-    }
-  else
-    curr_debug_line = cs.current_line ();
-
-  std::ostringstream buf;
-
-  if (! nm.empty ())
-    {
-      if (Vgud_mode)
-        {
-          static char ctrl_z = 'Z' & 0x1f;
-
-          buf << ctrl_z << ctrl_z << nm << ':' << curr_debug_line;
-        }
-      else
-        {
-          // FIXME: we should come up with a clean way to detect
-          // that we are stopped on the no-op command that marks the
-          // end of a function or script.
-
-          if (! silent)
-            {
-              buf << "stopped in " << nm;
-
-              if (curr_debug_line > 0)
-                buf << " at line " << curr_debug_line;
-            }
-
-          octave_link::enter_debugger_event (nm, curr_debug_line);
-
-          octave_link::set_workspace ();
-
-          frame.add_fcn (execute_in_debugger_handler,
-                         std::pair<std::string, int> (nm, curr_debug_line));
-
-          if (! silent)
-            {
-              std::string line_buf;
-
-              if (caller)
-                line_buf = caller->get_code_line (curr_debug_line);
-
-              if (! line_buf.empty ())
-                buf << "\n" << curr_debug_line << ": " << line_buf;
-            }
-        }
-    }
-
-  if (silent)
-    octave::command_editor::erase_empty_line (true);
-
-  std::string msg = buf.str ();
-
-  if (! msg.empty ())
-    std::cerr << msg << std::endl;
-
-  frame.protect_var (VPS1);
-  VPS1 = prompt;
-
-  // FIXME: should debugging be possible in an embedded interpreter?
-
-  octave::application *app = octave::application::app ();
-
-  if (! app->interactive ())
-    {
-
-      frame.add_method (app, &octave::application::interactive,
-                        app->interactive ());
-
-      frame.add_method (app, &octave::application::forced_interactive,
-                        app->forced_interactive ());
-
-      app->interactive (true);
-
-      app->forced_interactive (true);
-    }
-
-  octave::parser curr_parser;
-
-  octave::tree_evaluator& tw = interp.get_evaluator ();
-
-  while (Vdebugging)
-    {
-      try
-        {
-          Vtrack_line_num = false;
-
-          reset_error_handler ();
-
-          curr_parser.reset ();
-
-          int retval = curr_parser.run ();
-
-          if (octave::command_editor::interrupt (false))
-            break;
-          else
-            {
-              if (retval == 0 && curr_parser.m_stmt_list)
-                {
-                  curr_parser.m_stmt_list->accept (tw);
-
-                  if (octave_completion_matches_called)
-                    octave_completion_matches_called = false;
-                }
-
-              octave_quit ();
-            }
-        }
-      catch (const octave::execution_exception& e)
-        {
-          std::string stack_trace = e.info ();
-
-          if (! stack_trace.empty ())
-            std::cerr << stack_trace;
-
-          // Ignore errors when in debugging mode;
-          octave::interpreter::recover_from_exception ();
-        }
-    }
-}
-
-namespace octave
-{
   const std::string base_reader::s_in_src ("invalid");
 
   const std::string terminal_reader::s_in_src ("terminal");
@@ -777,7 +1092,46 @@
 
     eof = false;
 
-    return octave_fgets (m_file, eof);
+    std::string src_str = octave_fgets (m_file, eof);
+
+    octave::input_system& input_sys
+      = octave::__get_input_system__ ("get_input");
+
+    std::string mfile_encoding = input_sys.mfile_encoding ();
+
+    std::string encoding
+      = (mfile_encoding.compare ("system") == 0
+         ? octave_locale_charset_wrapper () : mfile_encoding);
+
+    if (encoding.compare ("utf-8") == 0)
+    {
+      // Check for BOM and strip it
+      if (src_str.compare (0, 3, "\xef\xbb\xbf") == 0)
+        src_str.erase (0, 3);
+    }
+    else
+    {
+      // convert encoding to UTF-8 before returning string
+      const char *src = src_str.c_str ();
+      size_t srclen = src_str.length ();
+
+      size_t length;
+      uint8_t *utf8_str = nullptr;
+
+      utf8_str = octave_u8_conv_from_encoding (encoding.c_str (), src, srclen,
+                                               &length);
+
+      if (! utf8_str)
+        error ("file_reader::get_input: converting from codepage '%s' to UTF-8: %s",
+               encoding.c_str (), std::strerror (errno));
+
+      octave::unwind_protect frame;
+      frame.add_fcn (::free, static_cast<void *> (utf8_str));
+
+      src_str = std::string (reinterpret_cast<char *> (utf8_str), length);
+    }
+
+    return src_str;
   }
 
   const std::string eval_string_reader::s_in_src ("eval_string");
@@ -804,67 +1158,8 @@
   }
 }
 
-// If the user simply hits return, this will produce an empty matrix.
-
-static octave_value_list
-get_user_input (const octave_value_list& args, int nargout)
-{
-  octave_value_list retval;
-
-  int read_as_string = 0;
-
-  if (args.length () == 2)
-    read_as_string++;
-
-  std::string prompt = args(0).xstring_value ("input: unrecognized argument");
-
-  octave::flush_stdout ();
-
-  octave::pager_stream::reset ();
-  octave::diary_stream::reset ();
-
-  octave_diary << prompt;
-
-  bool eof = false;
-
-  std::string input_buf = interactive_input (prompt.c_str (), eof);
-
-  if (input_buf.empty ())
-    error ("input: reading user-input failed!");
-
-  size_t len = input_buf.length ();
-
-  octave_diary << input_buf;
-
-  if (input_buf[len - 1] != '\n')
-    octave_diary << "\n";
-
-  if (len < 1)
-    return read_as_string ? octave_value ("") : octave_value (Matrix ());
-
-  if (read_as_string)
-    {
-      // FIXME: fix gnu_readline and octave_gets instead!
-      if (input_buf.length () == 1 && input_buf[0] == '\n')
-        retval(0) = "";
-      else
-        retval(0) = input_buf;
-    }
-  else
-    {
-      int parse_status = 0;
-
-      retval = octave::eval_string (input_buf, true, parse_status, nargout);
-
-      if (! Vdebugging && retval.empty ())
-        retval(0) = Matrix ();
-    }
-
-  return retval;
-}
-
-DEFUN (input, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (input, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{ans} =} input (@var{prompt})
 @deftypefnx {} {@var{ans} =} input (@var{prompt}, "s")
 Print @var{prompt} and wait for user input.
@@ -907,31 +1202,13 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
-  return get_user_input (args, std::max (nargout, 1));
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.get_user_input (args, std::max (nargout, 1));
 }
 
-bool
-octave_yes_or_no (const std::string& prompt)
-{
-  std::string prompt_string = prompt + "(yes or no) ";
-
-  while (1)
-    {
-      bool eof = false;
-
-      std::string input_buf = interactive_input (prompt_string, eof);
-
-      if (input_buf == "yes")
-        return true;
-      else if (input_buf == "no")
-        return false;
-      else
-        message (nullptr, "Please answer yes or no.");
-    }
-}
-
-DEFUN (yes_or_no, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (yes_or_no, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {@var{ans} =} yes_or_no ("@var{prompt}")
 Ask the user a yes-or-no question.
 
@@ -949,61 +1226,14 @@
   if (nargin > 1)
     print_usage ();
 
+  octave::input_system& input_sys = interp.get_input_system ();
+
   std::string prompt;
 
   if (nargin == 1)
     prompt = args(0).xstring_value ("yes_or_no: PROMPT must be a string");
 
-  return ovl (octave_yes_or_no (prompt));
-}
-
-octave_value
-do_keyboard (octave::interpreter& interp, const octave_value_list& args)
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  assert (nargin == 0 || nargin == 1);
-
-  octave::unwind_protect frame;
-
-  frame.add_fcn (octave::command_history::ignore_entries,
-                 octave::command_history::ignoring_entries ());
-
-  octave::command_history::ignore_entries (false);
-
-  frame.protect_var (Vdebugging);
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  frame.add_method (cs, &octave::call_stack::restore_frame,
-                    cs.current_frame ());
-
-  // FIXME: probably we just want to print one line, not the
-  // entire statement, which might span many lines...
-  //
-  // tree_print_code tpc (octave_stdout);
-  // stmt.accept (tpc);
-
-  Vdebugging = true;
-  Vtrack_line_num = false;
-
-  std::string prompt = "debug> ";
-  if (nargin > 0)
-    prompt = args(0).string_value ();
-
-  get_debug_input (interp, prompt);
-
-  return retval;
-}
-
-octave_value
-do_keyboard (const octave_value_list& args)
-{
-  octave::interpreter& interp = octave::__get_interpreter__ ("do_keyboard");
-
-  return do_keyboard (interp, args);
+  return ovl (input_sys.yes_or_no (prompt));
 }
 
 DEFMETHOD (keyboard, interp, args, ,
@@ -1037,12 +1267,15 @@
   // Skip the frame assigned to the keyboard function.
   cs.goto_frame_relative (0);
 
-  octave::tree_evaluator::debug_mode = true;
-  octave::tree_evaluator::quiet_breakpoint_flag = false;
+  octave::tree_evaluator& tw = interp.get_evaluator ();
 
-  octave::tree_evaluator::current_frame = cs.current_frame ();
+  tw.debug_mode (true);
+  tw.quiet_breakpoint_flag (false);
+  tw.current_frame (cs.current_frame ());
 
-  do_keyboard (interp, args);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  input_sys.keyboard (args);
 
   return ovl ();
 }
@@ -1182,16 +1415,19 @@
 static int
 internal_input_event_hook_fcn (void)
 {
-  input_event_hook_functions.run ();
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("internal_input_event_hook_fcn");
 
-  if (input_event_hook_functions.empty ())
+  input_sys.run_input_event_hooks ();
+
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::remove_event_hook (internal_input_event_hook_fcn);
 
   return 0;
 }
 
-DEFUN (add_input_event_hook, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (add_input_event_hook, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{id} =} add_input_event_hook (@var{fcn})
 @deftypefnx {} {@var{id} =} add_input_event_hook (@var{fcn}, @var{data})
 Add the named function or function handle @var{fcn} to the list of functions
@@ -1220,18 +1456,20 @@
   if (nargin == 2)
     user_data = args(1);
 
+  octave::input_system& input_sys = interp.get_input_system ();
+
   hook_function hook_fcn (args(0), user_data);
 
-  if (input_event_hook_functions.empty ())
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::add_event_hook (internal_input_event_hook_fcn);
 
-  input_event_hook_functions.insert (hook_fcn.id (), hook_fcn);
+  input_sys.add_input_event_hook (hook_fcn);
 
   return ovl (hook_fcn.id ());
 }
 
-DEFUN (remove_input_event_hook, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (remove_input_event_hook, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} remove_input_event_hook (@var{name})
 @deftypefnx {} {} remove_input_event_hook (@var{fcn_id})
 Remove the named function or function handle with the given identifier
@@ -1249,23 +1487,20 @@
 
   bool warn = (nargin < 2);
 
-  hook_function_list::iterator p
-    = input_event_hook_functions.find (hook_fcn_id);
+  octave::input_system& input_sys = interp.get_input_system ();
 
-  if (p != input_event_hook_functions.end ())
-    input_event_hook_functions.erase (p);
-  else if (warn)
+  if (! input_sys.remove_input_event_hook (hook_fcn_id) && warn)
     warning ("remove_input_event_hook: %s not found in list",
              hook_fcn_id.c_str ());
 
-  if (input_event_hook_functions.empty ())
+  if (! input_sys.have_input_event_hooks ())
     octave::command_editor::remove_event_hook (internal_input_event_hook_fcn);
 
   return ovl ();
 }
 
-DEFUN (PS1, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PS1, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PS1 ()
 @deftypefnx {} {@var{old_val} =} PS1 (@var{new_val})
 @deftypefnx {} {} PS1 (@var{new_val}, "local")
@@ -1303,11 +1538,13 @@
 @seealso{PS2, PS4}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (PS1);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.PS1 (args, nargout);
 }
 
-DEFUN (PS2, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PS2, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PS2 ()
 @deftypefnx {} {@var{old_val} =} PS2 (@var{new_val})
 @deftypefnx {} {} PS2 (@var{new_val}, "local")
@@ -1325,11 +1562,13 @@
 @seealso{PS1, PS4}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (PS2);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.PS2 (args, nargout);
 }
 
-DEFUN (completion_append_char, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (completion_append_char, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} completion_append_char ()
 @deftypefnx {} {@var{old_val} =} completion_append_char (@var{new_val})
 @deftypefnx {} {} completion_append_char (@var{new_val}, "local")
@@ -1343,11 +1582,13 @@
 The original variable value is restored when exiting the function.
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (completion_append_char);
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.completion_append_char (args, nargout);
 }
 
-DEFUN (__request_drawnow__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__request_drawnow__, , args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} __request_drawnow__ ()
 @deftypefnx {} {} __request_drawnow__ (@var{flag})
 Undocumented internal function.
@@ -1366,23 +1607,70 @@
   return ovl ();
 }
 
-DEFUN (__gud_mode__, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (__gud_mode__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn {} {} __gud_mode__ ()
 Undocumented internal function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  return input_sys.gud_mode (args, nargout);
+}
+
+DEFMETHOD (__mfile_encoding__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {@var{current_encoding} =} __mfile_encoding__ (@var{new_encoding})
+Set and query the codepage that is used for reading .m files.
+@end deftypefn */)
+{
+  octave::input_system& input_sys = interp.get_input_system ();
 
-  if (nargin > 1)
-    print_usage ();
+  return input_sys.mfile_encoding (args, nargout);
+}
+
+// Always define these functions.  The macro is intended to allow the
+// declarations to be hidden, not so that Octave will not provide the
+// functions if they are requested.
+
+// #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
 
-  octave_value_list retval;
+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);
+}
 
-  if (nargin == 0)
-    retval = ovl (Vgud_mode);
-  else
-    Vgud_mode = args(0).bool_value ();
+octave_value
+do_keyboard (const octave_value_list& args)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("do_keyboard");
+
+  return input_sys.keyboard (args);
+}
+
+void
+remove_input_event_hook_functions (void)
+{
+  octave::input_system& input_sys
+    = octave::__get_input_system__ ("remove_input_event_hook_functions");
 
-  return retval;
+  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	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/input.h	Thu Dec 20 17:18:56 2018 -0500
@@ -31,19 +31,12 @@
 
 #include <string>
 
+#include "hook-fcn.h"
 #include "oct-refcount.h"
 #include "oct-time.h"
 #include "ovl.h"
 #include "pager.h"
 
-class octave_value;
-namespace octave
-{
-  class base_lexer;
-}
-
-extern OCTINTERP_API FILE * get_input_from_stdin (void);
-
 // TRUE after a call to completion_matches.
 extern bool octave_completion_matches_called;
 
@@ -57,25 +50,157 @@
 // TRUE if we are not executing a command direct from debug> prompt.
 extern OCTINTERP_API bool Vtrack_line_num;
 
-extern std::string find_indexed_expression (const std::string& text);
-
-extern void initialize_command_input (void);
-
-extern bool octave_yes_or_no (const std::string& prompt);
+extern octave::sys::time Vlast_prompt_time;
 
-extern octave_value do_keyboard (const octave_value_list& args
-                                 = octave_value_list ());
-
-extern void remove_input_event_hook_functions (void);
-
-extern void set_default_prompts (void);
-
-extern octave::sys::time Vlast_prompt_time;
+class octave_value;
 
 namespace octave
 {
-  class
-  base_reader
+  class interpreter;
+  class base_lexer;
+
+  class input_system
+  {
+  public:
+
+    input_system (interpreter& interp);
+
+    void initialize (bool line_editing);
+
+    octave_value PS1 (const octave_value_list& args, int nargout);
+
+    std::string PS1 (void) const { return m_PS1; }
+
+    std::string PS1 (const std::string& s)
+    {
+      std::string val = m_PS1;
+      m_PS1 = s;
+      return val;
+    }
+
+    void set_PS1 (const std::string& s) { m_PS1 = s; }
+
+    octave_value PS2 (const octave_value_list& args, int nargout);
+
+    std::string PS2 (void) const { return m_PS2; }
+
+    std::string PS2 (const std::string& s)
+    {
+      std::string val = m_PS2;
+      m_PS2 = s;
+      return val;
+    }
+
+    void set_PS2 (const std::string& s) { m_PS2 = s; }
+
+    std::string last_debugging_command (void) const
+    {
+      return m_last_debugging_command;
+    }
+
+    std::string last_debugging_command (const std::string& s)
+    {
+      std::string val = m_last_debugging_command;
+      m_last_debugging_command = s;
+      return val;
+    }
+
+    octave_value
+    completion_append_char (const octave_value_list& args, int nargout);
+
+    char completion_append_char (void) const
+    {
+      return m_completion_append_char;
+    }
+
+    char completion_append_char (char c)
+    {
+      char val = m_completion_append_char;
+      m_completion_append_char = c;
+      return val;
+    }
+
+    void set_completion_append_char (char c) { m_completion_append_char = c; }
+
+    octave_value gud_mode (const octave_value_list& args, int nargout);
+
+    bool gud_mode (void) const { return m_gud_mode; }
+
+    bool gud_mode (bool flag)
+    {
+      bool val = m_gud_mode;
+      m_gud_mode = flag;
+      return val;
+    }
+
+    void set_gud_mode (bool flag) { m_gud_mode = flag; }
+
+    octave_value mfile_encoding (const octave_value_list& args, int nargout);
+
+    std::string mfile_encoding (void) const { return m_mfile_encoding; }
+
+    std::string mfile_encoding (const std::string& s)
+    {
+      std::string val = m_mfile_encoding;
+      m_mfile_encoding = s;
+      return val;
+    }
+
+    void set_mfile_encoding (const std::string& s) { m_mfile_encoding = s; }
+
+    bool yes_or_no (const std::string& prompt);
+
+    std::string interactive_input (const std::string& s, bool& eof);
+
+    octave_value_list
+    get_user_input (const octave_value_list& args, int nargout);
+
+    octave_value
+    keyboard (const octave_value_list& args = octave_value_list ());
+
+    bool have_input_event_hooks (void) const;
+
+    void add_input_event_hook (const hook_function& hook_fcn);
+
+    bool remove_input_event_hook (const std::string& hook_fcn_id);
+
+    void clear_input_event_hooks (void);
+
+    void run_input_event_hooks (void);
+
+  private:
+
+    interpreter& m_interpreter;
+
+    // Primary prompt string.
+    std::string m_PS1;
+
+    // Secondary prompt string.
+    std::string m_PS2;
+
+    // Character to append after successful command-line completion
+    // attempts.
+    char m_completion_append_char;
+
+    // TRUE if we are running in the Emacs GUD mode.
+    bool m_gud_mode;
+
+    // Codepage which is used to read .m files
+    std::string m_mfile_encoding;
+
+    // If we are in debugging mode, this is the last command entered,
+    // so that we can repeat the previous command if the user just
+    // types RET.
+    std::string m_last_debugging_command;
+
+    hook_function_list m_input_event_hook_functions;
+
+    std::string gnu_readline (const std::string& s, bool& eof) const;
+
+    void get_debug_input (const std::string& prompt);
+  };
+
+  class base_reader
   {
   public:
 
@@ -135,8 +260,7 @@
     static const std::string s_in_src;
   };
 
-  class
-  input_reader
+  class input_reader
   {
   public:
 
@@ -210,4 +334,21 @@
   };
 }
 
+#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::keyboard' instead")
+extern octave_value do_keyboard (const octave_value_list& args
+                                 = octave_value_list ());
+
+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.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/interpreter-private.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -32,10 +32,14 @@
 #include "error.h"
 #include "gtk-manager.h"
 #include "help.h"
+#include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
 #include "load-path.h"
+#include "load-save.h"
+#include "oct-hist.h"
 #include "ov-classdef.h"
+#include "pager.h"
 #include "symtab.h"
 
 namespace octave
@@ -67,6 +71,27 @@
     return interp.get_help_system ();
   }
 
+  history_system& __get_history_system__ (const std::string& who)
+  {
+    interpreter& interp = __get_interpreter__ (who);
+
+    return interp.get_history_system ();
+  }
+
+  input_system& __get_input_system__ (const std::string& who)
+  {
+    interpreter& interp = __get_interpreter__ (who);
+
+    return interp.get_input_system ();
+  }
+
+  output_system& __get_output_system__ (const std::string& who)
+  {
+    interpreter& interp = __get_interpreter__ (who);
+
+    return interp.get_output_system ();
+  }
+
   load_path& __get_load_path__ (const std::string& who)
   {
     interpreter& interp = __get_interpreter__ (who);
@@ -74,6 +99,13 @@
     return interp.get_load_path ();
   }
 
+  load_save_system& __get_load_save_system__ (const std::string& who)
+  {
+    interpreter& interp = __get_interpreter__ (who);
+
+    return interp.get_load_save_system ();
+  }
+
   type_info& __get_type_info__ (const std::string& who)
   {
     interpreter& interp = __get_interpreter__ (who);
@@ -114,9 +146,9 @@
 
   bp_table& __get_bp_table__ (const std::string& who)
   {
-    interpreter& interp = __get_interpreter__ (who);
+    tree_evaluator& tw = __get_evaluator__ (who);
 
-    return interp.get_bp_table ();
+    return tw.get_bp_table ();
   }
 
   call_stack& __get_call_stack__ (const std::string& who)
--- a/libinterp/corefcn/interpreter-private.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/interpreter-private.h	Thu Dec 20 17:18:56 2018 -0500
@@ -39,8 +39,12 @@
   class dynamic_loader;
   class gtk_manager;
   class help_system;
+  class history_system;
+  class input_system;
   class interpreter;
   class load_path;
+  class load_save_system;
+  class output_system;
   class tree_evaluator;
   class type_info;
 
@@ -50,8 +54,16 @@
 
   extern help_system& __get_help_system__ (const std::string& who);
 
+  extern history_system& __get_history_system__ (const std::string& who);
+
+  extern input_system& __get_input_system__ (const std::string& who);
+
   extern load_path& __get_load_path__ (const std::string& who);
 
+  extern load_save_system& __get_load_save_system__ (const std::string& who);
+
+  extern output_system& __get_output_system__ (const std::string& who);
+
   extern type_info& __get_type_info__ (const std::string& who);
 
   extern symbol_table& __get_symbol_table__ (const std::string& who);
--- a/libinterp/corefcn/interpreter.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/interpreter.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,7 +29,6 @@
 
 #include "cmd-edit.h"
 #include "cmd-hist.h"
-#include "file-ops.h"
 #include "file-stat.h"
 #include "fpucw-wrappers.h"
 #include "lo-blas-proto.h"
@@ -49,6 +48,7 @@
 #include "file-io.h"
 #include "graphics.h"
 #include "help.h"
+#include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
 #include "load-path.h"
@@ -64,8 +64,8 @@
 #include "parse.h"
 #include "pt-eval.h"
 #include "pt-jump.h"
-#include "pt-mat.h"
 #include "pt-stmt.h"
+#include "settings.h"
 #include "sighandlers.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
@@ -275,26 +275,6 @@
     return 0;
   }
 
-  static void execute_pkg_add (const std::string& dir)
-  {
-    std::string file_name = sys::file_ops::concat (dir, "PKG_ADD");
-
-    load_path& lp = __get_load_path__ ("execute_pkg_add");
-
-    try
-      {
-        lp.execute_pkg_add (dir);
-      }
-    catch (const interrupt_exception&)
-      {
-        interpreter::recover_from_exception ();
-      }
-    catch (const execution_exception&)
-      {
-        interpreter::recover_from_exception ();
-      }
-  }
-
   static void initialize_version_info (void)
   {
     octave_value_list args;
@@ -378,13 +358,17 @@
   interpreter::interpreter (application *app_context)
     : m_app_context (app_context),
       m_environment (),
+      m_settings (),
       m_help_system (*this),
+      m_input_system (*this),
+      m_output_system (*this),
+      m_history_system (*this),
       m_dynamic_loader (*this),
       m_load_path (),
+      m_load_save_system (*this),
       m_type_info (),
       m_symbol_table (),
       m_evaluator (*this),
-      m_bp_table (),
       m_stream_list (*this),
       m_child_list (),
       m_url_handle_manager (),
@@ -421,8 +405,6 @@
 
     thread::init ();
 
-    set_default_prompts ();
-
     // Initialize default warning state before --traditional option
     // that may reset them.
 
@@ -430,8 +412,6 @@
 
     octave_ieee_init ();
 
-    octave_prepare_hdf5 ();
-
     initialize_xerbla_error_handler ();
 
     initialize_error_handlers ();
@@ -531,11 +511,7 @@
           Ftexi_macros_file (*this, octave_value (texi_macros_file));
       }
 
-    // Force default line editor if we don't want readline editing.
-    if (line_editing)
-      initialize_command_input ();
-    else
-      command_editor::force_default_editor ();
+    m_input_system.initialize (line_editing);
 
     // These can come after command line args since none of them set any
     // defaults that might be changed by command line options.
@@ -588,7 +564,7 @@
               command_history::ignore_entries ();
           }
 
-        ::initialize_history (read_history_file);
+        m_history_system.initialize (read_history_file);
 
         if (! m_app_context)
           command_history::ignore_entries ();
@@ -627,7 +603,8 @@
         frame.add_method (m_load_path, &load_path::set_add_hook,
                           m_load_path.get_add_hook ());
 
-        m_load_path.set_add_hook (execute_pkg_add);
+        m_load_path.set_add_hook ([this] (const std::string& dir)
+                                  { this->execute_pkg_add (dir); });
 
         m_load_path.initialize (set_initial_path);
 
@@ -969,119 +946,7 @@
 
     // The big loop.
 
-    lexer *lxr = (application::interactive () ? new lexer ()
-                                              : new lexer (stdin));
-
-    parser parser (*lxr);
-
-    int retval = 0;
-    do
-      {
-        try
-          {
-            reset_error_handler ();
-
-            parser.reset ();
-
-            if (m_symbol_table.at_top_level ())
-              tree_evaluator::reset_debug_state ();
-
-            retval = parser.run ();
-
-            if (retval == 0)
-              {
-                if (parser.m_stmt_list)
-                  {
-                    parser.m_stmt_list->accept (m_evaluator);
-
-                    octave_quit ();
-
-                    if (! application::interactive ())
-                      {
-                        bool quit = (tree_return_command::returning
-                                     || tree_break_command::breaking);
-
-                        if (tree_return_command::returning)
-                          tree_return_command::returning = 0;
-
-                        if (tree_break_command::breaking)
-                          tree_break_command::breaking--;
-
-                        if (quit)
-                          break;
-                      }
-
-                    if (octave_completion_matches_called)
-                      octave_completion_matches_called = false;
-                    else
-                      command_editor::increment_current_command_number ();
-                  }
-                else if (parser.m_lexer.m_end_of_input)
-                  {
-                    retval = EOF;
-                    break;
-                  }
-              }
-          }
-        catch (const interrupt_exception&)
-          {
-            recover_from_exception ();
-
-            // Required newline when the user does Ctrl+C at the prompt.
-            if (application::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& e)
-          {
-            std::string stack_trace = e.info ();
-
-            if (! stack_trace.empty ())
-              std::cerr << stack_trace;
-
-            if (application::interactive ())
-              recover_from_exception ();
-            else
-              {
-                // We should exit with a nonzero status.
-                retval = 1;
-                break;
-              }
-          }
-        catch (const std::bad_alloc&)
-          {
-            recover_from_exception ();
-
-            std::cerr << "error: out of memory -- trying to return to prompt"
-                      << std::endl;
-          }
-
-#if defined (DBSTOP_NANINF)
-        if (Vdebug_on_naninf)
-          {
-            if (setjump (naninf_jump) != 0)
-              debug_or_throw_exception (true);  // true = stack trace
-          }
-#endif
-      }
-    while (retval == 0);
-
-    if (retval == EOF)
-      {
-        if (application::interactive ())
-          octave_stdout << "\n";
-
-        retval = 0;
-      }
-
-    return retval;
+    return m_evaluator.repl (application::interactive ());
   }
 
   // Call a function with exceptions handled to avoid problems with
@@ -1126,7 +991,7 @@
     octave_link::process_events (true);
     octave_link::disconnect_link ();
 
-    OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ());
+    OCTAVE_SAFE_CALL (m_input_system.clear_input_event_hooks, ());
 
     while (! atexit_functions.empty ())
       {
@@ -1148,7 +1013,7 @@
 
     OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
 
-    OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
+    OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ());
 
     if (! command_history::ignoring_entries ())
       OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
@@ -1166,8 +1031,6 @@
 
     OCTAVE_SAFE_CALL (sysdep_cleanup, ());
 
-    OCTAVE_SAFE_CALL (octave_finalize_hdf5, ());
-
     OCTAVE_SAFE_CALL (flush_stdout, ());
 
     // Don't call singleton_cleanup_list::cleanup until we have the
@@ -1267,6 +1130,26 @@
     return retval;
   }
 
+  octave_value_list interpreter::eval_string (const std::string& eval_str,
+                                              bool silent, int& parse_status,
+                                              int nargout)
+  {
+    return m_evaluator.eval_string (eval_str, silent, parse_status, nargout);
+  }
+
+  octave_value interpreter::eval_string (const std::string& eval_str,
+                                         bool silent, int& parse_status)
+  {
+    return m_evaluator.eval_string (eval_str, silent, parse_status);
+  }
+
+  octave_value_list interpreter::eval_string (const octave_value& arg,
+                                              bool silent, int& parse_status,
+                                              int nargout)
+  {
+    return m_evaluator.eval_string (arg, silent, parse_status, nargout);
+  }
+
   void interpreter::recover_from_exception (void)
   {
     can_interrupt = true;
@@ -1308,21 +1191,24 @@
 
   void interpreter::maximum_braindamage (void)
   {
-    FPS1 (octave_value (">> "));
-    FPS2 (octave_value (""));
+    m_input_system.PS1 (">> ");
+    m_input_system.PS2 ("");
 
     m_evaluator.PS4 ("");
 
+    m_load_save_system.crash_dumps_octave_core (false);
+    m_load_save_system.save_default_options ("-mat-binary");
+
+    m_history_system.timestamp_format_string ("%%-- %D %I:%M %p --%%");
+
     Fbeep_on_error (octave_value (true));
     Fconfirm_recursive_rmdir (octave_value (false));
-    Fcrash_dumps_octave_core (octave_value (false));
+
     Fdisable_diagonal_matrix (octave_value (true));
     Fdisable_permutation_matrix (octave_value (true));
     Fdisable_range (octave_value (true));
     Ffixed_point_format (octave_value (true));
-    Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%"));
     Fprint_empty_dimensions (octave_value (false));
-    Fsave_default_options (octave_value ("-mat-binary"));
     Fstruct_levels_to_print (octave_value (0));
 
     disable_warning ("Octave:abbreviated-property-match");
@@ -1330,4 +1216,20 @@
     disable_warning ("Octave:function-name-clash");
     disable_warning ("Octave:possible-matlab-short-circuit-operator");
   }
+
+  void interpreter::execute_pkg_add (const std::string& dir)
+  {
+    try
+      {
+        m_load_path.execute_pkg_add (dir);
+      }
+    catch (const octave::interrupt_exception&)
+      {
+        octave::interpreter::recover_from_exception ();
+      }
+    catch (const octave::execution_exception&)
+      {
+        octave::interpreter::recover_from_exception ();
+      }
+  }
 }
--- a/libinterp/corefcn/interpreter.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/interpreter.h	Thu Dec 20 17:18:56 2018 -0500
@@ -31,16 +31,20 @@
 #include "quit.h"
 #include "str-vec.h"
 
-#include "bp-table.h"
 #include "dynamic-ld.h"
 #include "environment.h"
 #include "gtk-manager.h"
 #include "help.h"
+#include "input.h"
 #include "load-path.h"
+#include "load-save.h"
+#include "oct-hist.h"
 #include "oct-stream.h"
 #include "ov-classdef.h"
 #include "ov-typeinfo.h"
+#include "pager.h"
 #include "pt-eval.h"
+#include "settings.h"
 #include "symtab.h"
 #include "url-handle-manager.h"
 
@@ -58,7 +62,6 @@
   class profiler;
   class call_stack;
   class child_list;
-  class tree_evaluator;
 
   // The application object contains a pointer to the current
   // interpreter and the interpreter contains a pointer back to the
@@ -151,11 +154,31 @@
       return m_environment;
     }
 
+    settings& get_settings (void)
+    {
+      return m_settings;
+    }
+
     help_system& get_help_system (void)
     {
       return m_help_system;
     }
 
+    input_system& get_input_system (void)
+    {
+      return m_input_system;
+    }
+
+    output_system& get_output_system (void)
+    {
+      return m_output_system;
+    }
+
+    history_system& get_history_system (void)
+    {
+      return m_history_system;
+    }
+
     dynamic_loader& get_dynamic_loader (void)
     {
       return m_dynamic_loader;
@@ -166,6 +189,11 @@
       return m_load_path;
     }
 
+    load_save_system& get_load_save_system (void)
+    {
+      return m_load_save_system;
+    }
+
     symbol_table& get_symbol_table (void)
     {
       return m_symbol_table;
@@ -179,11 +207,6 @@
     symbol_scope get_current_scope (void);
     symbol_scope require_current_scope (const std::string& who);
 
-    bp_table& get_bp_table (void)
-    {
-      return m_bp_table;
-    }
-
     call_stack& get_call_stack (void);
 
     profiler& get_profiler (void);
@@ -215,6 +238,15 @@
 
     bool mislocked (const std::string& nm);
 
+    octave_value_list eval_string (const std::string& eval_str, bool silent,
+                                   int& parse_status, int nargout);
+
+    octave_value eval_string (const std::string& eval_str, bool silent,
+                              int& parse_status);
+
+    octave_value_list eval_string (const octave_value& arg, bool silent,
+                                   int& parse_status, int nargout);
+
     static void recover_from_exception (void);
 
     static void add_atexit_function (const std::string& fname);
@@ -253,20 +285,28 @@
 
     environment m_environment;
 
+    settings m_settings;
+
     help_system m_help_system;
 
+    input_system m_input_system;
+
+    output_system m_output_system;
+
+    history_system m_history_system;
+
     dynamic_loader m_dynamic_loader;
 
     load_path m_load_path;
 
+    load_save_system m_load_save_system;
+
     type_info m_type_info;
 
     symbol_table m_symbol_table;
 
     tree_evaluator m_evaluator;
 
-    bp_table m_bp_table;
-
     stream_list m_stream_list;
 
     child_list m_child_list;
@@ -295,6 +335,8 @@
     bool m_initialized;
 
     void maximum_braindamage (void);
+
+    void execute_pkg_add (const std::string& dir);
   };
 }
 
--- a/libinterp/corefcn/kron.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/kron.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -64,13 +64,17 @@
   T *cv = c.fortran_vec ();
 
   for (octave_idx_type ja = 0; ja < nca; ja++)
-    for (octave_idx_type jb = 0; jb < ncb; jb++)
-      for (octave_idx_type ia = 0; ia < nra; ia++)
+    {
+      octave_quit ();
+      for (octave_idx_type jb = 0; jb < ncb; jb++)
         {
-          octave_quit ();
-          mx_inline_mul (nrb, cv, a(ia, ja), b.data () + nrb*jb);
-          cv += nrb;
+          for (octave_idx_type ia = 0; ia < nra; ia++)
+            {
+              mx_inline_mul (nrb, cv, a(ia, ja), b.data () + nrb*jb);
+              cv += nrb;
+            }
         }
+    }
 
   return c;
 }
@@ -90,12 +94,14 @@
   MArray<T> c (dim_vector (nra*nrb, nca*ncb), T ());
 
   for (octave_idx_type ja = 0; ja < dla; ja++)
-    for (octave_idx_type jb = 0; jb < ncb; jb++)
-      {
-        octave_quit ();
-        mx_inline_mul (nrb, &c.xelem (ja*nrb, ja*ncb + jb), a.dgelem (ja),
-                       b.data () + nrb*jb);
-      }
+    {
+      octave_quit ();
+      for (octave_idx_type jb = 0; jb < ncb; jb++)
+        {
+          mx_inline_mul (nrb, &c.xelem (ja*nrb, ja*ncb + jb), a.dgelem (ja),
+                         b.data () + nrb*jb);
+        }
+    }
 
   return c;
 }
@@ -111,22 +117,24 @@
   C.cidx (0) = 0;
 
   for (octave_idx_type Aj = 0; Aj < A.columns (); Aj++)
-    for (octave_idx_type Bj = 0; Bj < B.columns (); Bj++)
-      {
-        octave_quit ();
-        for (octave_idx_type Ai = A.cidx (Aj); Ai < A.cidx (Aj+1); Ai++)
-          {
-            octave_idx_type Ci = A.ridx (Ai) * B.rows ();
-            const T v = A.data (Ai);
+    {
+      octave_quit ();
+      for (octave_idx_type Bj = 0; Bj < B.columns (); Bj++)
+        {
+          for (octave_idx_type Ai = A.cidx (Aj); Ai < A.cidx (Aj+1); Ai++)
+            {
+              octave_idx_type Ci = A.ridx (Ai) * B.rows ();
+              const T v = A.data (Ai);
 
-            for (octave_idx_type Bi = B.cidx (Bj); Bi < B.cidx (Bj+1); Bi++)
-              {
-                C.data (idx) = v * B.data (Bi);
-                C.ridx (idx++) = Ci + B.ridx (Bi);
-              }
-          }
-        C.cidx (Aj * B.columns () + Bj + 1) = idx;
-      }
+              for (octave_idx_type Bi = B.cidx (Bj); Bi < B.cidx (Bj+1); Bi++)
+                {
+                  C.data (idx) = v * B.data (Bi);
+                  C.ridx (idx++) = Ci + B.ridx (Bi);
+                }
+            }
+          C.cidx (Aj * B.columns () + Bj + 1) = idx;
+        }
+    }
 
   return C;
 }
--- a/libinterp/corefcn/load-path.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/load-path.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -42,6 +42,7 @@
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
+#include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
 
@@ -148,23 +149,6 @@
   return retval;
 }
 
-static void
-execute_pkg_add_or_del (const std::string& dir,
-                        const std::string& script_file)
-{
-  if (! octave_interpreter_ready)
-    return;
-
-  octave::unwind_protect frame;
-
-  std::string file = octave::sys::file_ops::concat (dir, script_file);
-
-  octave::sys::file_stat fs (file);
-
-  if (fs.exists ())
-    octave::source_file (file, "base");
-}
-
 // True if a path is contained in a path list separated by path_sep_char
 
 static bool
@@ -205,6 +189,13 @@
   std::string load_path::sys_path;
   load_path::abs_dir_cache_type load_path::abs_dir_cache;
 
+  load_path::load_path (void)
+    : 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); })
+  { }
+
   void
   load_path::initialize (bool set_initial_path)
   {
@@ -338,7 +329,7 @@
 
             dir = strip_trailing_separators (dir);
 
-            dir_info_list_iterator i = find_dir_info (dir);
+            auto i = find_dir_info (dir);
 
             if (i != dir_info_list.end ())
               {
@@ -372,9 +363,13 @@
 
     for (auto& di : dir_info_list)
       {
-        di.update ();
-
-        add (di, true, "", true);
+        bool ok = di.update ();
+
+        if (! ok)
+          warning ("load-path: update failed for '%s', removing from path",
+                   di.dir_name.c_str ());
+        else
+          add (di, true, "", true);
       }
   }
 
@@ -845,6 +840,22 @@
     execute_pkg_add_or_del (dir, "PKG_DEL");
   }
 
+  void load_path::execute_pkg_add_or_del (const std::string& dir,
+                                          const std::string& script_file)
+  {
+    if (! octave_interpreter_ready)
+      return;
+
+    octave::unwind_protect frame;
+
+    std::string file = octave::sys::file_ops::concat (dir, script_file);
+
+    octave::sys::file_stat fs (file);
+
+    if (fs.exists ())
+      octave::source_file (file, "base");
+  }
+
   // FIXME: maybe we should also maintain a map to speed up this method of access.
 
   load_path::const_dir_info_list_iterator
@@ -852,9 +863,9 @@
   {
     std::string dir = sys::file_ops::tilde_expand (dir_arg);
 
-    const_dir_info_list_iterator retval = dir_info_list.begin ();
-
-    while (retval != dir_info_list.end ())
+    auto retval = dir_info_list.cbegin ();
+
+    while (retval != dir_info_list.cend ())
       {
         if (retval->dir_name == dir)
           break;
@@ -870,7 +881,7 @@
   {
     std::string dir = sys::file_ops::tilde_expand (dir_arg);
 
-    dir_info_list_iterator retval = dir_info_list.begin ();
+    auto retval = dir_info_list.begin ();
 
     while (retval != dir_info_list.end ())
       {
@@ -940,7 +951,7 @@
 
     dir = strip_trailing_separators (dir);
 
-    dir_info_list_iterator i = find_dir_info (dir);
+    auto i = find_dir_info (dir);
 
     if (i != dir_info_list.end ())
       move (i, at_end);
@@ -1068,12 +1079,13 @@
   {
     load_path::dir_info::fcn_file_map_type retval;
 
-    sys::dir_entry dir (d);
-
-    if (dir)
+    string_vector flist;
+    std::string msg;
+
+    if (! octave::sys::get_dirlist (d, flist, msg))
+      warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
+    else
       {
-        string_vector flist = dir.read ();
-
         octave_idx_type len = flist.numel ();
 
         for (octave_idx_type i = 0; i < len; i++)
@@ -1112,87 +1124,83 @@
               }
           }
       }
-    else
-      {
-        std::string msg = dir.error ();
-        warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
-      }
 
     return retval;
   }
 
-  void
+  bool
   load_path::dir_info::update (void)
   {
     sys::file_stat fs (dir_name);
 
-    sys::file_stat pfs (sys::file_ops::concat (dir_name, "private"));
-    bool has_private_dir = pfs && pfs.is_dir ();
-
     if (! fs)
       {
         std::string msg = fs.error ();
         warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
+        return false;
       }
-    else
+
+    sys::file_stat pfs (sys::file_ops::concat (dir_name, "private"));
+    bool has_private_dir = pfs && pfs.is_dir ();
+
+    if (is_relative)
       {
-        if (is_relative)
+        try
           {
-            try
+            std::string abs_name = sys::env::make_absolute (dir_name);
+
+            const_abs_dir_cache_iterator p = abs_dir_cache.find (abs_name);
+
+            if (p != abs_dir_cache.end ())
               {
-                std::string abs_name = sys::env::make_absolute (dir_name);
-
-                const_abs_dir_cache_iterator p = abs_dir_cache.find (abs_name);
-
-                if (p != abs_dir_cache.end ())
-                  {
-                    // The directory is in the cache of all directories we have
-                    // visited (indexed by absolute name).  If it is out of date,
-                    // initialize it.  Otherwise, copy the info from the cache.
-                    // By doing that, we avoid unnecessary calls to stat that can
-                    // slow things down tremendously for large directories.
-                    const dir_info& di = p->second;
-
-                    if ((fs.mtime () + fs.time_resolution ()
-                         > di.dir_time_last_checked)
-                        || (has_private_dir
-                            && (pfs.mtime () + pfs.time_resolution ()
-                                > dir_time_last_checked)))
-                      initialize ();
-                    else
-                      {
-                        // Copy over info from cache, but leave dir_name and
-                        // is_relative unmodified.
-                        this->abs_dir_name = di.abs_dir_name;
-                        this->dir_mtime = di.dir_mtime;
-                        this->dir_time_last_checked = di.dir_time_last_checked;
-                        this->all_files = di.all_files;
-                        this->fcn_files = di.fcn_files;
-                        this->private_file_map = di.private_file_map;
-                        this->method_file_map = di.method_file_map;
-                        this->package_dir_map = di.package_dir_map;
-                      }
-                  }
+                // The directory is in the cache of all directories we have
+                // visited (indexed by absolute name).  If it is out of date,
+                // initialize it.  Otherwise, copy the info from the cache.
+                // By doing that, we avoid unnecessary calls to stat that can
+                // slow things down tremendously for large directories.
+                const dir_info& di = p->second;
+
+                if ((fs.mtime () + fs.time_resolution ()
+                     > di.dir_time_last_checked)
+                    || (has_private_dir
+                        && (pfs.mtime () + pfs.time_resolution ()
+                            > dir_time_last_checked)))
+                  initialize ();
                 else
                   {
-                    // We haven't seen this directory before.
-                    initialize ();
+                    // Copy over info from cache, but leave dir_name and
+                    // is_relative unmodified.
+                    abs_dir_name = di.abs_dir_name;
+                    dir_mtime = di.dir_mtime;
+                    dir_time_last_checked = di.dir_time_last_checked;
+                    all_files = di.all_files;
+                    fcn_files = di.fcn_files;
+                    private_file_map = di.private_file_map;
+                    method_file_map = di.method_file_map;
+                    package_dir_map = di.package_dir_map;
                   }
               }
-            catch (const execution_exception&)
+            else
               {
-                // Skip updating if we don't know where we are,
-                // but don't treat it as an error.
-                interpreter::recover_from_exception ();
+                // We haven't seen this directory before.
+                initialize ();
               }
           }
-        // Absolute path, check timestamp to see whether it requires re-caching
-        else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked
-                 || (has_private_dir
-                     && (pfs.mtime () + pfs.time_resolution ()
-                         > dir_time_last_checked)))
-          initialize ();
+        catch (const execution_exception&)
+          {
+            // Skip updating if we don't know where we are,
+            // but don't treat it as an error.
+            interpreter::recover_from_exception ();
+          }
       }
+    // Absolute path, check timestamp to see whether it requires re-caching
+    else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked
+             || (has_private_dir
+                 && (pfs.mtime () + pfs.time_resolution ()
+                     > dir_time_last_checked)))
+      initialize ();
+
+    return true;
   }
 
   bool
@@ -1360,8 +1368,7 @@
   {
     std::string dir_name = di.dir_name;
 
-    std::list<std::string>::iterator s =
-      std::find (dir_list.begin (), dir_list.end (), dir_name);
+    auto s = std::find (dir_list.begin (), dir_list.end (), dir_name);
 
     if (s != dir_list.end ())
       {
@@ -1673,7 +1680,7 @@
 
         file_info_list_type& file_info_list = fcn_map[base];
 
-        file_info_list_iterator p = file_info_list.begin ();
+        auto p = file_info_list.begin ();
 
         while (p != file_info_list.end ())
           {
@@ -1790,7 +1797,7 @@
 
             file_info_list_type& file_info_list = fm[base];
 
-            file_info_list_iterator p2 = file_info_list.begin ();
+            auto p2 = file_info_list.begin ();
             while (p2 != file_info_list.end ())
               {
                 if (p2->dir_name == full_dir_name)
@@ -1960,7 +1967,7 @@
   void
   load_path::package_info::remove_private_fcn_map (const std::string& dir)
   {
-    private_fcn_map_iterator p = private_fcn_map.find (dir);
+    auto p = private_fcn_map.find (dir);
 
     if (p != private_fcn_map.end ())
       private_fcn_map.erase (p);
@@ -2146,42 +2153,42 @@
   genpath (const std::string& dirname, const string_vector& skip)
   {
     std::string retval;
-
-    sys::dir_entry dir (dirname);
-
-    if (dir)
-      {
-        retval = dirname;
-
-        string_vector dirlist = dir.read ().sort (false);
-
-        octave_idx_type len = dirlist.numel ();
-
-        for (octave_idx_type i = 0; i < len; i++)
-          {
-            std::string elt = dirlist[i];
-
-            bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
-                           || elt[0] == '+');
+  string_vector dirlist;
+  std::string msg;
+
+  if (! sys::get_dirlist (dirname, dirlist, msg))
+    return retval;
+
+  retval = dirname;
+
+  dirlist = dirlist.sort (false);
+
+  octave_idx_type len = dirlist.numel ();
+
+  for (octave_idx_type i = 0; i < len; i++)
+    {
+      std::string elt = dirlist[i];
+
+      bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
+                     || elt[0] == '+');
+
+      if (! skip_p)
+        {
+          for (octave_idx_type j = 0; j < skip.numel (); j++)
+            {
+              skip_p = (elt == skip[j]);
+              if (skip_p)
+                break;
+            }
 
             if (! skip_p)
               {
-                for (octave_idx_type j = 0; j < skip.numel (); j++)
-                  {
-                    skip_p = (elt == skip[j]);
-                    if (skip_p)
-                      break;
-                  }
-
-                if (! skip_p)
-                  {
-                    std::string nm = sys::file_ops::concat (dirname, elt);
-
-                    sys::file_stat fs (nm);
-
-                    if (fs && fs.is_dir ())
-                      retval += directory_path::path_sep_str () + genpath (nm, skip);
-                  }
+                std::string nm = sys::file_ops::concat (dirname, elt);
+
+                sys::file_stat fs (nm);
+
+                if (fs && fs.is_dir ())
+                  retval += directory_path::path_sep_str () + genpath (nm, skip);
               }
           }
       }
@@ -2439,7 +2446,7 @@
       for (auto dir : dir_elts)
         {
           // Remove duplicate directory separators
-          std::string::iterator it_start = dir.begin ();
+          auto it_start = dir.begin ();
 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
           // In Windows, start check at second character (for UNC paths).
           it_start++;
--- a/libinterp/corefcn/load-path.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/load-path.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
 
 #include "octave-config.h"
 
+#include <functional>
 #include <iosfwd>
 #include <list>
 #include <map>
@@ -44,11 +45,7 @@
   {
   public:
 
-    load_path (void)
-      : package_map (), top_level_package (), dir_info_list (), init_dirs (),
-        m_command_line_path (), add_hook (load_path::execute_pkg_add),
-        remove_hook (load_path::execute_pkg_del)
-    { }
+    load_path (void);
 
     typedef void (*hook_fcn_ptr) (const std::string& dir);
 
@@ -169,14 +166,28 @@
 
     void display (std::ostream& os) const;
 
-    hook_fcn_ptr get_add_hook (void) { return add_hook; }
-    hook_fcn_ptr get_remove_hook (void) { return remove_hook; }
+    std::function<void (const std::string&)> get_add_hook (void)
+    {
+      return add_hook;
+    }
+
+    std::function<void (const std::string&)> get_remove_hook (void)
+    {
+      return remove_hook;
+    }
 
-    void set_add_hook (hook_fcn_ptr f) { add_hook = f; }
-    void set_remove_hook (hook_fcn_ptr f) { remove_hook = f; }
+    void set_add_hook (const std::function<void (const std::string&)>& f)
+    {
+      add_hook = f;
+    }
 
-    static void execute_pkg_add (const std::string& dir);
-    static void execute_pkg_del (const std::string& dir);
+    void set_remove_hook (const std::function<void (const std::string&)>& f)
+    {
+      remove_hook = f;
+    }
+
+    void execute_pkg_add (const std::string& dir);
+    void execute_pkg_del (const std::string& dir);
 
     void set_command_line_path (const std::string& p)
     {
@@ -265,7 +276,7 @@
 
       dir_info& operator = (const dir_info&) = default;
 
-      void update (void);
+      bool update (void);
 
       std::string dir_name;
       std::string abs_dir_name;
@@ -510,9 +521,12 @@
 
     static abs_dir_cache_type abs_dir_cache;
 
-    hook_fcn_ptr add_hook;
+    std::function<void (const std::string&)> add_hook;
 
-    hook_fcn_ptr remove_hook;
+    std::function<void (const std::string&)> remove_hook;
+
+    void execute_pkg_add_or_del (const std::string& dir,
+                                 const std::string& script_file);
 
     const_dir_info_list_iterator find_dir_info (const std::string& dir) const;
     dir_info_list_iterator find_dir_info (const std::string& dir);
--- a/libinterp/corefcn/load-save.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/load-save.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -56,6 +56,7 @@
 #include "defun.h"
 #include "error.h"
 #include "errwarn.h"
+#include "interpreter.h"
 #include "interpreter-private.h"
 #include "load-path.h"
 #include "load-save.h"
@@ -64,7 +65,7 @@
 #include "oct-map.h"
 #include "ov-cell.h"
 #include "pager.h"
-#include "pt-exp.h"
+#include "syminfo.h"
 #include "symtab.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
@@ -91,459 +92,1486 @@
 #  include "zfstream.h"
 #endif
 
-// Write octave-workspace file if Octave crashes or is killed by a signal.
-static bool Vcrash_dumps_octave_core = true;
-
-// The maximum amount of memory (in kilobytes) that we will attempt to
-// write to the Octave core file.
-static double Voctave_core_file_limit = -1.0;
-
-// The name of the Octave core file.
-static std::string Voctave_core_file_name = "octave-workspace";
-
-// The default output format.  May be one of "binary", "text",
-// "mat-binary", or "hdf5".
-static std::string Vsave_default_options = "-text";
-
-// The output format for Octave core files.
-static std::string Voctave_core_file_options = "-binary";
-
-static std::string
-default_save_header_format (void)
+namespace octave
 {
-  return
-    std::string ("# Created by Octave " OCTAVE_VERSION
-                 ", %a %b %d %H:%M:%S %Y %Z <")
-    + octave::sys::env::get_user_name ()
-    + '@'
-    + octave::sys::env::get_host_name ()
-    + '>';
-}
+  OCTAVE_NORETURN static
+  void
+  err_file_open (const std::string& fcn, const std::string& file)
+  {
+    if (fcn == "load")
+      error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
+    else if (fcn == "save")
+      error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
+    else
+      error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
+  }
 
-// The format string for the comment line at the top of text-format
-// save files.  Passed to strftime.  Should begin with '#' and contain
-// no newline characters.
-static std::string Vsave_header_format_string = default_save_header_format ();
-
-OCTAVE_NORETURN static
-void
-err_file_open (const std::string& fcn, const std::string& file)
-{
-  if (fcn == "load")
-    error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
-  else if (fcn == "save")
-    error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
-  else
-    error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
-}
+  // Return TRUE if NAME matches one of the given globbing PATTERNS.
 
-// Install a variable with name NAME and the value VAL in the
-// symbol table.  If GLOBAL is TRUE, make the variable global.
+  static bool
+  matches_patterns (const string_vector& patterns, int pat_idx,
+                    int num_pat, const std::string& name)
+  {
+    for (int i = pat_idx; i < num_pat; i++)
+      {
+        glob_match pattern (patterns[i]);
 
-static void
-install_loaded_variable (const std::string& name,
-                         const octave_value& val,
-                         bool global, const std::string& /*doc*/)
-{
-  octave::symbol_table& symtab
-    = octave::__get_symbol_table__ ("install_loaded_variable");
+        if (pattern.match (name))
+          return true;
+      }
 
-  octave::symbol_scope scope
-    = symtab.require_current_scope ("install_loaded_variable");
-
-  if (global)
-    {
-      octave::symbol_record sym = scope.find_symbol (name);
+    return false;
+  }
 
-      if (! sym.is_global ())
-        {
-          octave::symbol_scope global_scope = symtab.global_scope ();
-          octave::symbol_record global_sym = global_scope.find_symbol (name);
-
-          sym.bind_fwd_rep (global_scope.get_rep (), global_sym);
-        }
-    }
-
-  scope.assign (name, val);
-}
-
-// Return TRUE if NAME matches one of the given globbing PATTERNS.
+  static int
+  read_binary_file_header (std::istream& is, bool& swap,
+                           mach_info::float_format& flt_fmt,
+                           bool quiet = false)
+  {
+    const int magic_len = 10;
+    char magic[magic_len+1];
+    is.read (magic, magic_len);
+    magic[magic_len] = '\0';
 
-static bool
-matches_patterns (const string_vector& patterns, int pat_idx,
-                  int num_pat, const std::string& name)
-{
-  for (int i = pat_idx; i < num_pat; i++)
-    {
-      glob_match pattern (patterns[i]);
-
-      if (pattern.match (name))
-        return true;
-    }
-
-  return false;
-}
+    if (strncmp (magic, "Octave-1-L", magic_len) == 0)
+      swap = mach_info::words_big_endian ();
+    else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
+      swap = ! mach_info::words_big_endian ();
+    else
+      {
+        if (! quiet)
+          error ("load: unable to read binary file");
 
-int
-read_binary_file_header (std::istream& is, bool& swap,
-                         octave::mach_info::float_format& flt_fmt, bool quiet)
-{
-  const int magic_len = 10;
-  char magic[magic_len+1];
-  is.read (magic, magic_len);
-  magic[magic_len] = '\0';
+        return -1;
+      }
 
-  if (strncmp (magic, "Octave-1-L", magic_len) == 0)
-    swap = octave::mach_info::words_big_endian ();
-  else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
-    swap = ! octave::mach_info::words_big_endian ();
-  else
-    {
-      if (! quiet)
-        error ("load: unable to read binary file");
+    char tmp = 0;
+    is.read (&tmp, 1);
+
+    flt_fmt = mopt_digit_to_float_format (tmp);
 
-      return -1;
-    }
-
-  char tmp = 0;
-  is.read (&tmp, 1);
-
-  flt_fmt = mopt_digit_to_float_format (tmp);
+    if (flt_fmt == mach_info::flt_fmt_unknown)
+      {
+        if (! quiet)
+          error ("load: unrecognized binary format!");
 
-  if (flt_fmt == octave::mach_info::flt_fmt_unknown)
-    {
-      if (! quiet)
-        error ("load: unrecognized binary format!");
+        return -1;
+      }
 
-      return -1;
-    }
-
-  return 0;
-}
+    return 0;
+  }
 
 #if defined (HAVE_ZLIB)
-static bool
-check_gzip_magic (const std::string& fname)
-{
-  bool retval = false;
+  static bool
+  check_gzip_magic (const std::string& fname)
+  {
+    bool retval = false;
 
-  std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+    std::string ascii_fname = sys::get_ASCII_filename (fname);
+
+    std::ifstream file (ascii_fname.c_str (),
+                        std::ios::in | std::ios::binary);
 
-  unsigned char magic[2];
-  if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
-      && magic[0] == 0x1f && magic[1] == 0x8b)
-    retval = true;
+    unsigned char magic[2];
+    if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
+        && magic[0] == 0x1f && magic[1] == 0x8b)
+      retval = true;
 
-  file.close ();
+    file.close ();
 
-  return retval;
-}
+    return retval;
+  }
 #endif
 
-static load_save_format
-get_file_format (std::istream& file, const std::string& filename)
-{
-  load_save_format retval = LS_UNKNOWN;
+  static std::string
+  find_file_to_load (const std::string& name, const std::string& orig_name)
+  {
+    std::string fname = find_data_file_in_load_path ("load", name, true);
+
+    size_t dot_pos = fname.rfind ('.');
+    size_t sep_pos = fname.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    if (dot_pos == std::string::npos
+        || (sep_pos != std::string::npos && dot_pos < sep_pos))
+      {
+        // Either no '.' in name or no '.' appears after last directory
+        // separator.
+
+        sys::file_stat fs (fname);
 
-  octave::mach_info::float_format flt_fmt = octave::mach_info::flt_fmt_unknown;
+        if (! (fs.exists () && fs.is_reg ()))
+          fname = find_file_to_load (fname + ".mat", orig_name);
+      }
+    else
+      {
+        sys::file_stat fs (fname);
 
-  bool swap = false;
+        if (! (fs.exists () && fs.is_reg ()))
+          {
+            fname = "";
+
+            error ("load: unable to find file %s", orig_name.c_str ());
+          }
+      }
+
+    return fname;
+  }
+
+  // Return TRUE if PATTERN has any special globbing chars in it.
 
-  if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
-    retval = LS_BINARY;
-  else
-    {
-      file.clear ();
-      file.seekg (0, std::ios::beg);
+  static bool
+  glob_pattern_p (const std::string& pattern)
+  {
+    int open = 0;
+
+    int len = pattern.length ();
 
-      int32_t mopt, nr, nc, imag, len;
+    for (int i = 0; i < len; i++)
+      {
+        char c = pattern[i];
+
+        switch (c)
+          {
+          case '?':
+          case '*':
+            return true;
 
-      int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
-                                      true);
+          case '[':       // Only accept an open brace if there is a close
+            open++;       // brace to match it.  Bracket expressions must be
+            continue;     // complete, according to Posix.2
+
+          case ']':
+            if (open)
+              return true;
+            continue;
 
-      if (! err)
-        retval = LS_MAT_BINARY;
-      else
-        {
-          file.clear ();
-          file.seekg (0, std::ios::beg);
+          case '\\':
+            if (i == len - 1)
+              return false;
+            continue;
 
-          err = read_mat5_binary_file_header (file, swap, true, filename);
+          default:
+            continue;
+          }
+      }
+
+    return false;
+  }
 
-          if (! err)
-            {
-              file.clear ();
-              file.seekg (0, std::ios::beg);
-              retval = LS_MAT5_BINARY;
-            }
-          else
-            {
-              file.clear ();
-              file.seekg (0, std::ios::beg);
+  load_save_system::load_save_system (interpreter& interp)
+    : m_interpreter (interp),
+      m_crash_dumps_octave_core (true),
+      m_octave_core_file_limit (-1.0),
+      m_octave_core_file_name ("octave-workspace"),
+      m_save_default_options ("-text"),
+      m_octave_core_file_options ("-binary"),
+      m_save_header_format_string (init_save_header_format ())
+  {
+#if defined (HAVE_HDF5)
+    H5dont_atexit ();
+#endif
+  }
 
-              std::string name_val = extract_keyword (file, "name");
-              std::string type_val = extract_keyword (file, "type");
+  load_save_system::~load_save_system (void)
+  {
+#if defined (HAVE_HDF5)
+    H5close ();
+#endif
+  }
 
-              if (name_val.empty () != true && type_val.empty () != true)
-                retval = LS_TEXT;
-              else
-                {
-                  file.clear ();
-                  file.seekg (0, std::ios::beg);
+  octave_value
+  load_save_system::crash_dumps_octave_core (const octave_value_list& args,
+                                             int nargout)
+  {
+    return set_internal_variable (m_crash_dumps_octave_core, args, nargout,
+                                  "crash_dumps_octave_core");
+  }
+
+  octave_value
+  load_save_system::octave_core_file_limit (const octave_value_list& args,
+                                            int nargout)
+  {
+    return set_internal_variable (m_octave_core_file_limit, args, nargout,
+                                  "octave_core_file_limit");
+  }
 
-                  // FIXME: looks_like_mat_ascii_file does not check to see
-                  // whether the file contains numbers.  It just skips comments
-                  // and checks for the same number of words on each line.  We
-                  // may need a better check here.  The best way to do that
-                  // might be just to try to read the file and see if it works.
+  octave_value
+  load_save_system::octave_core_file_name (const octave_value_list& args,
+                                           int nargout)
+  {
+    return set_internal_variable (m_octave_core_file_name, args, nargout,
+                                  "octave_core_file_name", false);
+  }
+
+  octave_value
+  load_save_system::save_default_options (const octave_value_list& args,
+                                          int nargout)
+  {
+    return set_internal_variable (m_save_default_options, args, nargout,
+                                  "save_default_options", false);
+  }
 
-                  if (looks_like_mat_ascii_file (file, filename))
-                    retval = LS_MAT_ASCII;
-                }
-            }
-        }
-    }
+  octave_value
+  load_save_system::octave_core_file_options (const octave_value_list& args,
+                                              int nargout)
+  {
+    return set_internal_variable (m_octave_core_file_options, args, nargout,
+                                  "octave_core_file_options", false);
+  }
 
-  return retval;
-}
+  octave_value
+  load_save_system::save_header_format_string (const octave_value_list& args,
+                                               int nargout)
+  {
+    return set_internal_variable (m_save_header_format_string, args, nargout,
+                                  "save_header_format_string");
+  }
 
-static load_save_format
-get_file_format (const std::string& fname, const std::string& orig_fname,
-                 bool& use_zlib, bool quiet = false)
-{
-  load_save_format retval = LS_UNKNOWN;
+  load_save_format
+  load_save_system::get_file_format (const std::string& fname,
+                                     const std::string& orig_fname,
+                                     bool& use_zlib, bool quiet)
+  {
+    load_save_format retval = UNKNOWN;
+
+    std::string ascii_fname = sys::get_ASCII_filename (fname);
 
 #if defined (HAVE_HDF5)
-  // check this before we open the file
-  if (H5Fis_hdf5 (fname.c_str ()) > 0)
-    return LS_HDF5;
+    // check this before we open the file
+    if (H5Fis_hdf5 (ascii_fname.c_str ()) > 0)
+      return HDF5;
 #endif
 
 #if defined (HAVE_ZLIB)
-  use_zlib = check_gzip_magic (fname);
+    use_zlib = check_gzip_magic (fname);
 #else
-  use_zlib = false;
+    use_zlib = false;
+#endif
+
+    if (! use_zlib)
+      {
+        std::ifstream file (ascii_fname.c_str (),
+                            std::ios::in | std::ios::binary);
+        if (file)
+          {
+            retval = get_file_format (file, orig_fname);
+            file.close ();
+          }
+        else if (! quiet)
+          err_file_open ("load", orig_fname);
+      }
+#if defined (HAVE_ZLIB)
+    else
+      {
+        gzifstream gzfile (fname.c_str (), std::ios::in | std::ios::binary);
+        if (gzfile)
+          {
+            retval = get_file_format (gzfile, orig_fname);
+            gzfile.close ();
+          }
+        else if (! quiet)
+          err_file_open ("load", orig_fname);
+      }
+#endif
+
+    return retval;
+  }
+
+  octave_value
+  load_save_system::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)
+  {
+    octave_value retval;
+
+    octave_scalar_map retstruct;
+
+    std::ostringstream output_buf;
+    std::list<std::string> symbol_names;
+
+    octave_idx_type count = 0;
+
+    for (;;)
+      {
+        bool global = false;
+        octave_value tc;
+
+        std::string name;
+        std::string doc;
+
+        switch (fmt.type ())
+          {
+          case TEXT:
+            name = read_text_data (stream, orig_fname, global, tc, count);
+            break;
+
+          case BINARY:
+            name = read_binary_data (stream, swap, flt_fmt, orig_fname,
+                                     global, tc, doc);
+            break;
+
+          case MAT_ASCII:
+            name = read_mat_ascii_data (stream, orig_fname, tc);
+            break;
+
+          case MAT_BINARY:
+            name = read_mat_binary_data (stream, orig_fname, tc);
+            break;
+
+#if defined (HAVE_HDF5)
+          case HDF5:
+            name = read_hdf5_data (stream, orig_fname, global, tc, doc,
+                                   argv, argv_idx, argc);
+            break;
 #endif
 
-  if (! use_zlib)
-    {
-      std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
-      if (file)
-        {
-          retval = get_file_format (file, orig_fname);
-          file.close ();
-        }
-      else if (! quiet)
-        err_file_open ("load", orig_fname);
-    }
-#if defined (HAVE_ZLIB)
-  else
-    {
-      gzifstream gzfile (fname.c_str (), std::ios::in | std::ios::binary);
-      if (gzfile)
-        {
-          retval = get_file_format (gzfile, orig_fname);
-          gzfile.close ();
-        }
-      else if (! quiet)
-        err_file_open ("load", orig_fname);
-    }
+          case MAT5_BINARY:
+          case MAT7_BINARY:
+            name = read_mat5_binary_element (stream, orig_fname, swap,
+                                             global, tc);
+            break;
+
+          default:
+            err_unrecognized_data_fmt ("load");
+            break;
+          }
+
+        if (stream.eof () || name.empty ())
+          break;
+        else
+          {
+            if (! tc.is_defined ())
+              error ("load: unable to load variable '%s'", name.c_str ());
+
+            if (fmt.type () == MAT_ASCII && argv_idx < argc)
+              warning ("load: loaded ASCII file '%s' -- ignoring extra args",
+                       orig_fname.c_str ());
+
+            if (fmt.type () == MAT_ASCII
+                || argv_idx == argc
+                || matches_patterns (argv, argv_idx, argc, name))
+              {
+                count++;
+                if (list_only)
+                  {
+                    if (verbose)
+                      {
+                        if (count == 1)
+                          output_buf
+                            << "type               rows   cols   name\n"
+                            << "====               ====   ====   ====\n";
+
+                        output_buf
+                          << std::setiosflags (std::ios::left)
+                          << std::setw (16) << tc.type_name ().c_str ()
+                          << std::setiosflags (std::ios::right)
+                          << std::setw (7) << tc.rows ()
+                          << std::setw (7) << tc.columns ()
+                          << "   " << name << "\n";
+                      }
+                    else
+                      symbol_names.push_back (name);
+                  }
+                else
+                  {
+                    if (nargout == 1)
+                      {
+                        if (fmt.type () == MAT_ASCII)
+                          retval = tc;
+                        else
+                          retstruct.assign (name, tc);
+                      }
+                    else
+                      install_loaded_variable (name, tc, global, doc);
+                  }
+              }
+
+            // Only attempt to read one item from a headless text file.
+
+            if (fmt.type () == MAT_ASCII)
+              break;
+          }
+      }
+
+    if (list_only && count)
+      {
+        if (verbose)
+          {
+            std::string msg = output_buf.str ();
+
+            if (nargout > 0)
+              retval = msg;
+            else
+              octave_stdout << msg;
+          }
+        else
+          {
+            if (nargout  > 0)
+              retval = Cell (string_vector (symbol_names));
+            else
+              {
+                string_vector names (symbol_names);
+
+                names.list_in_columns (octave_stdout);
+
+                octave_stdout << "\n";
+              }
+          }
+      }
+    else if (retstruct.nfields () != 0)
+      retval = retstruct;
+
+    return retval;
+  }
+
+  string_vector
+  load_save_system::parse_save_options (const string_vector& argv,
+                                        load_save_format& fmt, bool& append,
+                                        bool& save_as_floats, bool& use_zlib)
+  {
+#if ! defined (HAVE_ZLIB)
+    octave_unused_parameter (use_zlib);
 #endif
 
-  return retval;
-}
+    string_vector retval;
+    int argc = argv.numel ();
+
+    bool do_double = false;
+    bool do_tabs = false;
 
-octave_value
-do_load (std::istream& stream, const std::string& orig_fname,
-         load_save_format format, octave::mach_info::float_format flt_fmt,
-         bool list_only, bool swap, bool verbose,
-         const string_vector& argv, int argv_idx, int argc, int nargout)
-{
-  octave_value retval;
+    for (int i = 0; i < argc; i++)
+      {
+        if (argv[i] == "-append")
+          {
+            append = true;
+          }
+        else if (argv[i] == "-ascii" || argv[i] == "-a")
+          {
+            fmt.set_type (MAT_ASCII);
+          }
+        else if (argv[i] == "-double")
+          {
+            do_double = true;
+          }
+        else if (argv[i] == "-tabs")
+          {
+            do_tabs = true;
+          }
+        else if (argv[i] == "-text" || argv[i] == "-t")
+          {
+            fmt.set_type (TEXT);
+          }
+        else if (argv[i] == "-binary" || argv[i] == "-b")
+          {
+            fmt.set_type (BINARY);
+          }
+        else if (argv[i] == "-hdf5" || argv[i] == "-h")
+          {
+#if defined (HAVE_HDF5)
+            fmt.set_type (HDF5);
+#else
+            err_disabled_feature ("save", "HDF5");
+#endif
+          }
+        else if (argv[i] == "-mat-binary" || argv[i] == "-mat"
+                 || argv[i] == "-m" || argv[i] == "-6" || argv[i] == "-v6"
+                 || argv[i] == "-V6")
+          {
+            fmt.set_type (MAT5_BINARY);
+          }
+#if defined (HAVE_ZLIB)
+        else if (argv[i] == "-mat7-binary" || argv[i] == "-7"
+                 || argv[i] == "-v7" || argv[i] == "-V7")
+          {
+            fmt.set_type (MAT7_BINARY);
+          }
+#endif
+        else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
+                 || argv[i] == "-v4" || argv[i] == "-4")
+          {
+            fmt.set_type (MAT_BINARY);
+          }
+        else if (argv[i] == "-float-binary" || argv[i] == "-f")
+          {
+            fmt.set_type (BINARY);
+            save_as_floats = true;
+          }
+        else if (argv[i] == "-float-hdf5")
+          {
+#if defined (HAVE_HDF5)
+            fmt.set_type (HDF5);
+            save_as_floats = true;
+#else
+            err_disabled_feature ("save", "HDF5");
+#endif
+          }
+#if defined (HAVE_ZLIB)
+        else if (argv[i] == "-zip" || argv[i] == "-z")
+          {
+            use_zlib = true;
+          }
+#endif
+        else if (argv[i] == "-struct")
+          {
+            retval.append (argv[i]);
+          }
+        else if (argv[i][0] == '-' && argv[i] != "-")
+          {
+            error ("save: Unrecognized option '%s'", argv[i].c_str ());
+          }
+        else
+          retval.append (argv[i]);
+      }
 
-  octave_scalar_map retstruct;
+    if (do_double)
+      {
+        if (fmt.type () == MAT_ASCII)
+          fmt.set_option (MAT_ASCII_LONG);
+        else
+          warning (R"(save: "-double" option only has an effect with "-ascii")");
+      }
 
-  std::ostringstream output_buf;
-  std::list<std::string> symbol_names;
+    if (do_tabs)
+      {
+        if (fmt.type () == MAT_ASCII)
+          fmt.set_option (MAT_ASCII_TABS);
+        else
+          warning (R"(save: "-tabs" option only has an effect with "-ascii")");
+      }
 
-  octave_idx_type count = 0;
+    return retval;
+  }
 
-  for (;;)
-    {
-      bool global = false;
-      octave_value tc;
+  string_vector
+  load_save_system::parse_save_options (const std::string& arg,
+                                        load_save_format& fmt,
+                                        bool& append, bool& save_as_floats,
+                                        bool& use_zlib)
+  {
+    std::istringstream is (arg);
+    std::string str;
+    string_vector argv;
+
+    while (! is.eof ())
+      {
+        is >> str;
+        argv.append (str);
+      }
+
+    return parse_save_options (argv, fmt, append, save_as_floats, use_zlib);
+  }
+
+  void load_save_system::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)
+  {
+    if (write_header_info)
+      write_header (os, fmt);
 
-      std::string name;
-      std::string doc;
+    if (argv_idx == argc)
+      {
+        save_vars (os, "*", fmt, save_as_floats);
+      }
+    else if (argv[argv_idx] == "-struct")
+      {
+        if (++argv_idx >= argc)
+          error ("save: missing struct name");
+
+        std::string struct_name = argv[argv_idx];
+
+        symbol_scope scope = m_interpreter.get_current_scope ();
+
+        octave_value struct_var;
+
+        if (scope)
+          {
+            if (! scope.is_variable (struct_name))
+              error ("save: no such variable: '%s'", struct_name.c_str ());
+
+            struct_var = scope.varval (struct_name);
+          }
+
+        if (! struct_var.isstruct () || struct_var.numel () != 1)
+          error ("save: '%s' is not a scalar structure", struct_name.c_str ());
+
+        octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
+
+        ++argv_idx;
 
-      switch (format.type)
-        {
-        case LS_TEXT:
-          name = read_text_data (stream, orig_fname, global, tc, count);
-          break;
+        if (argv_idx < argc)
+          {
+            for (int i = argv_idx; i < argc; i++)
+              {
+                if (! save_fields (os, struct_var_map, argv[i], fmt,
+                                   save_as_floats))
+                  {
+                    warning ("save: no such field '%s.%s'",
+                             struct_name.c_str (), argv[i].c_str ());
+                  }
+              }
+          }
+        else
+          save_fields (os, struct_var_map, "*", fmt, save_as_floats);
+      }
+    else
+      {
+        for (int i = argv_idx; i < argc; i++)
+          {
+            if (argv[i] == "")
+              continue;  // Skip empty vars for Matlab compatibility
+            if (! save_vars (os, argv[i], fmt, save_as_floats))
+              warning ("save: no such variable '%s'", argv[i].c_str ());
+          }
+      }
+  }
+
+  void load_save_system::dump_octave_core (void)
+  {
+    if (m_crash_dumps_octave_core)
+      {
+        // FIXME: should choose better filename?
 
-        case LS_BINARY:
-          name = read_binary_data (stream, swap, flt_fmt, orig_fname,
-                                   global, tc, doc);
-          break;
+        const char *fname = m_octave_core_file_name.c_str ();
+
+        message (nullptr, "attempting to save variables to '%s'...", fname);
+
+        load_save_format fmt (BINARY);
+
+        bool save_as_floats = false;
+
+        bool append = false;
+
+        bool use_zlib = false;
+
+        load_save_system::parse_save_options (m_octave_core_file_options,
+                                              fmt, append, save_as_floats,
+                                              use_zlib);
 
-        case LS_MAT_ASCII:
-          name = read_mat_ascii_data (stream, orig_fname, tc);
-          break;
+        std::ios::openmode mode = std::ios::out;
+
+        // Matlab v7 files are always compressed
+        if (fmt.type () == MAT7_BINARY)
+          use_zlib = false;
 
-        case LS_MAT_BINARY:
-          name = read_mat_binary_data (stream, orig_fname, tc);
-          break;
+        if (fmt.type () == BINARY
+#if defined (HAVE_HDF5)
+            || fmt.type () == HDF5
+#endif
+            || fmt.type () == MAT_BINARY
+            || fmt.type () == MAT5_BINARY
+            || fmt.type () == MAT7_BINARY)
+          mode |= std::ios::binary;
+
+        mode |= append ? std::ios::ate : std::ios::trunc;
 
 #if defined (HAVE_HDF5)
-        case LS_HDF5:
-          name = read_hdf5_data (stream, orig_fname, global, tc, doc,
-                                 argv, argv_idx, argc);
-          break;
+        if (fmt.type () == HDF5)
+          {
+            hdf5_ofstream file (fname, mode);
+
+            if (file.file_id >= 0)
+              {
+                dump_octave_core (file, fname, fmt, save_as_floats);
+
+                file.close ();
+              }
+            else
+              warning ("dump_octave_core: unable to open '%s' for writing...",
+                       fname);
+          }
+        else
 #endif
+          // don't insert any commands here!  The open brace below must
+          // go with the else above!
+          {
+#if defined (HAVE_ZLIB)
+            if (use_zlib)
+              {
+                gzofstream file (fname, mode);
+
+                if (file)
+                  {
+                    dump_octave_core (file, fname, fmt, save_as_floats);
+
+                    file.close ();
+                  }
+                else
+                  warning ("dump_octave_core: unable to open '%s' for writing...",
+                           fname);
+              }
+            else
+#endif
+              {
+                std::ofstream file (fname, mode);
+
+                if (file)
+                  {
+                    dump_octave_core (file, fname, fmt, save_as_floats);
 
-        case LS_MAT5_BINARY:
-        case LS_MAT7_BINARY:
-          name = read_mat5_binary_element (stream, orig_fname, swap,
-                                           global, tc);
-          break;
+                    file.close ();
+                  }
+                else
+                  warning ("dump_octave_core: unable to open '%s' for writing...",
+                           fname);
+              }
+          }
+      }
+  }
+
+  void load_save_system::write_header (std::ostream& os,
+                                       const load_save_format& fmt)
+  {
+    switch (fmt.type ())
+      {
+      case BINARY:
+        {
+          os << (mach_info::words_big_endian ()
+                 ? "Octave-1-B" : "Octave-1-L");
+
+          mach_info::float_format flt_fmt =
+            mach_info::native_float_format ();
+
+          char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
+
+          os.write (&tmp, 1);
+        }
+        break;
 
-        default:
-          err_unrecognized_data_fmt ("load");
-          break;
+      case MAT5_BINARY:
+      case MAT7_BINARY:
+        {
+          char const *versionmagic;
+          char headertext[128];
+          sys::gmtime now;
+
+          // ISO 8601 format date
+          const char *matlab_format = "MATLAB 5.0 MAT-file, written by Octave "
+            OCTAVE_VERSION ", %Y-%m-%d %T UTC";
+          std::string comment_string = now.strftime (matlab_format);
+
+          size_t len = std::min (comment_string.length (), static_cast<size_t> (124));
+          memset (headertext, ' ', 124);
+          memcpy (headertext, comment_string.data (), len);
+
+          // The first pair of bytes give the version of the MAT file
+          // format.  The second pair of bytes form a magic number which
+          // signals a MAT file.  MAT file data are always written in
+          // native byte order.  The order of the bytes in the second
+          // pair indicates whether the file was written by a big- or
+          // little-endian machine.  However, the version number is
+          // written in the *opposite* byte order from everything else!
+          if (mach_info::words_big_endian ())
+            versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
+          else
+            versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
+
+          memcpy (headertext+124, versionmagic, 4);
+          os.write (headertext, 128);
         }
 
-      if (stream.eof () || name.empty ())
         break;
-      else
-        {
-          if (! tc.is_defined ())
-            error ("load: unable to load variable '%s'", name.c_str ());
 
-          if (format == LS_MAT_ASCII && argv_idx < argc)
-            warning ("load: loaded ASCII file '%s' -- ignoring extra args",
-                     orig_fname.c_str ());
+#if defined (HAVE_HDF5)
+      case HDF5:
+#endif
+      case TEXT:
+        {
+          sys::localtime now;
 
-          if (format == LS_MAT_ASCII
-              || argv_idx == argc
-              || matches_patterns (argv, argv_idx, argc, name))
+          std::string comment_string = now.strftime (m_save_header_format_string);
+
+          if (! comment_string.empty ())
             {
-              count++;
-              if (list_only)
+#if defined (HAVE_HDF5)
+              if (fmt.type () == HDF5)
                 {
-                  if (verbose)
-                    {
-                      if (count == 1)
-                        output_buf
-                          << "type               rows   cols   name\n"
-                          << "====               ====   ====   ====\n";
-
-                      output_buf
-                        << std::setiosflags (std::ios::left)
-                        << std::setw (16) << tc.type_name ().c_str ()
-                        << std::setiosflags (std::ios::right)
-                        << std::setw (7) << tc.rows ()
-                        << std::setw (7) << tc.columns ()
-                        << "   " << name << "\n";
-                    }
-                  else
-                    symbol_names.push_back (name);
+                  hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
+                  H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
                 }
               else
+#endif
+                os << comment_string << "\n";
+            }
+        }
+        break;
+
+      default:
+        break;
+      }
+  }
+
+  // Save variables with names matching PATTERN on stream OS in the
+  // format specified by FMT.
+
+  size_t load_save_system::save_vars (std::ostream& os,
+                                      const std::string& pattern,
+                                      const load_save_format& fmt,
+                                      bool save_as_floats)
+  {
+    call_stack& cs = m_interpreter.get_call_stack ();
+
+    symbol_info_list syminfo_list = cs.glob_symbol_info (pattern);
+
+    size_t saved = 0;
+
+    for (const auto& syminfo : syminfo_list)
+      {
+        do_save (os, syminfo, fmt, save_as_floats);
+
+        saved++;
+      }
+
+    return saved;
+  }
+
+  void load_save_system::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)
+  {
+    switch (fmt.type ())
+      {
+      case TEXT:
+        save_text_data (os, tc, name, global, 0);
+        break;
+
+      case BINARY:
+        save_binary_data (os, tc, name, help, global, save_as_floats);
+        break;
+
+      case MAT_ASCII:
+        if (! save_mat_ascii_data (os, tc,
+                                   fmt.options () & MAT_ASCII_LONG ? 16 : 8,
+                                   fmt.options () & MAT_ASCII_TABS))
+          warning ("save: unable to save %s in ASCII format", name.c_str ());
+        break;
+
+      case MAT_BINARY:
+        save_mat_binary_data (os, tc, name);
+        break;
+
+#if defined (HAVE_HDF5)
+      case HDF5:
+        save_hdf5_data (os, tc, name, help, global, save_as_floats);
+        break;
+#endif
+
+      case MAT5_BINARY:
+        save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
+        break;
+
+      case MAT7_BINARY:
+        save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
+        break;
+
+      default:
+        err_unrecognized_data_fmt ("save");
+        break;
+      }
+  }
+
+  // Save the info from SR on stream OS in the format specified by FMT.
+
+  void load_save_system::do_save (std::ostream& os,
+                                  const symbol_info& syminfo,
+                                  const load_save_format& fmt,
+                                  bool save_as_floats)
+  {
+    octave_value val = syminfo.value ();
+
+    if (val.is_defined ())
+      {
+        std::string name = syminfo.name ();
+        std::string help;
+        bool global = syminfo.is_global ();
+
+        do_save (os, val, name, help, global, fmt, save_as_floats);
+      }
+  }
+
+  // save fields of a scalar structure STR matching PATTERN on stream OS
+  // in the format specified by FMT.
+
+  size_t load_save_system::save_fields (std::ostream& os,
+                                        const octave_scalar_map& m,
+                                        const std::string& pattern,
+                                        const load_save_format& fmt,
+                                        bool save_as_floats)
+  {
+    glob_match pat (pattern);
+
+    size_t saved = 0;
+
+    for (auto it = m.begin (); it != m.end (); it++)
+      {
+        std::string empty_str;
+
+        if (pat.match (m.key (it)))
+          {
+            do_save (os, m.contents (it), m.key (it), empty_str,
+                     0, fmt, save_as_floats);
+
+            saved++;
+          }
+      }
+
+    return saved;
+  }
+
+  void load_save_system::dump_octave_core (std::ostream& os,
+                                           const char *fname,
+                                           const load_save_format& fmt,
+                                           bool save_as_floats)
+  {
+    write_header (os, fmt);
+
+    call_stack& cs = m_interpreter.get_call_stack ();
+
+    symbol_info_list syminfo_list = cs.top_scope_symbol_info ();
+
+    double save_mem_size = 0;
+
+    for (const auto& syminfo : syminfo_list)
+      {
+        octave_value val = syminfo.value ();
+
+        std::string name = syminfo.name ();
+        std::string help;
+        bool global = syminfo.is_global ();
+
+        double val_size = val.byte_size () / 1024;
+
+        // FIXME: maybe we should try to throw out the largest first...
+
+        if (m_octave_core_file_limit < 0
+            || save_mem_size + val_size < m_octave_core_file_limit)
+          {
+            save_mem_size += val_size;
+
+            do_save (os, val, name, help, global, fmt, save_as_floats);
+          }
+      }
+
+    message (nullptr, "save to '%s' complete", fname);
+  }
+
+  // Install a variable with name NAME and the value VAL in the
+  // symbol table.  If GLOBAL is TRUE, make the variable global.
+
+  void load_save_system::install_loaded_variable (const std::string& name,
+                                                  const octave_value& val,
+                                                  bool global,
+                                                  const std::string& /*doc*/)
+  {
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    symbol_scope scope = symtab.require_current_scope ("load_save_system::install_loaded_variable");
+
+    if (global)
+      {
+        symbol_record sym = scope.find_symbol (name);
+
+        if (! sym.is_global ())
+          {
+            symbol_scope global_scope = symtab.global_scope ();
+            symbol_record global_sym = global_scope.find_symbol (name);
+
+            sym.bind_fwd_rep (global_scope.get_rep (), global_sym);
+          }
+      }
+
+    scope.assign (name, val);
+  }
+
+  std::string load_save_system::init_save_header_format (void)
+  {
+    return
+      (std::string ("# Created by Octave " OCTAVE_VERSION
+                   ", %a %b %d %H:%M:%S %Y %Z <")
+       + sys::env::get_user_name ()
+       + '@'
+       + sys::env::get_host_name ()
+       + '>');
+  }
+
+  load_save_format
+  load_save_system::get_file_format (std::istream& file,
+                                     const std::string& filename)
+  {
+    load_save_format retval = load_save_system::UNKNOWN;
+
+    mach_info::float_format flt_fmt
+      = mach_info::flt_fmt_unknown;
+
+    bool swap = false;
+
+    if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
+      retval = BINARY;
+    else
+      {
+        file.clear ();
+        file.seekg (0, std::ios::beg);
+
+        int32_t mopt, nr, nc, imag, len;
+
+        int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
+                                        true);
+
+        if (! err)
+          retval = MAT_BINARY;
+        else
+          {
+            file.clear ();
+            file.seekg (0, std::ios::beg);
+
+            err = read_mat5_binary_file_header (file, swap, true, filename);
+
+            if (! err)
+              {
+                file.clear ();
+                file.seekg (0, std::ios::beg);
+                retval = MAT5_BINARY;
+              }
+            else
+              {
+                file.clear ();
+                file.seekg (0, std::ios::beg);
+
+                std::string name_val = extract_keyword (file, "name");
+                std::string type_val = extract_keyword (file, "type");
+
+                if (name_val.empty () != true && type_val.empty () != true)
+                  retval = TEXT;
+                else
+                  {
+                    file.clear ();
+                    file.seekg (0, std::ios::beg);
+
+                    // FIXME: looks_like_mat_ascii_file does not check
+                    // to see whether the file contains numbers.  It
+                    // just skips comments and checks for the same
+                    // number of words on each line.  We may need a
+                    // better check here.  The best way to do that might
+                    // be just to try to read the file and see if it
+                    // works.
+
+                    if (looks_like_mat_ascii_file (file, filename))
+                      retval = MAT_ASCII;
+                  }
+              }
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value_list
+  load_save_system::load (const octave_value_list& args, int nargout)
+  {
+    octave_value_list retval;
+
+    int argc = args.length () + 1;
+
+    string_vector argv = args.make_argv ("load");
+
+    int i = 1;
+    std::string orig_fname = "";
+
+    // Function called with Matlab-style ["filename", options] syntax
+    if (argc > 1 && ! argv[1].empty () && argv[1].at (0) != '-')
+      {
+        orig_fname = argv[1];
+        i++;
+      }
+
+    // It isn't necessary to have the default load format stored in a
+    // user preference variable since we can determine the type of file
+    // as we are reading.
+
+    load_save_format format = UNKNOWN;
+
+    bool list_only = false;
+    bool verbose = false;
+
+    for (; i < argc; i++)
+      {
+        if (argv[i] == "-force" || argv[i] == "-f")
+          {
+            // Silently ignore this
+            // warning ("load: -force ignored");
+          }
+        else if (argv[i] == "-list" || argv[i] == "-l")
+          {
+            list_only = true;
+          }
+        else if (argv[i] == "-verbose" || argv[i] == "-v")
+          {
+            verbose = true;
+          }
+        else if (argv[i] == "-ascii" || argv[i] == "-a")
+          {
+            format = MAT_ASCII;
+          }
+        else if (argv[i] == "-binary" || argv[i] == "-b")
+          {
+            format = BINARY;
+          }
+        else if (argv[i] == "-mat-binary" || argv[i] == "-mat"
+                 || argv[i] == "-m" || argv[i] == "-6" || argv[i] == "-v6")
+          {
+            format = MAT5_BINARY;
+          }
+        else if (argv[i] == "-7" || argv[i] == "-v7")
+          {
+            format = MAT7_BINARY;
+          }
+        else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
+                 || argv[i] == "-v4" || argv[i] == "-4")
+          {
+            format = MAT_BINARY;
+          }
+        else if (argv[i] == "-hdf5" || argv[i] == "-h")
+          {
+#if defined (HAVE_HDF5)
+            format = HDF5;
+#else
+            err_disabled_feature ("load", "HDF5");
+#endif
+          }
+        else if (argv[i] == "-import" || argv[i] == "-i")
+          {
+            warning ("load: -import ignored");
+          }
+        else if (argv[i] == "-text" || argv[i] == "-t")
+          {
+            format = TEXT;
+          }
+        else
+          break;
+      }
+
+    if (orig_fname == "")
+      {
+        if (i == argc)
+          print_usage ();
+
+        orig_fname = argv[i];
+      }
+    else
+      i--;
+
+    mach_info::float_format flt_fmt = mach_info::flt_fmt_unknown;
+
+    bool swap = false;
+
+    if (orig_fname == "-")
+      {
+        i++;
+
+#if defined (HAVE_HDF5)
+        if (format.type () == HDF5)
+          error ("load: cannot read HDF5 format from stdin");
+        else
+#endif
+          if (format.type () != UNKNOWN)
+            {
+              // FIXME: if we have already seen EOF on a previous call,
+              // how do we fix up the state of std::cin so that we can get
+              // additional input?  I'm afraid that we can't fix this
+              // using std::cin only.
+
+              retval = load_vars (std::cin, orig_fname, format, flt_fmt,
+                                  list_only, swap, verbose, argv, i,
+                                  argc, nargout);
+            }
+          else
+            error ("load: must specify file format if reading from stdin");
+      }
+    else
+      {
+        std::string fname = sys::file_ops::tilde_expand (orig_fname);
+
+        fname = find_file_to_load (fname, orig_fname);
+
+        bool use_zlib = false;
+
+        if (format.type () == UNKNOWN)
+          format = get_file_format (fname, orig_fname, use_zlib);
+
+#if defined (HAVE_HDF5)
+        if (format.type () == HDF5)
+          {
+            i++;
+
+            hdf5_ifstream hdf5_file (fname.c_str ());
+
+            if (hdf5_file.file_id < 0)
+              err_file_open ("load", orig_fname);
+
+            retval = load_vars (hdf5_file, orig_fname, format, flt_fmt,
+                                list_only, swap, verbose, argv, i,
+                                argc, nargout);
+
+            hdf5_file.close ();
+          }
+        else
+#endif
+          // don't insert any statements here; the "else" above has to
+          // go with the "if" below!!!!!
+          if (format.type () != UNKNOWN)
+            {
+              i++;
+
+              // Always open in binary mode and handle various
+              // line-endings explicitly.
+              std::ios::openmode mode = std::ios::in | std::ios::binary;
+
+#if defined (HAVE_ZLIB)
+              if (use_zlib)
                 {
-                  if (nargout == 1)
+                  gzifstream file (fname.c_str (), mode);
+
+                  if (! file)
+                    err_file_open ("load", orig_fname);
+
+                  if (format.type () == BINARY)
                     {
-                      if (format == LS_MAT_ASCII)
-                        retval = tc;
-                      else
-                        retstruct.assign (name, tc);
+                      if (read_binary_file_header (file, swap, flt_fmt) < 0)
+                        {
+                          if (file) file.close ();
+                          return retval;
+                        }
+                    }
+                  else if (format.type () == MAT5_BINARY
+                           || format.type () == MAT7_BINARY)
+                    {
+                      if (read_mat5_binary_file_header (file, swap, false,
+                                                        orig_fname) < 0)
+                        {
+                          if (file) file.close ();
+                          return retval;
+                        }
                     }
-                  else
-                    install_loaded_variable (name, tc, global, doc);
+
+                  retval = load_vars (file, orig_fname, format, flt_fmt,
+                                      list_only, swap, verbose, argv, i,
+                                      argc, nargout);
+
+                  file.close ();
+                }
+              else
+#endif
+                {
+                  std::string ascii_fname = sys::get_ASCII_filename (fname);
+
+                  std::ifstream file (ascii_fname.c_str (), mode);
+
+                  if (! file)
+                    error ("load: unable to open input file '%s'",
+                           orig_fname.c_str ());
+
+                  if (format.type () == BINARY)
+                    {
+                      if (read_binary_file_header (file, swap, flt_fmt) < 0)
+                        {
+                          if (file) file.close ();
+                          return retval;
+                        }
+                    }
+                  else if (format.type () == MAT5_BINARY
+                           || format.type () == MAT7_BINARY)
+                    {
+                      if (read_mat5_binary_file_header (file, swap, false,
+                                                        orig_fname) < 0)
+                        {
+                          if (file) file.close ();
+                          return retval;
+                        }
+                    }
+
+                  retval = load_vars (file, orig_fname, format, flt_fmt,
+                                      list_only, swap, verbose, argv, i,
+                                      argc, nargout);
+
+                  file.close ();
                 }
             }
+          else
+            error ("load: unable to determine file format of '%s'",
+                   orig_fname.c_str ());
 
-          // Only attempt to read one item from a headless text file.
+      }
+
+    return retval;
+  }
+
+  octave_value_list
+  load_save_system::save (const octave_value_list& args, int nargout)
+  {
+    // Here is where we would get the default save format if it were
+    // stored in a user preference variable.
+    load_save_format format = TEXT;
+    bool save_as_floats = false;
+    bool append = false;
+    bool use_zlib = false;
+
+
+    // get default options
+    parse_save_options (save_default_options (), format, append,
+                        save_as_floats, use_zlib);
+
+    // override from command line
+    string_vector argv = args.make_argv ();
+
+    argv = parse_save_options (argv, format, append, save_as_floats, use_zlib);
+
+    int argc = argv.numel ();
+    int i = 0;
+
+    if (i == argc)
+      print_usage ();
+
+    if (save_as_floats && format.type () == TEXT)
+      error ("save: cannot specify both -text and -float-binary");
 
-          if (format == LS_MAT_ASCII)
-            break;
-        }
-    }
+    octave_value_list retval;
+
+    if (argv[i] == "-")
+      {
+        i++;
+
+#if defined (HAVE_HDF5)
+        if (format.type () == HDF5)
+          error ("save: cannot write HDF5 format to stdout");
+        else
+#endif
+          // don't insert any commands here!  the brace below must go
+          // with the "else" above!
+          {
+            if (append)
+              warning ("save: ignoring -append option for output to stdout");
 
-  if (list_only && count)
-    {
-      if (verbose)
-        {
-          std::string msg = output_buf.str ();
+            if (nargout == 0)
+              save_vars (argv, i, argc, octave_stdout, format,
+                         save_as_floats, true);
+            else
+              {
+                std::ostringstream output_buf;
+                save_vars (argv, i, argc, output_buf, format,
+                           save_as_floats, true);
+                retval = octave_value (output_buf.str());
+              }
+          }
+      }
+
+    // Guard against things like 'save a*', which are probably mistakes...
+
+    else if (i == argc - 1 && glob_pattern_p (argv[i]))
+      print_usage ();
+    else
+      {
+        std::string fname = sys::file_ops::tilde_expand (argv[i]);
+
+        i++;
 
-          if (nargout > 0)
-            retval = msg;
-          else
-            octave_stdout << msg;
-        }
-      else
-        {
-          if (nargout  > 0)
-            retval = Cell (string_vector (symbol_names));
-          else
-            {
-              string_vector names (symbol_names);
+        // Matlab v7 files are always compressed
+        if (format.type () == MAT7_BINARY)
+          use_zlib = false;
+
+        std::ios::openmode mode
+          = (append ? (std::ios::app | std::ios::ate) : std::ios::out);
+
+        if (format.type () == BINARY
+#if defined (HAVE_HDF5)
+            || format.type () == HDF5
+#endif
+            || format.type () == MAT_BINARY
+            || format.type () == MAT5_BINARY
+            || format.type () == MAT7_BINARY)
+          mode |= std::ios::binary;
+
+#if defined (HAVE_HDF5)
+        if (format.type () == HDF5)
+          {
+            // FIXME: It should be possible to append to HDF5 files.
+            if (append)
+              error ("save: appending to HDF5 files is not implemented");
+
+            std::string ascii_fname = sys::get_ASCII_filename (fname);
+
+            bool write_header_info
+              = ! (append && H5Fis_hdf5 (ascii_fname.c_str ()) > 0);
+
+            hdf5_ofstream hdf5_file (fname.c_str (), mode);
+
+            if (hdf5_file.file_id == -1)
+              err_file_open ("save", fname);
+
+            save_vars (argv, i, argc, hdf5_file, format, save_as_floats,
+                       write_header_info);
 
-              names.list_in_columns (octave_stdout);
+            hdf5_file.close ();
+          }
+        else
+#endif
+          // don't insert any statements here!  The brace below must go
+          // with the "else" above!
+          {
+#if defined (HAVE_ZLIB)
+            if (use_zlib)
+              {
+                gzofstream file (fname.c_str (), mode);
+
+                if (! file)
+                  err_file_open ("save", fname);
+
+                bool write_header_info = ! file.tellp ();
+
+                save_vars (argv, i, argc, file, format, save_as_floats,
+                           write_header_info);
 
-              octave_stdout << "\n";
-            }
-        }
-    }
-  else if (retstruct.nfields () != 0)
-    retval = retstruct;
+                file.close ();
+              }
+            else
+#endif
+              {
+                std::ofstream file (fname.c_str (), mode);
+
+                if (! file)
+                  err_file_open ("save", fname);
 
-  return retval;
+                bool write_header_info = ! file.tellp ();
+
+                save_vars (argv, i, argc, file, format, save_as_floats,
+                           write_header_info);
+
+                file.close ();
+              }
+          }
+      }
+
+    return retval;
+  }
 }
 
-static std::string
-find_file_to_load (const std::string& name, const std::string& orig_name)
+void
+dump_octave_core (void)
 {
-  std::string fname = find_data_file_in_load_path ("load", name, true);
-
-  size_t dot_pos = fname.rfind ('.');
-  size_t sep_pos = fname.find_last_of (octave::sys::file_ops::dir_sep_chars ());
-
-  if (dot_pos == std::string::npos
-      || (sep_pos != std::string::npos && dot_pos < sep_pos))
-    {
-      // Either no '.' in name or no '.' appears after last directory
-      // separator.
-
-      octave::sys::file_stat fs (fname);
+  octave::load_save_system& load_save_sys
+    = octave::__get_load_save_system__ ("dump_octave_core");
 
-      if (! (fs.exists () && fs.is_reg ()))
-        fname = find_file_to_load (fname + ".mat", orig_name);
-    }
-  else
-    {
-      octave::sys::file_stat fs (fname);
-
-      if (! (fs.exists () && fs.is_reg ()))
-        {
-          fname = "";
-
-          error ("load: unable to find file %s", orig_name.c_str ());
-        }
-    }
-
-  return fname;
+  load_save_sys.dump_octave_core ();
 }
 
-bool
-is_octave_data_file (const std::string& fname)
-{
-  bool use_zlib = false;
-  return get_file_format (fname, fname, use_zlib, true) != LS_UNKNOWN;
-}
-
-DEFUN (load, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (load, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} load file
 @deftypefnx {} {} load options file
 @deftypefnx {} {} load options file v1 v2 @dots{}
@@ -641,836 +1669,13 @@
 @seealso{save, dlmwrite, csvwrite, fwrite}
 @end deftypefn */)
 {
-  octave_value_list retval;
-
-  int argc = args.length () + 1;
-
-  string_vector argv = args.make_argv ("load");
-
-  int i = 1;
-  std::string orig_fname = "";
-
-  // Function called with Matlab-style ["filename", options] syntax
-  if (argc > 1 && ! argv[1].empty () && argv[1].at (0) != '-')
-    {
-      orig_fname = argv[1];
-      i++;
-    }
-
-  // It isn't necessary to have the default load format stored in a
-  // user preference variable since we can determine the type of file
-  // as we are reading.
-
-  load_save_format format = LS_UNKNOWN;
-
-  bool list_only = false;
-  bool verbose = false;
-
-  for (; i < argc; i++)
-    {
-      if (argv[i] == "-force" || argv[i] == "-f")
-        {
-          // Silently ignore this
-          // warning ("load: -force ignored");
-        }
-      else if (argv[i] == "-list" || argv[i] == "-l")
-        {
-          list_only = true;
-        }
-      else if (argv[i] == "-verbose" || argv[i] == "-v")
-        {
-          verbose = true;
-        }
-      else if (argv[i] == "-ascii" || argv[i] == "-a")
-        {
-          format = LS_MAT_ASCII;
-        }
-      else if (argv[i] == "-binary" || argv[i] == "-b")
-        {
-          format = LS_BINARY;
-        }
-      else if (argv[i] == "-mat-binary" || argv[i] == "-mat" || argv[i] == "-m"
-               || argv[i] == "-6" || argv[i] == "-v6")
-        {
-          format = LS_MAT5_BINARY;
-        }
-      else if (argv[i] == "-7" || argv[i] == "-v7")
-        {
-          format = LS_MAT7_BINARY;
-        }
-      else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
-               || argv[i] == "-v4" || argv[i] == "-4")
-        {
-          format = LS_MAT_BINARY;
-        }
-      else if (argv[i] == "-hdf5" || argv[i] == "-h")
-        {
-#if defined (HAVE_HDF5)
-          format = LS_HDF5;
-#else
-          err_disabled_feature ("load", "HDF5");
-#endif
-        }
-      else if (argv[i] == "-import" || argv[i] == "-i")
-        {
-          warning ("load: -import ignored");
-        }
-      else if (argv[i] == "-text" || argv[i] == "-t")
-        {
-          format = LS_TEXT;
-        }
-      else
-        break;
-    }
-
-  if (orig_fname == "")
-    {
-      if (i == argc)
-        print_usage ();
-
-      orig_fname = argv[i];
-    }
-  else
-    i--;
-
-  octave::mach_info::float_format flt_fmt = octave::mach_info::flt_fmt_unknown;
-
-  bool swap = false;
-
-  if (orig_fname == "-")
-    {
-      i++;
-
-#if defined (HAVE_HDF5)
-      if (format == LS_HDF5)
-        error ("load: cannot read HDF5 format from stdin");
-      else
-#endif
-      if (format != LS_UNKNOWN)
-        {
-          // FIXME: if we have already seen EOF on a previous call,
-          // how do we fix up the state of std::cin so that we can get
-          // additional input?  I'm afraid that we can't fix this
-          // using std::cin only.
-
-          retval = do_load (std::cin, orig_fname, format, flt_fmt,
-                            list_only, swap, verbose, argv, i, argc,
-                            nargout);
-        }
-      else
-        error ("load: must specify file format if reading from stdin");
-    }
-  else
-    {
-      std::string fname = octave::sys::file_ops::tilde_expand (orig_fname);
-
-      fname = find_file_to_load (fname, orig_fname);
-
-      bool use_zlib = false;
-
-      if (format == LS_UNKNOWN)
-        format = get_file_format (fname, orig_fname, use_zlib);
-
-#if defined (HAVE_HDF5)
-      if (format == LS_HDF5)
-        {
-          i++;
-
-          hdf5_ifstream hdf5_file (fname.c_str ());
-
-          if (hdf5_file.file_id < 0)
-            err_file_open ("load", orig_fname);
-
-          retval = do_load (hdf5_file, orig_fname, format,
-                            flt_fmt, list_only, swap, verbose,
-                            argv, i, argc, nargout);
-
-          hdf5_file.close ();
-        }
-      else
-#endif
-        // don't insert any statements here; the "else" above has to
-        // go with the "if" below!!!!!
-      if (format != LS_UNKNOWN)
-        {
-          i++;
-
-          // Always open in binary mode and handle various
-          // line-endings explicitly.
-          std::ios::openmode mode = std::ios::in | std::ios::binary;
-
-#if defined (HAVE_ZLIB)
-          if (use_zlib)
-            {
-              gzifstream file (fname.c_str (), mode);
-
-              if (! file)
-                err_file_open ("load", orig_fname);
-
-              if (format == LS_BINARY)
-                {
-                  if (read_binary_file_header (file, swap, flt_fmt) < 0)
-                    {
-                      if (file) file.close ();
-                      return retval;
-                    }
-                }
-              else if (format == LS_MAT5_BINARY
-                       || format == LS_MAT7_BINARY)
-                {
-                  if (read_mat5_binary_file_header (file, swap, false,
-                                                    orig_fname) < 0)
-                    {
-                      if (file) file.close ();
-                      return retval;
-                    }
-                }
-
-              retval = do_load (file, orig_fname, format,
-                                flt_fmt, list_only, swap, verbose,
-                                argv, i, argc, nargout);
-
-              file.close ();
-            }
-          else
-#endif
-            {
-              std::ifstream file (fname.c_str (), mode);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
 
-              if (! file)
-                error ("load: unable to open input file '%s'",
-                       orig_fname.c_str ());
-
-              if (format == LS_BINARY)
-                {
-                  if (read_binary_file_header (file, swap, flt_fmt) < 0)
-                    {
-                      if (file) file.close ();
-                      return retval;
-                    }
-                }
-              else if (format == LS_MAT5_BINARY
-                       || format == LS_MAT7_BINARY)
-                {
-                  if (read_mat5_binary_file_header (file, swap, false,
-                                                    orig_fname) < 0)
-                    {
-                      if (file) file.close ();
-                      return retval;
-                    }
-                }
-
-              retval = do_load (file, orig_fname, format,
-                                flt_fmt, list_only, swap, verbose,
-                                argv, i, argc, nargout);
-
-              file.close ();
-            }
-        }
-      else
-        error ("load: unable to determine file format of '%s'",
-               orig_fname.c_str ());
-
-    }
-
-  return retval;
-}
-
-// Return TRUE if PATTERN has any special globbing chars in it.
-
-static bool
-glob_pattern_p (const std::string& pattern)
-{
-  int open = 0;
-
-  int len = pattern.length ();
-
-  for (int i = 0; i < len; i++)
-    {
-      char c = pattern[i];
-
-      switch (c)
-        {
-        case '?':
-        case '*':
-          return true;
-
-        case '[':       // Only accept an open brace if there is a close
-          open++;       // brace to match it.  Bracket expressions must be
-          continue;     // complete, according to Posix.2
-
-        case ']':
-          if (open)
-            return true;
-          continue;
-
-        case '\\':
-          if (i == len - 1)
-            return false;
-          continue;
-
-        default:
-          continue;
-        }
-    }
-
-  return false;
-}
-
-static void
-do_save (std::ostream& os, const octave_value& tc,
-         const std::string& name, const std::string& help,
-         bool global, load_save_format fmt, bool save_as_floats)
-{
-  switch (fmt.type)
-    {
-    case LS_TEXT:
-      save_text_data (os, tc, name, global, 0);
-      break;
-
-    case LS_BINARY:
-      save_binary_data (os, tc, name, help, global, save_as_floats);
-      break;
-
-    case LS_MAT_ASCII:
-      if (! save_mat_ascii_data (os, tc, fmt.opts & LS_MAT_ASCII_LONG ? 16 : 8,
-                                 fmt.opts & LS_MAT_ASCII_TABS))
-        warning ("save: unable to save %s in ASCII format", name.c_str ());
-      break;
-
-    case LS_MAT_BINARY:
-      save_mat_binary_data (os, tc, name);
-      break;
-
-#if defined (HAVE_HDF5)
-    case LS_HDF5:
-      save_hdf5_data (os, tc, name, help, global, save_as_floats);
-      break;
-#endif
-
-    case LS_MAT5_BINARY:
-      save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
-      break;
-
-    case LS_MAT7_BINARY:
-      save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
-      break;
-
-    default:
-      err_unrecognized_data_fmt ("save");
-      break;
-    }
-}
-
-// Save the info from SR on stream OS in the format specified by FMT.
-
-void
-do_save (std::ostream& os, const octave::symbol_record& sr,
-         octave::symbol_record::context_id context,
-         load_save_format fmt, bool save_as_floats)
-{
-  octave_value val = sr.varval (context);
-
-  if (val.is_defined ())
-    {
-      std::string name = sr.name ();
-      std::string help;
-      bool global = sr.is_global ();
-
-      do_save (os, val, name, help, global, fmt, save_as_floats);
-    }
-}
-
-// save fields of a scalar structure STR matching PATTERN on stream OS
-// in the format specified by FMT.
-
-static size_t
-save_fields (std::ostream& os, const octave_scalar_map& m,
-             const std::string& pattern,
-             load_save_format fmt, bool save_as_floats)
-{
-  glob_match pat (pattern);
-
-  size_t saved = 0;
-
-  for (octave_scalar_map::const_iterator it = m.begin (); it != m.end (); it++)
-    {
-      std::string empty_str;
-
-      if (pat.match (m.key (it)))
-        {
-          do_save (os, m.contents (it), m.key (it), empty_str,
-                   0, fmt, save_as_floats);
-
-          saved++;
-        }
-    }
-
-  return saved;
-}
-
-// Save variables with names matching PATTERN on stream OS in the
-// format specified by FMT.
-
-static size_t
-save_vars (std::ostream& os, const std::string& pattern,
-           load_save_format fmt, bool save_as_floats)
-{
-  octave::symbol_scope scope = octave::__require_current_scope__ ("save_vars");
-
-  octave::symbol_record::context_id context = scope.current_context ();
-
-  std::list<octave::symbol_record> vars = scope.glob (pattern);
-
-  size_t saved = 0;
-
-  for (const auto& var : vars)
-    {
-      do_save (os, var, context, fmt, save_as_floats);
-
-      saved++;
-    }
-
-  return saved;
+  return load_save_sys.load (args, nargout);
 }
 
-static string_vector
-parse_save_options (const string_vector& argv,
-                    load_save_format& format, bool& append,
-                    bool& save_as_floats, bool& use_zlib)
-{
-#if ! defined (HAVE_ZLIB)
-  octave_unused_parameter (use_zlib);
-#endif
-
-  string_vector retval;
-  int argc = argv.numel ();
-
-  bool do_double = false;
-  bool do_tabs = false;
-
-  for (int i = 0; i < argc; i++)
-    {
-      if (argv[i] == "-append")
-        {
-          append = true;
-        }
-      else if (argv[i] == "-ascii" || argv[i] == "-a")
-        {
-          format = LS_MAT_ASCII;
-        }
-      else if (argv[i] == "-double")
-        {
-          do_double = true;
-        }
-      else if (argv[i] == "-tabs")
-        {
-          do_tabs = true;
-        }
-      else if (argv[i] == "-text" || argv[i] == "-t")
-        {
-          format = LS_TEXT;
-        }
-      else if (argv[i] == "-binary" || argv[i] == "-b")
-        {
-          format = LS_BINARY;
-        }
-      else if (argv[i] == "-hdf5" || argv[i] == "-h")
-        {
-#if defined (HAVE_HDF5)
-          format = LS_HDF5;
-#else
-          err_disabled_feature ("save", "HDF5");
-#endif
-        }
-      else if (argv[i] == "-mat-binary" || argv[i] == "-mat"
-               || argv[i] == "-m" || argv[i] == "-6" || argv[i] == "-v6"
-               || argv[i] == "-V6")
-        {
-          format = LS_MAT5_BINARY;
-        }
-#if defined (HAVE_ZLIB)
-      else if (argv[i] == "-mat7-binary" || argv[i] == "-7"
-               || argv[i] == "-v7" || argv[i] == "-V7")
-        {
-          format = LS_MAT7_BINARY;
-        }
-#endif
-      else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
-               || argv[i] == "-v4" || argv[i] == "-4")
-        {
-          format = LS_MAT_BINARY;
-        }
-      else if (argv[i] == "-float-binary" || argv[i] == "-f")
-        {
-          format = LS_BINARY;
-          save_as_floats = true;
-        }
-      else if (argv[i] == "-float-hdf5")
-        {
-#if defined (HAVE_HDF5)
-          format = LS_HDF5;
-          save_as_floats = true;
-#else
-          err_disabled_feature ("save", "HDF5");
-#endif
-        }
-#if defined (HAVE_ZLIB)
-      else if (argv[i] == "-zip" || argv[i] == "-z")
-        {
-          use_zlib = true;
-        }
-#endif
-      else if (argv[i] == "-struct")
-        {
-          retval.append (argv[i]);
-        }
-      else if (argv[i][0] == '-' && argv[i] != "-")
-        {
-          error ("save: Unrecognized option '%s'", argv[i].c_str ());
-        }
-      else
-        retval.append (argv[i]);
-    }
-
-  if (do_double)
-    {
-      if (format == LS_MAT_ASCII)
-        format.opts |= LS_MAT_ASCII_LONG;
-      else
-        warning (R"(save: "-double" option only has an effect with "-ascii")");
-    }
-
-  if (do_tabs)
-    {
-      if (format == LS_MAT_ASCII)
-        format.opts |= LS_MAT_ASCII_TABS;
-      else
-        warning (R"(save: "-tabs" option only has an effect with "-ascii")");
-    }
-
-  return retval;
-}
-
-static string_vector
-parse_save_options (const std::string& arg, load_save_format& format,
-                    bool& append, bool& save_as_floats, bool& use_zlib)
-{
-  std::istringstream is (arg);
-  std::string str;
-  string_vector argv;
-
-  while (! is.eof ())
-    {
-      is >> str;
-      argv.append (str);
-    }
-
-  return parse_save_options (argv, format, append, save_as_floats, use_zlib);
-}
-
-void
-write_header (std::ostream& os, load_save_format format)
-{
-  switch (format.type)
-    {
-    case LS_BINARY:
-      {
-        os << (octave::mach_info::words_big_endian ()
-               ? "Octave-1-B" : "Octave-1-L");
-
-        octave::mach_info::float_format flt_fmt =
-          octave::mach_info::native_float_format ();
-
-        char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
-
-        os.write (&tmp, 1);
-      }
-      break;
-
-    case LS_MAT5_BINARY:
-    case LS_MAT7_BINARY:
-      {
-        char const *versionmagic;
-        char headertext[128];
-        octave::sys::gmtime now;
-
-        // ISO 8601 format date
-        const char *matlab_format = "MATLAB 5.0 MAT-file, written by Octave "
-            OCTAVE_VERSION ", %Y-%m-%d %T UTC";
-        std::string comment_string = now.strftime (matlab_format);
-
-        size_t len = std::min (comment_string.length (), static_cast<size_t> (124));
-        memset (headertext, ' ', 124);
-        memcpy (headertext, comment_string.data (), len);
-
-        // The first pair of bytes give the version of the MAT file
-        // format.  The second pair of bytes form a magic number which
-        // signals a MAT file.  MAT file data are always written in
-        // native byte order.  The order of the bytes in the second
-        // pair indicates whether the file was written by a big- or
-        // little-endian machine.  However, the version number is
-        // written in the *opposite* byte order from everything else!
-        if (octave::mach_info::words_big_endian ())
-          versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
-        else
-          versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
-
-        memcpy (headertext+124, versionmagic, 4);
-        os.write (headertext, 128);
-      }
-
-      break;
-
-#if defined (HAVE_HDF5)
-    case LS_HDF5:
-#endif
-    case LS_TEXT:
-      {
-        octave::sys::localtime now;
-
-        std::string comment_string = now.strftime (Vsave_header_format_string);
-
-        if (! comment_string.empty ())
-          {
-#if defined (HAVE_HDF5)
-            if (format == LS_HDF5)
-              {
-                hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
-                H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
-              }
-            else
-#endif
-              os << comment_string << "\n";
-          }
-      }
-      break;
-
-    default:
-      break;
-    }
-}
-
-void
-octave_prepare_hdf5 (void)
-{
-#if defined (HAVE_HDF5)
-  H5dont_atexit ();
-#endif
-}
-
-void
-octave_finalize_hdf5 (void)
-{
-#if defined (HAVE_HDF5)
-  H5close ();
-#endif
-}
-
-static void
-save_vars (const string_vector& argv, int argv_idx, int argc,
-           std::ostream& os, load_save_format fmt,
-           bool save_as_floats, bool write_header_info)
-{
-  if (write_header_info)
-    write_header (os, fmt);
-
-  if (argv_idx == argc)
-    {
-      save_vars (os, "*", fmt, save_as_floats);
-    }
-  else if (argv[argv_idx] == "-struct")
-    {
-      if (++argv_idx >= argc)
-        error ("save: missing struct name");
-
-      std::string struct_name = argv[argv_idx];
-
-      octave::symbol_scope scope = octave::__get_current_scope__ ("save_vars");
-
-      octave_value struct_var;
-
-      if (scope)
-        {
-          if (! scope.is_variable (struct_name))
-            error ("save: no such variable: '%s'", struct_name.c_str ());
-
-          struct_var = scope.varval (struct_name);
-        }
-
-      if (! struct_var.isstruct () || struct_var.numel () != 1)
-        error ("save: '%s' is not a scalar structure", struct_name.c_str ());
-
-      octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
-
-      ++argv_idx;
-
-      if (argv_idx < argc)
-        {
-          for (int i = argv_idx; i < argc; i++)
-            {
-              if (! save_fields (os, struct_var_map, argv[i], fmt,
-                                 save_as_floats))
-                {
-                  warning ("save: no such field '%s.%s'",
-                           struct_name.c_str (), argv[i].c_str ());
-                }
-            }
-        }
-      else
-        save_fields (os, struct_var_map, "*", fmt, save_as_floats);
-    }
-  else
-    {
-      for (int i = argv_idx; i < argc; i++)
-        {
-          if (argv[i] == "")
-            continue;  // Skip empty vars for Matlab compatibility
-          if (! save_vars (os, argv[i], fmt, save_as_floats))
-            warning ("save: no such variable '%s'", argv[i].c_str ());
-        }
-    }
-}
-
-static void
-dump_octave_core (std::ostream& os, const char *fname, load_save_format fmt,
-                  bool save_as_floats)
-{
-  write_header (os, fmt);
-
-  octave::symbol_table& symtab =
-    octave::__get_symbol_table__ ("dump_octave_core");
-
-  octave::symbol_scope top_scope = symtab.top_scope ();
-
-  octave::symbol_record::context_id context = top_scope.current_context ();
-
-  std::list<octave::symbol_record> vars = top_scope.all_variables ();
-
-  double save_mem_size = 0;
-
-  for (const auto& var : vars)
-    {
-      octave_value val = var.varval (context);
-
-      if (val.is_defined ())
-        {
-          std::string name = var.name ();
-          std::string help;
-          bool global = var.is_global ();
-
-          double val_size = val.byte_size () / 1024;
-
-          // FIXME: maybe we should try to throw out the largest first...
-
-          if (Voctave_core_file_limit < 0
-              || save_mem_size + val_size < Voctave_core_file_limit)
-            {
-              save_mem_size += val_size;
-
-              do_save (os, val, name, help, global, fmt, save_as_floats);
-            }
-        }
-    }
-
-  message (nullptr, "save to '%s' complete", fname);
-}
-
-void
-dump_octave_core (void)
-{
-  if (Vcrash_dumps_octave_core)
-    {
-      // FIXME: should choose better filename?
-
-      const char *fname = Voctave_core_file_name.c_str ();
-
-      message (nullptr, "attempting to save variables to '%s'...", fname);
-
-      load_save_format format = LS_BINARY;
-
-      bool save_as_floats = false;
-
-      bool append = false;
-
-      bool use_zlib = false;
-
-      parse_save_options (Voctave_core_file_options, format, append,
-                          save_as_floats, use_zlib);
-
-      std::ios::openmode mode = std::ios::out;
-
-      // Matlab v7 files are always compressed
-      if (format == LS_MAT7_BINARY)
-        use_zlib = false;
-
-      if (format == LS_BINARY
-#if defined (HAVE_HDF5)
-          || format == LS_HDF5
-#endif
-          || format == LS_MAT_BINARY
-          || format == LS_MAT5_BINARY
-          || format == LS_MAT7_BINARY)
-        mode |= std::ios::binary;
-
-      mode |= append ? std::ios::ate : std::ios::trunc;
-
-#if defined (HAVE_HDF5)
-      if (format == LS_HDF5)
-        {
-          hdf5_ofstream file (fname, mode);
-
-          if (file.file_id >= 0)
-            {
-              dump_octave_core (file, fname, format, save_as_floats);
-
-              file.close ();
-            }
-          else
-            warning ("dump_octave_core: unable to open '%s' for writing...",
-                     fname);
-        }
-      else
-#endif
-        // don't insert any commands here!  The open brace below must
-        // go with the else above!
-        {
-#if defined (HAVE_ZLIB)
-          if (use_zlib)
-            {
-              gzofstream file (fname, mode);
-
-              if (file)
-                {
-                  dump_octave_core (file, fname, format, save_as_floats);
-
-                  file.close ();
-                }
-              else
-                warning ("dump_octave_core: unable to open '%s' for writing...",
-                         fname);
-            }
-          else
-#endif
-            {
-              std::ofstream file (fname, mode);
-
-              if (file)
-                {
-                  dump_octave_core (file, fname, format, save_as_floats);
-
-                  file.close ();
-                }
-              else
-                warning ("dump_octave_core: unable to open '%s' for writing...",
-                         fname);
-            }
-        }
-    }
-}
-
-DEFUN (save, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (save, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} save file
 @deftypefnx {} {} save options file
 @deftypefnx {} {} save options file @var{v1} @var{v2} @dots{}
@@ -1611,148 +1816,13 @@
 @seealso{load, save_default_options, save_header_format_string, save_precision, dlmread, csvread, fread}
 @end deftypefn */)
 {
-  // Here is where we would get the default save format if it were
-  // stored in a user preference variable.
-  load_save_format format = LS_TEXT;
-  bool save_as_floats = false;
-  bool append = false;
-  bool use_zlib = false;
-
-  // get default options
-  parse_save_options (Vsave_default_options, format, append, save_as_floats,
-                      use_zlib);
-
-  // override from command line
-  string_vector argv = args.make_argv ();
-
-  argv = parse_save_options (argv, format, append, save_as_floats, use_zlib);
-
-  int argc = argv.numel ();
-  int i = 0;
-
-  if (i == argc)
-    print_usage ();
-
-  if (save_as_floats && format == LS_TEXT)
-    error ("save: cannot specify both -text and -float-binary");
-
-  octave_value_list retval;
-
-  if (argv[i] == "-")
-    {
-      i++;
-
-#if defined (HAVE_HDF5)
-      if (format == LS_HDF5)
-        error ("save: cannot write HDF5 format to stdout");
-      else
-#endif
-        // don't insert any commands here!  the brace below must go
-        // with the "else" above!
-        {
-          if (append)
-            warning ("save: ignoring -append option for output to stdout");
-
-          if (nargout == 0)
-            save_vars (argv, i, argc, std::cout, format, save_as_floats, true);
-          else
-            {
-              std::ostringstream output_buf;
-              save_vars (argv, i, argc, output_buf, format, save_as_floats, true);
-              retval = octave_value (output_buf.str());
-            }
-        }
-    }
-
-  // Guard against things like 'save a*', which are probably mistakes...
-
-  else if (i == argc - 1 && glob_pattern_p (argv[i]))
-    print_usage ();
-  else
-    {
-      std::string fname = octave::sys::file_ops::tilde_expand (argv[i]);
-
-      i++;
-
-      // Matlab v7 files are always compressed
-      if (format == LS_MAT7_BINARY)
-        use_zlib = false;
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
 
-      std::ios::openmode mode
-        = (append ? (std::ios::app | std::ios::ate) : std::ios::out);
-
-      if (format == LS_BINARY
-#if defined (HAVE_HDF5)
-          || format == LS_HDF5
-#endif
-          || format == LS_MAT_BINARY
-          || format == LS_MAT5_BINARY
-          || format == LS_MAT7_BINARY)
-        mode |= std::ios::binary;
-
-#if defined (HAVE_HDF5)
-      if (format == LS_HDF5)
-        {
-          // FIXME: It should be possible to append to HDF5 files.
-          if (append)
-            error ("save: appending to HDF5 files is not implemented");
-
-          bool write_header_info
-            = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
-
-          hdf5_ofstream hdf5_file (fname.c_str (), mode);
-
-          if (hdf5_file.file_id == -1)
-            err_file_open ("save", fname);
-
-          save_vars (argv, i, argc, hdf5_file, format,
-                     save_as_floats, write_header_info);
-
-          hdf5_file.close ();
-        }
-      else
-#endif
-        // don't insert any statements here!  The brace below must go
-        // with the "else" above!
-        {
-#if defined (HAVE_ZLIB)
-          if (use_zlib)
-            {
-              gzofstream file (fname.c_str (), mode);
-
-              if (! file)
-                err_file_open ("save", fname);
-
-              bool write_header_info = ! file.tellp ();
-
-              save_vars (argv, i, argc, file, format,
-                         save_as_floats, write_header_info);
-
-              file.close ();
-            }
-          else
-#endif
-            {
-              std::ofstream file (fname.c_str (), mode);
-
-              if (! file)
-                err_file_open ("save", fname);
-
-              bool write_header_info = ! file.tellp ();
-
-              save_vars (argv, i, argc, file, format,
-                         save_as_floats, write_header_info);
-
-              file.close ();
-            }
-        }
-    }
-
-  return retval;
+  return load_save_sys.save (args, nargout);
 }
 
-DEFUN (crash_dumps_octave_core, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (crash_dumps_octave_core, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} crash_dumps_octave_core ()
 @deftypefnx {} {@var{old_val} =} crash_dumps_octave_core (@var{new_val})
 @deftypefnx {} {} crash_dumps_octave_core (@var{new_val}, "local")
@@ -1766,11 +1836,13 @@
 @seealso{octave_core_file_limit, octave_core_file_name, octave_core_file_options}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (crash_dumps_octave_core);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.crash_dumps_octave_core (args, nargout);
 }
 
-DEFUN (save_default_options, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (save_default_options, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} save_default_options ()
 @deftypefnx {} {@var{old_val} =} save_default_options (@var{new_val})
 @deftypefnx {} {} save_default_options (@var{new_val}, "local")
@@ -1786,11 +1858,13 @@
 @seealso{save, save_header_format_string, save_precision}
 @end deftypefn */)
 {
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (save_default_options);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.save_default_options (args, nargout);
 }
 
-DEFUN (octave_core_file_limit, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (octave_core_file_limit, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} octave_core_file_limit ()
 @deftypefnx {} {@var{old_val} =} octave_core_file_limit (@var{new_val})
 @deftypefnx {} {} octave_core_file_limit (@var{new_val}, "local")
@@ -1812,11 +1886,13 @@
 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (octave_core_file_limit);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.octave_core_file_limit (args, nargout);
 }
 
-DEFUN (octave_core_file_name, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (octave_core_file_name, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} octave_core_file_name ()
 @deftypefnx {} {@var{old_val} =} octave_core_file_name (@var{new_val})
 @deftypefnx {} {} octave_core_file_name (@var{new_val}, "local")
@@ -1831,11 +1907,13 @@
 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}
 @end deftypefn */)
 {
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_name);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.octave_core_file_name (args, nargout);
 }
 
-DEFUN (octave_core_file_options, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (octave_core_file_options, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} octave_core_file_options ()
 @deftypefnx {} {@var{old_val} =} octave_core_file_options (@var{new_val})
 @deftypefnx {} {} octave_core_file_options (@var{new_val}, "local")
@@ -1852,11 +1930,13 @@
 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_limit}
 @end deftypefn */)
 {
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_options);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.octave_core_file_options (args, nargout);
 }
 
-DEFUN (save_header_format_string, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (save_header_format_string, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} save_header_format_string ()
 @deftypefnx {} {@var{old_val} =} save_header_format_string (@var{new_val})
 @deftypefnx {} {} save_header_format_string (@var{new_val}, "local")
@@ -1880,5 +1960,7 @@
 @seealso{strftime, save_default_options}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (save_header_format_string);
+  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
+
+  return load_save_sys.save_header_format_string (args, nargout);
 }
--- a/libinterp/corefcn/load-save.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/load-save.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,75 +30,264 @@
 
 #include "mach-info.h"
 
-namespace octave
-{
-  class symbol_record;
-}
-
 class string_vector;
 class octave_value;
 
-// FIXME: maybe MAT5 and MAT7 should be options to MAT_BINARY.
-// Similarly, save_as_floats may be an option for LS_BINARY, LS_HDF5 etc.
-enum load_save_format_type
-{
-  LS_TEXT,
-  LS_BINARY,
-  LS_MAT_ASCII,
-  LS_MAT_BINARY,
-  LS_MAT5_BINARY,
-  LS_MAT7_BINARY,
-  LS_HDF5,
-  LS_UNKNOWN
-};
-
-enum load_save_format_options
+namespace octave
 {
-  // LS_MAT_ASCII options (not exclusive)
-  LS_MAT_ASCII_LONG = 1,
-  LS_MAT_ASCII_TABS = 2,
-  // LS_MAT_BINARY options
-  LS_MAT_BINARY_V5 = 1,
-  LS_MAT_BINARY_V7,
-  // zero means no option.
-  LS_NO_OPTION = 0
-};
+  class interpreter;
+  class load_save_format;
+  class symbol_info;
+
+  class load_save_system
+  {
+  public:
+
+    // FIXME: maybe MAT5 and MAT7 should be options to MAT_BINARY.
+    // Similarly, save_as_floats may be an option for LS_BINARY,
+    // LS_HDF5 etc.
+
+    enum format_type
+      {
+        TEXT,
+        BINARY,
+        MAT_ASCII,
+        MAT_BINARY,
+        MAT5_BINARY,
+        MAT7_BINARY,
+        HDF5,
+        UNKNOWN
+      };
+
+    enum format_options
+      {
+        // MAT_ASCII options (not exclusive)
+        MAT_ASCII_LONG = 1,
+        MAT_ASCII_TABS = 2,
+        // MAT_BINARY options
+        MAT_BINARY_V5 = 1,
+        MAT_BINARY_V7,
+        // zero means no option.
+        NO_OPTION = 0
+      };
+
+    load_save_system (interpreter& interp);
+
+    ~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);
+
+    bool crash_dumps_octave_core (void) const
+    {
+      return m_crash_dumps_octave_core;
+    }
+
+    bool crash_dumps_octave_core (bool flag)
+    {
+      return set (m_crash_dumps_octave_core, flag);
+    }
+
+    octave_value octave_core_file_limit (const octave_value_list& args,
+                                         int nargout);
+
+    double octave_core_file_limit (void) const
+    {
+      return m_octave_core_file_limit;
+    }
+
+    double octave_core_file_limit (double limit)
+    {
+      return set (m_octave_core_file_limit, limit);
+    }
+
+    octave_value octave_core_file_name (const octave_value_list& args,
+                                        int nargout);
+
+    std::string octave_core_file_name (void) const
+    {
+      return m_octave_core_file_name;
+    }
+
+    std::string octave_core_file_name (const std::string& file)
+    {
+      return set (m_octave_core_file_name, file);
+    }
+
+    octave_value save_default_options (const octave_value_list& args,
+                                       int nargout);
+
+    std::string save_default_options (void) const
+    {
+      return m_save_default_options;
+    }
+
+    std::string save_default_options (const std::string& options)
+    {
+      return set (m_save_default_options, options);
+    }
+
+    octave_value octave_core_file_options (const octave_value_list& args,
+                                           int nargout);
+
+    std::string octave_core_file_options (void) const
+    {
+      return m_octave_core_file_options;
+    }
+
+    std::string octave_core_file_options (const std::string& options)
+    {
+      return set (m_octave_core_file_options, options);
+    }
+
+    octave_value save_header_format_string (const octave_value_list& args,
+                                            int nargout);
+
+    std::string save_header_format_string (void) const
+    {
+      return m_save_header_format_string;
+    }
+
+    std::string save_header_format_string (const std::string& format)
+    {
+      return set (m_save_header_format_string, format);
+    }
 
-class load_save_format
-{
-public:
-  load_save_format (load_save_format_type t,
-                    load_save_format_options o = LS_NO_OPTION)
-    : type (t), opts (o) { }
-  operator int (void) const
-  { return type; }
-  int type, opts;
-};
+    static 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);
+
+    static 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
+    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);
+
+    void dump_octave_core (void);
+
+    octave_value_list
+    load (const octave_value_list& args = octave_value_list (),
+          int nargout = 0);
+
+    octave_value_list
+    save (const octave_value_list& args = octave_value_list (),
+          int nargout = 0);
+
+  private:
+
+    interpreter& m_interpreter;
+
+    // Write octave-workspace file if Octave crashes or is killed by a
+    // signal.
+    bool m_crash_dumps_octave_core;
+
+    // The maximum amount of memory (in kilobytes) that we will
+    // attempt to write to the Octave core file.
+    double m_octave_core_file_limit;
+
+    // The name of the Octave core file.
+    std::string m_octave_core_file_name;
+
+    // The default output format.  May be one of "binary", "text",
+    // "mat-binary", or "hdf5".
+    std::string m_save_default_options;
+
+    // The output format for Octave core files.
+    std::string m_octave_core_file_options;
+
+    // The format string for the comment line at the top of
+    // text-format save files.  Passed to strftime.  Should begin with
+    // '#' and contain no newline characters.
+    std::string m_save_header_format_string;
+
+    void write_header (std::ostream& os, const load_save_format& fmt);
+
+    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);
+
+    void do_save (std::ostream& os, const symbol_info& syminfo,
+                  const load_save_format& fmt, bool save_as_floats);
+
+    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);
+
+    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 load_save_format get_file_format (std::istream& file,
+                                             const std::string& filename);
+
+    template <typename T>
+    T set (T& var, const T& new_val)
+    {
+      T old_val = var;
+      var = new_val;
+      return old_val;
+    }
+  };
+
+  class load_save_format
+  {
+  public:
+
+    load_save_format (load_save_system::format_type type,
+                      load_save_system::format_options options = load_save_system::NO_OPTION)
+      : m_type (type), m_options (options)
+    { }
+
+    void set_type (load_save_system::format_type type) { m_type = type; }
+
+    load_save_system::format_type type (void) const { return m_type; }
+
+    void set_option (load_save_system::format_options option)
+    {
+      m_options |= option;
+    }
+
+    int options (void) const { return m_options; }
+
+  private:
+
+    load_save_system::format_type m_type;
+    int m_options;
+  };
+}
 
 extern void dump_octave_core (void);
 
-extern int
-read_binary_file_header (std::istream& is, bool& swap,
-                         octave::mach_info::float_format& flt_fmt,
-                         bool quiet = false);
-
-extern octave_value
-do_load (std::istream& stream, const std::string& orig_fname,
-         load_save_format format, octave::mach_info::float_format flt_fmt,
-         bool list_only, bool swap, bool verbose,
-         const string_vector& argv, int argv_idx, int argc, int nargout);
-
-extern OCTINTERP_API bool is_octave_data_file (const std::string& file);
-
-extern void
-do_save (std::ostream& os, const octave::symbol_record& sr,
-         load_save_format fmt, bool save_as_floats);
-
-extern void
-write_header (std::ostream& os, load_save_format format);
-
-extern void octave_prepare_hdf5 (void);
-
-extern void octave_finalize_hdf5 (void);
-
 #endif
--- a/libinterp/corefcn/ls-ascii-helper.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-ascii-helper.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
 
 #include "ls-ascii-helper.h"
 
-#include <iostream>
+#include <istream>
 #include <sstream>
 
 // Helper functions when reading from ascii files.
--- a/libinterp/corefcn/ls-hdf5.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-hdf5.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,8 +31,9 @@
 #include <cctype>
 
 #include <iomanip>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <string>
 #include <vector>
 
@@ -59,7 +60,6 @@
 #include "oct-map.h"
 #include "ov-cell.h"
 #include "pager.h"
-#include "pt-exp.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -88,19 +88,7 @@
   : file_id (-1), current_item (-1)
 {
 #if defined (HAVE_HDF5)
-
-  if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
-  else if (mode & std::ios::out)
-    {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
-      else
-        file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
-                             octave_H5P_DEFAULT);
-    }
-  if (file_id < 0)
-    std::ios::setstate (std::ios::badbit);
+  open_create (name, mode);
 
   current_item = 0;
 
@@ -136,20 +124,105 @@
 
   clear ();
 
+  open_create (name, mode);
+
+  current_item = 0;
+
+#else
+  // This shouldn't happen because construction of hdf5_fstreambase
+  // objects is supposed to be impossible if HDF5 is not available.
+
+  panic_impossible ();
+#endif
+}
+
+void
+hdf5_fstreambase::open_create (const char *name, int mode)
+{
+#if defined (HAVE_HDF5)
+  // Open the HDF5 file NAME. If it does not exist, create the file.
+
+  std::string fname_str (name);
+  std::string ascii_fname_str = octave::sys::get_ASCII_filename (fname_str);
+  const char *ascii_fname = ascii_fname_str.c_str ();
+
   if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
+    file_id = H5Fopen (ascii_fname, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
   else if (mode & std::ios::out)
     {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+      if (mode & std::ios::app && H5Fis_hdf5 (ascii_fname) > 0)
+        file_id = H5Fopen (ascii_fname, H5F_ACC_RDWR, octave_H5P_DEFAULT);
       else
+#  if defined (OCTAVE_USE_WINDOWS_API)
+        {
+          // Check whether file already exists
+          std::string abs_ascii_fname
+            = octave::sys::canonicalize_file_name (ascii_fname_str);
+          if (! abs_ascii_fname.empty ())
+            {
+              // Use the existing file
+              file_id = H5Fcreate (ascii_fname, H5F_ACC_TRUNC,
+                                   octave_H5P_DEFAULT, octave_H5P_DEFAULT);
+              if (file_id < 0)
+                std::ios::setstate (std::ios::badbit);
+
+              return;
+            }
+
+          // Check whether filename contains non-ASCII (UTF-8) characters.
+          std::string::const_iterator first_non_ASCII
+            = std::find_if (fname_str.begin (), fname_str.end (),
+                            [](char c) { return (c < 0 || c >= 128); });
+          if (first_non_ASCII == fname_str.end ())
+            {
+              // No non-ASCII characters
+              file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
+                                   octave_H5P_DEFAULT);
+              if (file_id < 0)
+                std::ios::setstate (std::ios::badbit);
+
+              return;
+            }
+
+          // Create file in temp folder
+          std::string tmp_name = octave::sys::tempnam ("", "oct-");
+          octave_hdf5_id hdf5_fid = H5Fcreate (tmp_name.c_str (), H5F_ACC_TRUNC,
+                                               octave_H5P_DEFAULT,
+                                               octave_H5P_DEFAULT);
+          if (hdf5_fid < 0)
+            {
+              file_id = -1;
+              std::ios::setstate (std::ios::badbit);
+              return;
+            }
+
+          // Close file
+          H5Fclose (hdf5_fid);
+
+          // Move temporary file to final destination
+          std::string msg;
+          int res = octave::sys::rename (tmp_name, name, msg);
+          if (res < 0)
+            {
+              std::ios::setstate (std::ios::badbit);
+              file_id = -1;
+              return;
+            }
+
+          // Open file at final location
+          ascii_fname_str = octave::sys::get_ASCII_filename (fname_str);
+          ascii_fname = ascii_fname_str.c_str ();
+          file_id = H5Fopen (ascii_fname, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+        }
+#  else
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
+#  endif
     }
   if (file_id < 0)
     std::ios::setstate (std::ios::badbit);
 
-  current_item = 0;
+  return;
 
 #else
   // This shouldn't happen because construction of hdf5_fstreambase
@@ -363,7 +436,7 @@
 
   H5G_stat_t info;
   herr_t retval = 0;
-  bool ident_valid = valid_identifier (name);
+  bool ident_valid = octave::valid_identifier (name);
 
   std::string vname = name;
 
@@ -379,7 +452,7 @@
       vname = make_valid_identifier (vname);
 
       // check again (in case vname was null, empty, or some such thing):
-      ident_valid = valid_identifier (vname);
+      ident_valid = octave::valid_identifier (vname);
     }
 
   H5Gget_objinfo (group_id, name, 1, &info);
--- a/libinterp/corefcn/ls-hdf5.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-hdf5.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 
 #include "octave-config.h"
 
-#include <iostream>
+#include <iosfwd>
 
 #include "oct-hdf5-types.h"
 #include "ov.h"
@@ -55,6 +55,8 @@
   void close (void);
 
   void open (const char *name, int mode, int);
+
+  void open_create (const char *name, int mode);
 };
 
 // input and output streams, subclassing istream and ostream
--- a/libinterp/corefcn/ls-mat-ascii.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-mat-ascii.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,8 @@
 #include <cctype>
 
 #include <iomanip>
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <sstream>
 #include <string>
 
@@ -54,7 +55,6 @@
 #include "ov-cell.h"
 #include "ov.h"
 #include "pager.h"
-#include "pt-exp.h"
 #include "sysdep.h"
 #include "utils.h"
 #include "variables.h"
@@ -248,17 +248,17 @@
         varname[i] = '_';
     }
 
-  if (octave::is_keyword (varname) || ! isalpha (varname[0]))
+  if (octave::iskeyword (varname) || ! isalpha (varname[0]))
     varname.insert (0, "X");
 
-  if (! valid_identifier (varname))
+  if (! octave::valid_identifier (varname))
     error ("load: unable to convert filename '%s' to valid identifier",
            filename.c_str ());
 
   octave_idx_type nr = 0;
   octave_idx_type nc = 0;
 
-  int total_count = 0;
+  octave_idx_type total_count = 0;
 
   get_lines_and_columns (is, nr, nc, filename);
 
@@ -328,8 +328,8 @@
   octave_idx_type expected = nr * nc;
 
   if (expected != total_count)
-    error ("load: expected %d elements, found %d",
-           expected, total_count);
+    error ("load: expected %" OCTAVE_IDX_TYPE_FORMAT " elements, found "
+           "%" OCTAVE_IDX_TYPE_FORMAT, expected, total_count);
 
   tc = tmp;
 
--- a/libinterp/corefcn/ls-mat4.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-mat4.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #endif
 
 #include <iomanip>
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <string>
 
 #include "byte-swap.h"
@@ -51,7 +52,6 @@
 #include "ov-cell.h"
 #include "ovl.h"
 #include "pager.h"
-#include "pt-exp.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
--- a/libinterp/corefcn/ls-mat5.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-mat5.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,8 +29,9 @@
 #include <cstring>
 
 #include <iomanip>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -69,7 +70,6 @@
 #include "ovl.h"
 #include "pager.h"
 #include "parse.h"
-#include "pt-exp.h"
 #include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
@@ -510,6 +510,9 @@
   if (read_mat5_tag (is, swap, type, element_length, is_small_data_element))
     return retval;                      // EOF
 
+  octave::interpreter& interp
+    = octave::__get_interpreter__ ("read_mat5_binary_element");
+
   if (type == miCOMPRESSED)
     {
 #if defined (HAVE_ZLIB)
@@ -903,7 +906,7 @@
                         names.push_back (fname + ".mex");
                         names.push_back (fname + ".m");
 
-                        octave::load_path& lp = octave::__get_load_path__ ("read_mat5_binary_element");
+                        octave::load_path& lp = interp.get_load_path ();
 
                         octave::directory_path p (lp.system_path ());
 
@@ -962,7 +965,7 @@
               = m1.contents ("workspace").scalar_map_value ();
             uint32NDArray MCOS = m2.contents ("MCOS").uint32_array_value ();
             octave_idx_type off
-              = static_cast<octave_idx_type>(MCOS(4).double_value ());
+              = static_cast<octave_idx_type> (MCOS(4).double_value ());
             m2 = subsys_ov.scalar_map_value ();
             m2 = m2.contents ("MCOS").scalar_map_value ();
             tc2 = m2.contents ("MCOS").cell_value ()(1 + off).cell_value ()(1);
@@ -973,15 +976,13 @@
             // Set up temporary scope to use for evaluating the text
             // that defines the anonymous function.
 
-            octave::symbol_table& symtab
-              = octave::__get_symbol_table__ ("read_mat5_binary_element");
+            octave::symbol_table& symtab = interp.get_symbol_table ();
 
             octave::symbol_scope local_scope;
 
             symtab.set_scope (local_scope);
 
-            octave::call_stack& cs
-              = octave::__get_call_stack__ ("read_mat5_binary_element");
+            octave::call_stack& cs = interp.get_call_stack ();
             cs.push (local_scope, 0);
             frame.add_method (cs, &octave::call_stack::pop);
 
@@ -989,8 +990,7 @@
               {
                 octave_value tmp;
 
-                for (octave_map::iterator p0 = m2.begin () ;
-                     p0 != m2.end (); p0++)
+                for (auto p0 = m2.begin (); p0 != m2.end (); p0++)
                   {
                     std::string key = m2.key (p0);
                     octave_value val = m2.contents (p0);
@@ -1000,8 +1000,8 @@
               }
 
             int parse_status;
-            octave_value anon_fcn_handle =
-              octave::eval_string (fname.substr (4), true, parse_status);
+            octave_value anon_fcn_handle
+              = interp.eval_string (fname.substr (4), true, parse_status);
 
             if (parse_status != 0)
               error ("load: failed to load anonymous function handle");
@@ -1191,8 +1191,7 @@
               }
             else
               {
-                cdef_manager& cdm
-                  = octave::__get_cdef_manager__ ("read_mat5_binary_element");
+                cdef_manager& cdm = interp.get_cdef_manager ();
 
                 if (cdm.find_class (classname, false, true).ok ())
                   {
@@ -1213,7 +1212,7 @@
 
                         tc = cls;
 
-                        octave::load_path& lp = octave::__get_load_path__ ("read_mat5_binary_element");
+                        octave::load_path& lp = interp.get_load_path ();
 
                         if (lp.find_method (classname, "loadobj") != "")
                           {
@@ -2189,7 +2188,7 @@
           ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen);
         }
 
-      for (octave_map::const_iterator i = m.begin (); i != m.end (); i++)
+      for (auto i = m.begin (); i != m.end (); i++)
         fieldcnt++;
 
       ret += 16 + fieldcnt * (max_namelen + 1);
@@ -2197,7 +2196,7 @@
       for (octave_idx_type j = 0; j < nel; j++)
         {
 
-          for (octave_map::const_iterator i = m.begin (); i != m.end (); i++)
+          for (auto i = m.begin (); i != m.end (); i++)
             {
               const Cell elts = m.contents (i);
 
@@ -2611,7 +2610,8 @@
 
       octave_map m;
 
-      octave::load_path& lp = octave::__get_load_path__ ("read_mat5_binary_element");
+      octave::load_path& lp
+        = octave::__get_load_path__ ("save_mat5_binary_element");
 
       if (tc.isobject ()
           && lp.find_method (tc.class_name (), "saveobj") != "")
--- a/libinterp/corefcn/ls-oct-binary.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-oct-binary.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <string>
 
 #include "byte-swap.h"
@@ -47,7 +48,6 @@
 #include "ov-cell.h"
 #include "ov.h"
 #include "pager.h"
-#include "pt-exp.h"
 #include "sysdep.h"
 #include "utils.h"
 #include "variables.h"
--- a/libinterp/corefcn/ls-oct-text.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ls-oct-text.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,7 +31,8 @@
 
 #include <fstream>
 #include <iomanip>
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <sstream>
 #include <string>
 
@@ -58,7 +59,6 @@
 #include "oct-map.h"
 #include "ov-cell.h"
 #include "pager.h"
-#include "pt-exp.h"
 #include "unwind-prot.h"
 #include "utils.h"
 #include "variables.h"
@@ -252,7 +252,7 @@
     }
 
   if (! (name == ".nargin." || name == ".nargout."
-         || name == CELL_ELT_TAG || valid_identifier (name)))
+         || name == CELL_ELT_TAG || octave::valid_identifier (name)))
     error ("load: invalid identifier '%s' found in file '%s'",
            name.c_str (), filename.c_str ());
 
@@ -375,7 +375,7 @@
     {
       octave_idx_type extras = nc % 3;
       if (extras)
-        warning ("ignoring last %d columns", extras);
+        warning ("ignoring last %" OCTAVE_IDX_TYPE_FORMAT " columns", extras);
 
       Matrix tmp = tc.matrix_value ();
       nr = tmp.rows ();
--- a/libinterp/corefcn/lsode.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/lsode.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,9 +26,6 @@
 
 #include <string>
 
-#include <iomanip>
-#include <iostream>
-
 #include "LSODE.h"
 #include "lo-mappers.h"
 
--- a/libinterp/corefcn/mappers.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/mappers.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -1214,6 +1214,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]));
 
 %!error isalnum ()
 %!error isalnum (1, 2)
@@ -1242,6 +1243,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]));
 
 %!error isalpha ()
 %!error isalpha (1, 2)
@@ -1317,6 +1319,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]));
 
 %!error isdigit ()
 %!error isdigit (1, 2)
@@ -1383,6 +1386,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]));
 
 %!error isgraph ()
 %!error isgraph (1, 2)
@@ -1408,6 +1412,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]));
 
 %!error islower ()
 %!error islower (1, 2)
@@ -1514,6 +1519,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]));
 
 %!error isprint ()
 %!error isprint (1, 2)
@@ -1542,6 +1548,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]));
 
 %!error ispunct ()
 %!error ispunct (1, 2)
@@ -1568,6 +1575,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]));
 
 %!error isspace ()
 %!error isspace (1, 2)
@@ -1593,6 +1601,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]));
 
 %!error isupper ()
 %!error isupper (1, 2)
@@ -1620,6 +1629,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]));
 
 %!error isxdigit ()
 %!error isxdigit (1, 2)
@@ -2139,6 +2149,8 @@
 %!assert (tolower ({"ABC", "DEF", {"GHI", {"JKL"}}}), {"abc", "def", {"ghi", {"jkl"}}})
 %!assert (tolower (["ABC"; "DEF"]), ["abc"; "def"])
 %!assert (tolower ({["ABC"; "DEF"]}), {["abc";"def"]})
+%!assert (tolower (["ABCÄÖÜSS"; "abcäöüß"]), ["abcäöüss"; "abcäöüß"])
+%!assert (tolower (repmat ("ÄÖÜ", 2, 1, 3)), repmat ("äöü", 2, 1, 3))
 %!assert (tolower (68), 68)
 %!assert (tolower ({[68, 68; 68, 68]}), {[68, 68; 68, 68]})
 %!assert (tolower (68i), 68i)
@@ -2203,6 +2215,8 @@
 %!assert (toupper ({"abc", "def", {"ghi", {"jkl"}}}), {"ABC", "DEF", {"GHI", {"JKL"}}})
 %!assert (toupper (["abc"; "def"]), ["ABC"; "DEF"])
 %!assert (toupper ({["abc"; "def"]}), {["ABC";"DEF"]})
+%!assert (toupper (["ABCÄÖÜSS"; "abcäöüß"]), ["ABCÄÖÜSS"; "ABCÄÖÜSS"])
+%!assert (toupper (repmat ("äöü", 2, 1, 3)), repmat ("ÄÖÜ", 2, 1, 3))
 %!assert (toupper (100), 100)
 %!assert (toupper ({[100, 100; 100, 100]}), {[100, 100; 100, 100]})
 %!assert (toupper (100i), 100i)
--- a/libinterp/corefcn/mex.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/mex.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -1163,7 +1163,7 @@
         for (size_t i = 0; i < tmp_len; i++)
           cpr[m*i+j] = static_cast<mxChar> (ptr[i]);
 
-        for (size_t i = tmp_len; i < static_cast<size_t>(nc); i++)
+        for (size_t i = tmp_len; i < static_cast<size_t> (nc); i++)
           cpr[m*i+j] = static_cast<mxChar> (' ');
       }
   }
@@ -1890,7 +1890,7 @@
 
     string_vector keys (fields, nfields);
 
-    octave_map m;
+    octave_map m (dv);
 
     mwSize ntot = nfields * get_number_of_elements ();
 
@@ -2132,7 +2132,7 @@
     // We can't use mex::free here because it modifies memlist.
     while (! memlist.empty ())
       {
-        std::set<void *>::iterator p = memlist.begin ();
+        auto p = memlist.begin ();
         xfree (*p);
         memlist.erase (p);
       }
@@ -2140,7 +2140,7 @@
     // We can't use mex::free_value here because it modifies arraylist.
     while (! arraylist.empty ())
       {
-        std::set<mxArray *>::iterator p = arraylist.begin ();
+        auto p = arraylist.begin ();
         delete *p;
         arraylist.erase (p);
       }
@@ -2180,7 +2180,7 @@
     if (! ptr)
       {
         // FIXME: could use "octave_new_handler();" instead
-        error ("%s: failed to allocate %d bytes of memory",
+        error ("%s: failed to allocate %zd bytes of memory",
                function_name (), n);
       }
 
@@ -2230,7 +2230,7 @@
       {
         v = std::realloc (ptr, n);
 
-        std::set<void *>::iterator p = memlist.find (ptr);
+        auto p = memlist.find (ptr);
 
         if (v && p != memlist.end ())
           {
@@ -2259,7 +2259,7 @@
       {
         unmark (ptr);
 
-        std::set<void *>::iterator p = global_memlist.find (ptr);
+        auto p = global_memlist.find (ptr);
 
         if (p != global_memlist.end ())
           {
@@ -2296,7 +2296,7 @@
   // made persistent, or because it was already freed.
   void unmark (void *ptr)
   {
-    std::set<void *>::iterator p = memlist.find (ptr);
+    auto p = memlist.find (ptr);
 
     if (p != memlist.end ())
       memlist.erase (p);
@@ -2314,7 +2314,7 @@
 
   void unmark_array (mxArray *ptr)
   {
-    std::set<mxArray *>::iterator p = arraylist.find (ptr);
+    auto p = arraylist.find (ptr);
 
     if (p != arraylist.end ())
       arraylist.erase (p);
@@ -2334,7 +2334,7 @@
   // Unmark a pointer as one we allocated.
   void unmark_foreign (void *ptr)
   {
-    std::set<void *>::iterator p = foreign_memlist.find (ptr);
+    auto p = foreign_memlist.find (ptr);
 
     if (p != foreign_memlist.end ())
       foreign_memlist.erase (p);
@@ -2357,7 +2357,7 @@
   {
     bool inlist = false;
 
-    std::set<mxArray *>::iterator p = arraylist.find (ptr);
+    auto p = arraylist.find (ptr);
 
     if (p != arraylist.end ())
       {
@@ -2416,7 +2416,7 @@
   // Unmark a pointer as one we allocated.
   void global_unmark (void *ptr)
   {
-    std::set<void *>::iterator p = global_memlist.find (ptr);
+    auto p = global_memlist.find (ptr);
 
     if (p != global_memlist.end ())
       global_memlist.erase (p);
@@ -3320,7 +3320,10 @@
 
   try
     {
-      ret = octave::eval_string (s, false, parse_status, 0);
+      octave::interpreter& interp
+        = octave::__get_interpreter__ ("mexEvalString");
+
+      ret = interp.eval_string (std::string (s), false, parse_status, 0);
     }
   catch (const octave::execution_exception&)
     {
@@ -3347,7 +3350,10 @@
 
   try
     {
-      ret = octave::eval_string (s, false, parse_status, 0);
+      octave::interpreter& interp
+        = octave::__get_interpreter__ ("mexEvalString");
+
+      ret = interp.eval_string (std::string (s), false, parse_status, 0);
     }
   catch (const octave::execution_exception&)
     {
@@ -3374,8 +3380,18 @@
 void
 mexErrMsgTxt (const char *s)
 {
-  if (s && strlen (s) > 0)
-    error ("%s: %s", mexFunctionName (), s);
+  size_t len;
+
+  if (s && (len = strlen (s)) > 0)
+    {
+      if (s[len - 1] == '\n')
+        {
+          std::string s_tmp (s, len - 1);
+          error ("%s: %s\n", mexFunctionName (), s_tmp.c_str ());
+        }
+      else
+        error ("%s: %s", mexFunctionName (), s);
+    }
   else
     {
       // For compatibility with Matlab, print an empty message.
@@ -3409,7 +3425,24 @@
 void
 mexWarnMsgTxt (const char *s)
 {
-  warning ("%s", s);
+  size_t len;
+
+  if (s && (len = strlen (s)) > 0)
+    {
+      if (s[len - 1] == '\n')
+        {
+          std::string s_tmp (s, len - 1);
+          warning ("%s\n", s_tmp.c_str ());
+        }
+      else
+        warning ("%s", s);
+    }
+  else
+    {
+      // For compatibility with Matlab, print an empty message.
+      // Octave's warning routine requires a non-null input so use a SPACE.
+      warning (" ");
+    }
 }
 
 void
@@ -3437,7 +3470,7 @@
   int retval;
   va_list args;
   va_start (args, fmt);
-  retval = octave_vformat (octave_stdout, fmt, args);
+  retval = octave::vformat (octave_stdout, fmt, args);
   va_end (args);
   return retval;
 }
@@ -3662,7 +3695,7 @@
     {
       const char *fname = mexFunctionName ();
 
-      std::map<std::string,int>::iterator p = mex_lock_count.find (fname);
+      auto p = mex_lock_count.find (fname);
 
       if (p != mex_lock_count.end ())
         {
--- a/libinterp/corefcn/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,6 @@
   %reldir%/gl2ps-print.h \
   %reldir%/graphics-handle.h \
   %reldir%/graphics-toolkit.h \
-  %reldir%/gripes.h \
   %reldir%/gtk-manager.h \
   %reldir%/help.h \
   %reldir%/hook-fcn.h \
@@ -79,13 +78,16 @@
   %reldir%/pr-flt-fmt.h \
   %reldir%/pr-output.h \
   %reldir%/procstream.h \
+  %reldir%/settings.h \
   %reldir%/sighandlers.h \
   %reldir%/sparse-xdiv.h \
   %reldir%/sparse-xpow.h \
+  %reldir%/syminfo.h \
   %reldir%/symrec.h \
   %reldir%/symscope.h \
   %reldir%/symtab.h \
   %reldir%/sysdep.h \
+  %reldir%/text-engine.h \
   %reldir%/text-renderer.h \
   %reldir%/toplev.h \
   %reldir%/txt-eng.h \
@@ -165,7 +167,6 @@
   %reldir%/gl2ps-print.cc \
   %reldir%/graphics-toolkit.cc \
   %reldir%/graphics.cc \
-  %reldir%/gripes.cc \
   %reldir%/gsvd.cc \
   %reldir%/gtk-manager.cc \
   %reldir%/hash.cc \
@@ -224,29 +225,30 @@
   %reldir%/rcond.cc \
   %reldir%/regexp.cc \
   %reldir%/schur.cc \
+  %reldir%/settings.cc \
   %reldir%/sighandlers.cc \
   %reldir%/sparse-xdiv.cc \
   %reldir%/sparse-xpow.cc \
   %reldir%/sparse.cc \
   %reldir%/spparms.cc \
   %reldir%/sqrtm.cc \
-  %reldir%/str2double.cc \
   %reldir%/strfind.cc \
   %reldir%/strfns.cc \
   %reldir%/sub2ind.cc \
   %reldir%/svd.cc \
   %reldir%/sylvester.cc \
+  %reldir%/syminfo.cc \
   %reldir%/symrec.cc \
   %reldir%/symscope.cc \
   %reldir%/symtab.cc \
   %reldir%/syscalls.cc \
   %reldir%/sysdep.cc \
   %reldir%/time.cc \
+  %reldir%/text-engine.cc \
   %reldir%/text-renderer.cc \
   %reldir%/toplev.cc \
   %reldir%/tril.cc \
   %reldir%/tsearch.cc \
-  %reldir%/txt-eng.cc \
   %reldir%/typecast.cc \
   %reldir%/urlwrite.cc \
   %reldir%/url-handle-manager.cc \
@@ -260,8 +262,8 @@
 
 ## Special rules for sources which must be built before rest of compilation.
 
-%reldir%/default-defs.h: %reldir%/default-defs.in.h build-aux/subst-default-vals.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-default-vals.sh)
+%reldir%/default-defs.h: %reldir%/default-defs.in.h build-aux/subst-config-vals.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-config-vals.sh)
 
 %reldir%/graphics.h: %reldir%/graphics.in.h %reldir%/genprops.awk | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)rm -f $@-t && \
@@ -299,9 +301,6 @@
 
 %reldir%/oct-tex-lexer.cc: LEX_OUTPUT_ROOT := lex.octave_tex_
 
-%reldir%/oct-tex-parser.yy: %reldir%/oct-tex-parser.in.yy
-	$(AM_V_GEN)$(call subst-bison-api-decls,octave_tex_)
-
 noinst_LTLIBRARIES += \
   %reldir%/libcorefcn.la
 
@@ -316,10 +315,6 @@
   $(LLVM_CPPFLAGS) \
   $(Z_CPPFLAGS)
 
-%canon_reldir%_libcorefcn_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
-
-%canon_reldir%_libcorefcn_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS) $(LLVM_CXXFLAGS)
-
 libinterp_EXTRA_DIST += \
   %reldir%/default-defs.in.h \
   %reldir%/genprops.awk \
@@ -329,7 +324,6 @@
   %reldir%/mxarray.in.h \
   %reldir%/oct-errno.in.cc \
   %reldir%/oct-tex-lexer.in.ll \
-  %reldir%/oct-tex-parser.in.yy \
   %reldir%/oct-tex-symbols.in
 
 GEN_CONFIG_SHELL += \
--- a/libinterp/corefcn/mxarray.in.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/mxarray.in.h	Thu Dec 20 17:18:56 2018 -0500
@@ -303,12 +303,6 @@
 
   mxArray_base (const mxArray_base&) { }
 
-  OCTAVE_DEPRECATED (4.2, "use 'err_invalid_type' instead")
-  void invalid_type_error (void) const
-  {
-    error ("invalid type for operation");
-  }
-
   OCTAVE_NORETURN void err_invalid_type (void) const
   {
     error ("invalid type for operation");
--- a/libinterp/corefcn/oct-hist.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-hist.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,7 +50,6 @@
 #include "str-vec.h"
 #include "unistd-wrappers.h"
 
-#include "defaults.h"
 #include "defun.h"
 #include "error.h"
 #include "errwarn.h"
@@ -66,489 +65,496 @@
 #include "utils.h"
 #include "variables.h"
 
-// TRUE means input is coming from temporary history file.
-bool input_from_tmp_history_file = false;
-
-static std::string
-default_history_file (void)
-{
-  std::string file;
-
-  std::string env_file = octave::sys::env::getenv ("OCTAVE_HISTFILE");
-
-  if (! env_file.empty ())
-    file = env_file;
-
-  if (file.empty ())
-    file = octave::sys::file_ops::concat (octave::sys::env::get_home_directory (),
-                                          ".octave_hist");
-
-  return file;
-}
-
-static int
-default_history_size (void)
-{
-  int size = 1000;
-
-  std::string env_size = octave::sys::env::getenv ("OCTAVE_HISTSIZE");
-
-  if (! env_size.empty ())
-    {
-      int val;
-
-      if (sscanf (env_size.c_str (), "%d", &val) == 1)
-        size = (val > 0 ? val : 0);
-    }
-
-  return size;
-}
-
-static std::string
-default_history_timestamp_format (void)
-{
-  return
-    "# Octave " OCTAVE_VERSION ", %a %b %d %H:%M:%S %Y %Z <"
-    + octave::sys::env::get_user_name ()
-    + '@'
-    + octave::sys::env::get_host_name ()
-    + '>';
-}
-
-// The format of the timestamp marker written to the history file when
-// Octave exits.
-static std::string Vhistory_timestamp_format_string
-  = default_history_timestamp_format ();
-
-// Display, save, or load history.  Stolen and modified from bash.
-//
-// Arg of -w FILENAME means write file, arg of -r FILENAME
-// means read file, arg of -q means don't number lines.  Arg of N
-// means only display that many items.
-
-static string_vector
-do_history (const octave_value_list& args, int nargout)
-{
-  bool numbered_output = nargout == 0;
-
-  octave::unwind_protect frame;
-
-  string_vector hlist;
-
-  frame.add_fcn (octave::command_history::set_file,
-                 octave::command_history::file ());
-
-  int nargin = args.length ();
-
-  // Number of history lines to show (-1 = all)
-  int limit = -1;
-
-  for (octave_idx_type i = 0; i < nargin; i++)
-    {
-      octave_value arg = args(i);
-
-      std::string option;
-
-      if (arg.is_string ())
-        option = arg.string_value ();
-      else if (arg.isnumeric ())
-        {
-          limit = arg.int_value ();
-          if (limit < 0)
-            limit = -limit;
-          continue;
-        }
-      else
-        err_wrong_type_arg ("history", arg);
-
-      if (option == "-r" || option == "-w" || option == "-a"
-          || option == "-n")
-        {
-          if (i < nargin - 1)
-            {
-              std::string fname
-                = args(++i).xstring_value ("history: filename must be a string for %s option",
-                                           option.c_str ());
-
-              octave::command_history::set_file (fname);
-            }
-          else
-            octave::command_history::set_file (default_history_file ());
-
-          if (option == "-a")
-            // Append 'new' lines to file.
-            octave::command_history::append ();
-
-          else if (option == "-w")
-            // Write entire history.
-            octave::command_history::write ();
-
-          else if (option == "-r")
-            {
-              // Read entire file.
-              octave::command_history::read ();
-              octave_link::set_history (octave::command_history::list ());
-            }
-
-          else if (option == "-n")
-            {
-              // Read 'new' history from file.
-              octave::command_history::read_range ();
-              octave_link::set_history (octave::command_history::list ());
-            }
-
-          else
-            panic_impossible ();
-
-          return hlist;
-        }
-      else if (option == "-c")
-        {
-          octave::command_history::clear ();
-          octave_link::clear_history ();
-        }
-      else if (option == "-q")
-        numbered_output = false;
-      else if (option == "--")
-        {
-          i++;
-          break;
-        }
-      else
-        {
-          // The last argument found in the command list that looks like
-          // an integer will be used
-          int tmp;
-
-          if (sscanf (option.c_str (), "%d", &tmp) == 1)
-            {
-              if (tmp > 0)
-                limit = tmp;
-              else
-                limit = -tmp;
-            }
-
-          else
-            {
-              if (option.length () > 0 && option[0] == '-')
-                error ("history: unrecognized option '%s'", option.c_str ());
-              else
-                error ("history: bad non-numeric arg '%s'", option.c_str ());
-            }
-        }
-    }
-
-  hlist = octave::command_history::list (limit, numbered_output);
-
-  int len = hlist.numel ();
-
-  if (nargout == 0)
-    {
-      for (octave_idx_type i = 0; i < len; i++)
-        octave_stdout << hlist[i] << "\n";
-    }
-
-  return hlist;
-}
-
-// Read the edited history lines from STREAM and return them
-// one at a time.  This can read unlimited length lines.  The
-// caller should free the storage.
-
-static char *
-edit_history_readline (std::fstream& stream)
-{
-  char c;
-  int line_len = 128;
-  int lindex = 0;
-  char *line = new char [line_len];
-  line[0] = '\0';
-
-  while (stream.get (c))
-    {
-      if (lindex + 2 >= line_len)
-        {
-          char *tmp_line = new char [line_len += 128];
-          strcpy (tmp_line, line);
-          delete [] line;
-          line = tmp_line;
-        }
-
-      if (c == '\n')
-        {
-          line[lindex++] = '\n';
-          line[lindex++] = '\0';
-          return line;
-        }
-      else
-        line[lindex++] = c;
-    }
-
-  if (! lindex)
-    {
-      delete [] line;
-      return nullptr;
-    }
-
-  if (lindex + 2 >= line_len)
-    {
-      char *tmp_line = new char [lindex+3];
-      strcpy (tmp_line, line);
-      delete [] line;
-      line = tmp_line;
-    }
-
-  // Finish with newline if none in file.
-
-  line[lindex++] = '\n';
-  line[lindex++] = '\0';
-  return line;
-}
-
-static void
-edit_history_add_hist (const std::string& line)
+namespace octave
 {
-  if (! line.empty ())
-    {
-      std::string tmp = line;
+  // Read the edited history lines from STREAM and return them
+  // one at a time.  This can read unlimited length lines.  The
+  // caller should free the storage.
 
-      int len = tmp.length ();
+  static char *
+  edit_history_readline (std::fstream& stream)
+  {
+    char c;
+    int line_len = 128;
+    int lindex = 0;
+    char *line = new char [line_len];
+    line[0] = '\0';
 
-      if (len > 0 && tmp[len-1] == '\n')
-        tmp.resize (len - 1);
+    while (stream.get (c))
+      {
+        if (lindex + 2 >= line_len)
+          {
+            char *tmp_line = new char [line_len += 128];
+            strcpy (tmp_line, line);
+            delete [] line;
+            line = tmp_line;
+          }
 
-      if (! tmp.empty ())
-        if (octave::command_history::add (tmp))
-          octave_link::append_history (tmp);
-    }
-}
+        if (c == '\n')
+          {
+            line[lindex++] = '\n';
+            line[lindex++] = '\0';
+            return line;
+          }
+        else
+          line[lindex++] = c;
+      }
 
-static bool
-get_int_arg (const octave_value& arg, int& val)
-{
-  bool ok = true;
+    if (! lindex)
+      {
+        delete [] line;
+        return nullptr;
+      }
 
-  if (arg.is_string ())
-    {
-      std::string tmp = arg.string_value ();
+    if (lindex + 2 >= line_len)
+      {
+        char *tmp_line = new char [lindex+3];
+        strcpy (tmp_line, line);
+        delete [] line;
+        line = tmp_line;
+      }
+
+    // Finish with newline if none in file.
+
+    line[lindex++] = '\n';
+    line[lindex++] = '\0';
+    return line;
+  }
 
-      ok = sscanf (tmp.c_str (), "%d", &val) == 1;
-    }
-  else if (arg.isnumeric ())
-    val = arg.int_value ();
-  else
-    ok = false;
+  static void
+  edit_history_add_hist (const std::string& line)
+  {
+    if (! line.empty ())
+      {
+        std::string tmp = line;
+
+        int len = tmp.length ();
+
+        if (len > 0 && tmp[len-1] == '\n')
+          tmp.resize (len - 1);
 
-  return ok;
-}
+        if (! tmp.empty ())
+          if (octave::command_history::add (tmp))
+            octave_link::append_history (tmp);
+      }
+  }
 
-static std::string
-mk_tmp_hist_file (const octave_value_list& args,
-                  bool insert_curr, const char *warn_for)
-{
-  string_vector hlist = octave::command_history::list ();
+  static bool
+  get_int_arg (const octave_value& arg, int& val)
+  {
+    bool ok = true;
 
-  int hist_count = hlist.numel () - 1;  // switch to zero-based indexing
+    if (arg.is_string ())
+      {
+        std::string tmp = arg.string_value ();
 
-  // The current command line is already part of the history list by
-  // the time we get to this point.  Delete the cmd from the list when
-  // executing 'edit_history' so that it doesn't show up in the history
-  // but the actual commands performed will.
+        ok = sscanf (tmp.c_str (), "%d", &val) == 1;
+      }
+    else if (arg.isnumeric ())
+      val = arg.int_value ();
+    else
+      ok = false;
 
-  if (! insert_curr)
-    octave::command_history::remove (hist_count);
+    return ok;
+  }
+
+  static std::string
+  mk_tmp_hist_file (const octave_value_list& args,
+                    bool insert_curr, const char *warn_for)
+  {
+    string_vector hlist = octave::command_history::list ();
+
+    int hist_count = hlist.numel () - 1;  // switch to zero-based indexing
 
-  hist_count--;  // skip last entry in history list
+    // The current command line is already part of the history list by
+    // the time we get to this point.  Delete the cmd from the list when
+    // executing 'edit_history' so that it doesn't show up in the history
+    // but the actual commands performed will.
 
-  // If no numbers have been specified, the default is to edit the
-  // last command in the history list.
+    if (! insert_curr)
+      octave::command_history::remove (hist_count);
+
+    hist_count--;  // skip last entry in history list
 
-  int hist_beg = hist_count;
-  int hist_end = hist_count;
+    // If no numbers have been specified, the default is to edit the
+    // last command in the history list.
+
+    int hist_beg = hist_count;
+    int hist_end = hist_count;
 
-  bool reverse = false;
+    bool reverse = false;
+
+    // Process options.
+
+    int nargin = args.length ();
 
-  // Process options.
-
-  int nargin = args.length ();
+    if (nargin == 2)
+      {
+        if (! get_int_arg (args(0), hist_beg)
+            || ! get_int_arg (args(1), hist_end))
+          error ("%s: arguments must be integers", warn_for);
 
-  if (nargin == 2)
-    {
-      if (! get_int_arg (args(0), hist_beg)
-          || ! get_int_arg (args(1), hist_end))
-        error ("%s: arguments must be integers", warn_for);
+        if (hist_beg < 0)
+          hist_beg += (hist_count + 1);
+        else
+          hist_beg--;
+        if (hist_end < 0)
+          hist_end += (hist_count + 1);
+        else
+          hist_end--;
+      }
+    else if (nargin == 1)
+      {
+        if (! get_int_arg (args(0), hist_beg))
+          error ("%s: argument must be an integer", warn_for);
+
+        if (hist_beg < 0)
+          hist_beg += (hist_count + 1);
+        else
+          hist_beg--;
+
+        hist_end = hist_beg;
+      }
 
-      if (hist_beg < 0)
-        hist_beg += (hist_count + 1);
-      else
-        hist_beg--;
-      if (hist_end < 0)
-        hist_end += (hist_count + 1);
-      else
-        hist_end--;
-    }
-  else if (nargin == 1)
-    {
-      if (! get_int_arg (args(0), hist_beg))
-        error ("%s: argument must be an integer", warn_for);
+    if (hist_beg > hist_count || hist_end > hist_count)
+      error ("%s: history specification out of range", warn_for);
+
+    if (hist_end < hist_beg)
+      {
+        std::swap (hist_end, hist_beg);
+        reverse = true;
+      }
+
+    std::string name = octave::sys::tempnam ("", "oct-");
+
+    std::fstream file (name.c_str (), std::ios::out);
 
-      if (hist_beg < 0)
-        hist_beg += (hist_count + 1);
-      else
-        hist_beg--;
+    if (! file)
+      error ("%s: couldn't open temporary file '%s'", warn_for,
+             name.c_str ());
+
+    if (reverse)
+      {
+        for (int i = hist_end; i >= hist_beg; i--)
+          file << hlist[i] << "\n";
+      }
+    else
+      {
+        for (int i = hist_beg; i <= hist_end; i++)
+          file << hlist[i] << "\n";
+      }
+
+    file.close ();
+
+    return name;
+  }
 
-      hist_end = hist_beg;
-    }
+  static void
+  unlink_cleanup (const char *file)
+  {
+    octave_unlink_wrapper (file);
+  }
 
-  if (hist_beg > hist_count || hist_end > hist_count)
-    error ("%s: history specification out of range", warn_for);
+  history_system::history_system (interpreter& interp)
+    : m_interpreter (interp), m_input_from_tmp_file (false),
+      m_timestamp_format_string ()
+  { }
 
-  if (hist_end < hist_beg)
-    {
-      std::swap (hist_end, hist_beg);
-      reverse = true;
-    }
+  void history_system::initialize (bool read_history_file)
+  {
+    command_history::initialize (read_history_file, default_file (),
+                                 default_size (),
+                                 sys::env::getenv ("OCTAVE_HISTCONTROL"));
+
+    octave_link::set_history (command_history::list ());
+  }
 
-  std::string name = octave::sys::tempnam ("", "oct-");
+  void history_system::write_timestamp (void)
+  {
+    sys::localtime now;
+
+    std::string timestamp = now.strftime (m_timestamp_format_string);
+
+    if (! timestamp.empty ())
+      if (command_history::add (timestamp))
+        octave_link::append_history (timestamp);
+  }
 
-  std::fstream file (name.c_str (), std::ios::out);
-
-  if (! file)
-    error ("%s: couldn't open temporary file '%s'", warn_for,
-           name.c_str ());
+  octave_value
+  history_system::input_from_tmp_file (const octave_value_list& args,
+                                       int nargout)
+  {
+    return set_internal_variable (m_input_from_tmp_file, args, nargout,
+                                  "input_from_tmp_file");
+  }
 
-  if (reverse)
-    {
-      for (int i = hist_end; i >= hist_beg; i--)
-        file << hlist[i] << "\n";
-    }
-  else
-    {
-      for (int i = hist_beg; i <= hist_end; i++)
-        file << hlist[i] << "\n";
-    }
+  octave_value
+  history_system::timestamp_format_string (const octave_value_list& args,
+                                           int nargout)
+  {
+    return set_internal_variable (m_timestamp_format_string, args, nargout,
+                                  "timestamp_format_string", false);
+  }
+
+  // Display, save, or load history.  Stolen and modified from bash.
+  //
+  // Arg of -w FILENAME means write file, arg of -r FILENAME
+  // means read file, arg of -q means don't number lines.  Arg of N
+  // means only display that many items.
+
+  string_vector history_system::do_history (const octave_value_list& args,
+                                            int nargout)
+  {
+    bool numbered_output = nargout == 0;
+
+    unwind_protect frame;
+
+    string_vector hlist;
 
-  file.close ();
+    frame.add_fcn (command_history::set_file, command_history::file ());
+
+    int nargin = args.length ();
 
-  return name;
-}
+    // Number of history lines to show (-1 = all)
+    int limit = -1;
+
+    for (octave_idx_type i = 0; i < nargin; i++)
+      {
+        octave_value arg = args(i);
 
-static void
-unlink_cleanup (const char *file)
-{
-  octave_unlink_wrapper (file);
-}
+        std::string option;
+
+        if (arg.is_string ())
+          option = arg.string_value ();
+        else if (arg.isnumeric ())
+          {
+            limit = arg.int_value ();
+            if (limit < 0)
+              limit = -limit;
+            continue;
+          }
+        else
+          err_wrong_type_arg ("history", arg);
 
-static void
-do_edit_history (octave::interpreter& interp, const octave_value_list& args)
-{
-  std::string name = mk_tmp_hist_file (args, false, "edit_history");
+        if (option == "-r" || option == "-w" || option == "-a"
+            || option == "-n")
+          {
+            if (i < nargin - 1)
+              {
+                std::string fname
+                  = args(++i).xstring_value ("history: filename must be a string for %s option",
+                                             option.c_str ());
 
-  if (name.empty ())
-    return;
+                command_history::set_file (fname);
+              }
+            else
+              command_history::set_file (default_file ());
+
+            if (option == "-a")
+              // Append 'new' lines to file.
+              command_history::append ();
 
-  // Call up our favorite editor on the file of commands.
+            else if (option == "-w")
+              // Write entire history.
+              command_history::write ();
 
-  octave::environment& env = interp.get_environment ();
-  std::string cmd = env.editor ();
-  cmd.append (R"( ")" + name + '"');
+            else if (option == "-r")
+              {
+                // Read entire file.
+                command_history::read ();
+                octave_link::set_history (command_history::list ());
+              }
 
-  // Ignore interrupts while we are off editing commands.  Should we
-  // maybe avoid using system()?
+            else if (option == "-n")
+              {
+                // Read 'new' history from file.
+                command_history::read_range ();
+                octave_link::set_history (command_history::list ());
+              }
 
-  volatile octave::interrupt_handler old_interrupt_handler
-    = octave::ignore_interrupts ();
-
-  int status = system (cmd.c_str ());
-
-  octave::set_interrupt_handler (old_interrupt_handler);
+            else
+              panic_impossible ();
 
-  // Check if text edition was successfull.  Abort the operation
-  // in case of failure.
-  if (status != EXIT_SUCCESS)
-    error ("edit_history: text editor command failed");
-
-  // Write the commands to the history file since source_file
-  // disables command line history while it executes.
+            return hlist;
+          }
+        else if (option == "-c")
+          {
+            command_history::clear ();
+            octave_link::clear_history ();
+          }
+        else if (option == "-q")
+          numbered_output = false;
+        else if (option == "--")
+          {
+            i++;
+            break;
+          }
+        else
+          {
+            // The last argument found in the command list that looks like
+            // an integer will be used
+            int tmp;
 
-  std::fstream file (name.c_str (), std::ios::in);
+            if (sscanf (option.c_str (), "%d", &tmp) == 1)
+              {
+                if (tmp > 0)
+                  limit = tmp;
+                else
+                  limit = -tmp;
+              }
 
-  char *line;
-  //int first = 1;
-  while ((line = edit_history_readline (file)) != nullptr)
-    {
-      // Skip blank lines.
+            else
+              {
+                if (option.length () > 0 && option[0] == '-')
+                  error ("history: unrecognized option '%s'", option.c_str ());
+                else
+                  error ("history: bad non-numeric arg '%s'", option.c_str ());
+              }
+          }
+      }
 
-      if (line[0] == '\n')
-        {
-          delete [] line;
-          continue;
-        }
+    hlist = command_history::list (limit, numbered_output);
+
+    int len = hlist.numel ();
+
+    if (nargout == 0)
+      {
+        for (octave_idx_type i = 0; i < len; i++)
+          octave_stdout << hlist[i] << "\n";
+      }
 
-      edit_history_add_hist (line);
+    return hlist;
+  }
+
+  void history_system::do_edit_history (const octave_value_list& args)
+  {
+    std::string name = mk_tmp_hist_file (args, false, "edit_history");
+
+    if (name.empty ())
+      return;
 
-      delete [] line;
-    }
+    // Call up our favorite editor on the file of commands.
+
+    environment& env = m_interpreter.get_environment ();
+    std::string cmd = env.editor ();
+    cmd.append (R"( ")" + name + '"');
 
-  file.close ();
+    // Ignore interrupts while we are off editing commands.  Should we
+    // maybe avoid using system()?
+
+    volatile interrupt_handler old_interrupt_handler
+      = ignore_interrupts ();
 
-  octave::unwind_protect frame;
+    int status = system (cmd.c_str ());
+
+    set_interrupt_handler (old_interrupt_handler);
 
-  frame.add_fcn (unlink_cleanup, name.c_str ());
-  frame.protect_var (input_from_tmp_history_file);
+    // Check if text edition was successfull.  Abort the operation
+    // in case of failure.
+    if (status != EXIT_SUCCESS)
+      error ("edit_history: text editor command failed");
 
-  input_from_tmp_history_file = true;
+    // Write the commands to the history file since source_file
+    // disables command line history while it executes.
+
+    std::fstream file (name.c_str (), std::ios::in);
 
-  // FIXME: instead of sourcing a file, we should just iterate through
-  // the list of commands, parsing and executing them one at a time as
-  // if they were entered interactively.
+    char *line;
+    //int first = 1;
+    while ((line = edit_history_readline (file)) != nullptr)
+      {
+        // Skip blank lines.
 
-  octave::source_file (name);
-}
+        if (line[0] == '\n')
+          {
+            delete [] line;
+            continue;
+          }
+
+        edit_history_add_hist (line);
 
-static void
-do_run_history (const octave_value_list& args)
-{
-  std::string name = mk_tmp_hist_file (args, false, "run_history");
+        delete [] line;
+      }
+
+    file.close ();
+
+    unwind_protect frame;
 
-  if (name.empty ())
-    return;
+    frame.add_fcn (unlink_cleanup, name.c_str ());
+    frame.protect_var (m_input_from_tmp_file);
+
+    m_input_from_tmp_file = true;
 
-  octave::unwind_protect frame;
+    // FIXME: instead of sourcing a file, we should just iterate through
+    // the list of commands, parsing and executing them one at a time as
+    // if they were entered interactively.
+
+    source_file (name);
+  }
 
-  frame.add_fcn (unlink_cleanup, name.c_str ());
-  frame.protect_var (input_from_tmp_history_file);
+  void history_system::do_run_history (const octave_value_list& args)
+  {
+    std::string name = mk_tmp_hist_file (args, false, "run_history");
+
+    if (name.empty ())
+      return;
 
-  input_from_tmp_history_file = true;
+    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;
 
-  // FIXME: instead of sourcing a file, we should just iterate through
-  // the list of commands, parsing and executing them one at a time as
-  // if they were entered interactively.
+    // FIXME: instead of sourcing a file, we should just iterate through
+    // the list of commands, parsing and executing them one at a time as
+    // if they were entered interactively.
+
+    source_file (name);
+  }
 
-  octave::source_file (name);
-}
+  std::string history_system::default_file (void)
+  {
+    std::string file;
+
+    std::string env_file = sys::env::getenv ("OCTAVE_HISTFILE");
+
+    if (! env_file.empty ())
+      file = env_file;
 
-void
-initialize_history (bool read_history_file)
-{
-  octave::command_history::initialize (read_history_file,
-                                       default_history_file (),
-                                       default_history_size (),
-                                       octave::sys::env::getenv ("OCTAVE_HISTCONTROL"));
+    if (file.empty ())
+      file = sys::file_ops::concat (sys::env::get_home_directory (),
+                                            ".octave_hist");
+
+    return file;
+  }
 
-  octave_link::set_history (octave::command_history::list ());
-}
+  int history_system::default_size (void)
+  {
+    int size = 1000;
+
+    std::string env_size = sys::env::getenv ("OCTAVE_HISTSIZE");
+
+    if (! env_size.empty ())
+      {
+        int val;
 
-void
-octave_history_write_timestamp (void)
-{
-  octave::sys::localtime now;
+        if (sscanf (env_size.c_str (), "%d", &val) == 1)
+          size = (val > 0 ? val : 0);
+      }
+
+    return size;
+  }
 
-  std::string timestamp = now.strftime (Vhistory_timestamp_format_string);
-
-  if (! timestamp.empty ())
-    if (octave::command_history::add (timestamp))
-      octave_link::append_history (timestamp);
+  std::string history_system::default_timestamp_format (void)
+  {
+    return
+      "# Octave " OCTAVE_VERSION ", %a %b %d %H:%M:%S %Y %Z <"
+      + sys::env::get_user_name ()
+      + '@'
+      + sys::env::get_host_name ()
+      + '>';
+  }
 }
 
 DEFMETHOD (edit_history, interp, args, ,
@@ -591,13 +597,15 @@
   if (args.length () > 2)
     print_usage ();
 
-  do_edit_history (interp, args);
+  octave::history_system& history_sys = interp.get_history_system ();
+
+  history_sys.do_edit_history (args);
 
   return ovl ();
 }
 
-DEFUN (history, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (history, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} history
 @deftypefnx {} {} history @var{opt1} @dots{}
 @deftypefnx {} {@var{h} =} history ()
@@ -640,15 +648,17 @@
 {
   // FIXME: should this be limited to the top-level context?
 
+  octave::history_system& history_sys = interp.get_history_system ();
+
   // Call do_history even if nargout is zero to display history list.
 
-  string_vector hlist = do_history (args, nargout);
+  string_vector hlist = history_sys.do_history (args, nargout);
 
   return nargout > 0 ? ovl (Cell (hlist)) : ovl ();
 }
 
-DEFUN (run_history, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (run_history, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} run_history
 @deftypefnx {} {} run_history @var{cmd_number}
 @deftypefnx {} {} run_history @var{first} @var{last}
@@ -701,10 +711,12 @@
 {
   // FIXME: should this be limited to the top-level context?
 
+  octave::history_system& history_sys = interp.get_history_system ();
+
   if (args.length () > 2)
     print_usage ();
 
-  do_run_history (args);
+  history_sys.do_run_history (args);
 
   return ovl ();
 }
@@ -801,8 +813,8 @@
   return retval;
 }
 
-DEFUN (history_timestamp_format_string, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (history_timestamp_format_string, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} history_timestamp_format_string ()
 @deftypefnx {} {@var{old_val} =} history_timestamp_format_string (@var{new_val})
 @deftypefnx {} {} history_timestamp_format_string (@var{new_val}, "local")
@@ -822,7 +834,9 @@
 @seealso{strftime, history_file, history_size, history_save}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (history_timestamp_format_string);
+  octave::history_system& history_sys = interp.get_history_system ();
+
+  return history_sys.timestamp_format_string (args, nargout);
 }
 
 DEFUN (history_save, args, nargout,
--- a/libinterp/corefcn/oct-hist.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-hist.h	Thu Dec 20 17:18:56 2018 -0500
@@ -29,12 +29,83 @@
 
 #include "cmd-hist.h"
 
-extern void initialize_history (bool read_history_file = false);
+namespace octave
+{
+  class history_system
+  {
+  public:
+
+    history_system (interpreter& interp);
+
+    history_system (const history_system&) = delete;
+
+    history_system& operator = (const history_system&) = delete;
+
+    ~history_system (void) = default;
+
+    void initialize (bool read_history_file = false);
+
+    void write_timestamp (void);
+
+    octave_value input_from_tmp_file (const octave_value_list& args,
+                                      int nargout);
+
+    bool input_from_tmp_file (void) const
+    {
+      return m_input_from_tmp_file;
+    }
+
+    bool input_from_tmp_file (bool flag)
+    {
+      return set (m_input_from_tmp_file, flag);
+    }
+
+    octave_value timestamp_format_string (const octave_value_list& args,
+                                          int nargout);
+
+    std::string timestamp_format_string (void) const
+    {
+      return m_timestamp_format_string;
+    }
 
-// Write timestamp to history file.
-extern void octave_history_write_timestamp (void);
+    std::string timestamp_format_string (const std::string& file)
+    {
+      return set (m_timestamp_format_string, file);
+    }
+
+    string_vector
+    do_history (const octave_value_list& args = octave_value_list (),
+                int nargout = 0);
+
+    void do_edit_history (const octave_value_list& args = octave_value_list ());
+
+    void do_run_history (const octave_value_list& args = octave_value_list ());
+
+  private:
+
+    interpreter& m_interpreter;
+
+    // TRUE means input is coming from temporary history file.
+    bool m_input_from_tmp_file;
 
-// TRUE means input is coming from temporary history file.
-extern bool input_from_tmp_history_file;
+    // The format of the timestamp marker written to the history file when
+    // Octave exits.
+    std::string m_timestamp_format_string;
+
+    static std::string default_file (void);
+
+    static int default_size (void);
+
+    static std::string default_timestamp_format (void);
+
+    template <typename T>
+    T set (T& var, const T& new_val)
+    {
+      T old_val = var;
+      var = new_val;
+      return old_val;
+    }
+  };
+}
 
 #endif
--- a/libinterp/corefcn/oct-iostrm.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-iostrm.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "error.h"
 #include "oct-iostrm.h"
--- a/libinterp/corefcn/oct-map.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-map.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -65,14 +65,14 @@
 octave_idx_type
 octave_fields::getfield (const std::string& field) const
 {
-  fields_rep::iterator p = rep->find (field);
+  auto p = rep->find (field);
   return (p != rep->end ()) ? p->second : -1;
 }
 
 octave_idx_type
 octave_fields::getfield (const std::string& field)
 {
-  fields_rep::iterator p = rep->find (field);
+  auto p = rep->find (field);
   if (p != rep->end ())
     return p->second;
   else
@@ -86,7 +86,7 @@
 octave_idx_type
 octave_fields::rmfield (const std::string& field)
 {
-  fields_rep::iterator p = rep->find (field);
+  auto p = rep->find (field);
   if (p == rep->end ())
     return -1;
   else
@@ -126,8 +126,8 @@
 {
   bool retval = true;
 
-  iterator p = begin ();
-  iterator q = other.begin ();
+  auto p = begin ();
+  auto q = other.begin ();
   for (; p != end () && q != other.end (); p++, q++)
     {
       if (p->first == q->first)
@@ -1193,7 +1193,7 @@
                     const Cell& rhs)
 {
   Cell tmp;
-  iterator p = seek (k);
+  auto p = seek (k);
   Cell& ref = (p != end () ? contents (p) : tmp);
 
   if (&ref == &tmp)
@@ -1322,11 +1322,11 @@
 {
   if (nfields () == rb.nfields ())
     {
-      for (const_iterator pa = begin (); pa != end (); pa++)
+      for (auto pa = cbegin (); pa != cend (); pa++)
         {
-          const_iterator pb = rb.seek (key (pa));
+          auto pb = rb.seek (key (pa));
 
-          if (pb == rb.end ())
+          if (pb == rb.cend ())
             error ("field name mismatch in structure concatenation");
 
           contents(pa).insert (rb.contents (pb), ra_idx);
--- a/libinterp/corefcn/oct-map.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-map.h	Thu Dec 20 17:18:56 2018 -0500
@@ -103,6 +103,9 @@
   const_iterator begin (void) const { return rep->begin (); }
   const_iterator end (void) const { return rep->end (); }
 
+  const_iterator cbegin (void) const { return rep->cbegin (); }
+  const_iterator cend (void) const { return rep->cend (); }
+
   std::string key (const_iterator p) const { return p->first; }
   octave_idx_type index (const_iterator p) const { return p->second; }
 
@@ -184,6 +187,9 @@
   const_iterator begin (void) const { return xkeys.begin (); }
   const_iterator end (void) const { return xkeys.end (); }
 
+  const_iterator cbegin (void) const { return xkeys.cbegin (); }
+  const_iterator cend (void) const { return xkeys.cend (); }
+
   const_iterator seek (const std::string& k) const { return xkeys.seek (k); }
 
   std::string key (const_iterator p) const
@@ -307,6 +313,9 @@
   const_iterator begin (void) const { return xkeys.begin (); }
   const_iterator end (void) const { return xkeys.end (); }
 
+  const_iterator cbegin (void) const { return xkeys.cbegin (); }
+  const_iterator cend (void) const { return xkeys.cend (); }
+
   const_iterator seek (const std::string& k) const { return xkeys.seek (k); }
 
   std::string key (const_iterator p) const
--- a/libinterp/corefcn/oct-opengl.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-opengl.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,22 +25,437 @@
 
 #include "octave-config.h"
 
-#if defined (HAVE_GL_GL_H)
-#  include <GL/gl.h>
-#elif defined (HAVE_OPENGL_GL_H) || defined (HAVE_FRAMEWORK_OPENGL)
-#  include <OpenGL/gl.h>
+#if defined (HAVE_OPENGL)
+
+#  if defined (HAVE_GL_GL_H)
+#    include <GL/gl.h>
+#  elif defined (HAVE_OPENGL_GL_H) || defined (HAVE_FRAMEWORK_OPENGL)
+#    include <OpenGL/gl.h>
+#  endif
+
+#  if defined (HAVE_GL_GLU_H)
+#    include <GL/glu.h>
+#  elif defined (HAVE_OPENGL_GLU_H) || defined (HAVE_FRAMEWORK_OPENGL)
+#    include <OpenGL/glu.h>
+#  endif
+
+#  if defined (HAVE_GL_GLEXT_H)
+#    include <GL/glext.h>
+#  elif defined (HAVE_OPENGL_GLEXT_H) || defined (HAVE_FRAMEWORK_OPENGL)
+#    include <OpenGL/glext.h>
+#  endif
+
 #endif
 
-#if defined (HAVE_GL_GLU_H)
-#  include <GL/glu.h>
-#elif defined (HAVE_OPENGL_GLU_H) || defined (HAVE_FRAMEWORK_OPENGL)
-#  include <OpenGL/glu.h>
-#endif
+namespace octave
+{
+  class opengl_functions
+  {
+  public:
+
+    opengl_functions (void) { }
+
+    opengl_functions (const opengl_functions&) = default;
+
+    opengl_functions& operator = (const opengl_functions&) = default;
+
+    virtual ~opengl_functions (void) = default;
+
+#if defined (HAVE_OPENGL)
+
+    // If OpenGL is not available, opengl_functions will be a dummy
+    // class that does nothing.  This makes the implementation of
+    // other things that rely on this class slightly simpler.
+
+    virtual void glAlphaFunc (GLenum func, GLclampf ref)
+    {
+      ::glAlphaFunc (func, ref);
+    }
+
+    virtual void glBegin (GLenum mode)
+    {
+      ::glBegin (mode);
+    }
+
+    virtual void glBindTexture (GLenum target, GLuint texture)
+    {
+      ::glBindTexture (target, texture);
+    }
+
+    virtual void glBitmap (GLsizei width, GLsizei height, GLfloat xorig,
+                           GLfloat yorig, GLfloat xmove, GLfloat ymove,
+                           const GLubyte *bitmap)
+    {
+      ::glBitmap (width, height, xorig, yorig, xmove, ymove, bitmap);
+    }
+
+    virtual void glBlendFunc (GLenum sfactor, GLenum dfactor)
+    {
+      ::glBlendFunc (sfactor, dfactor);
+    }
+
+    virtual void glCallList (GLuint list)
+    {
+      ::glCallList (list);
+    }
+
+    virtual void glClearColor (GLclampf red, GLclampf green, GLclampf blue,
+                               GLclampf alpha)
+    {
+      ::glClearColor (red, green, blue, alpha);
+    }
+
+    virtual void glClear (GLbitfield mask)
+    {
+      ::glClear (mask);
+    }
+
+    virtual void glClipPlane (GLenum plane, const GLdouble *equation)
+    {
+      ::glClipPlane (plane, equation);
+    }
+
+    virtual void glColor3dv (const GLdouble *v)
+    {
+      ::glColor3dv (v);
+    }
+
+    virtual void glColor3f (GLfloat red, GLfloat green, GLfloat blue)
+    {
+      ::glColor3f (red, green, blue);
+    }
+
+    virtual void glColor3fv (const GLfloat *v)
+    {
+      ::glColor3fv (v);
+    }
+
+    virtual void glColor4d (GLdouble red, GLdouble green, GLdouble blue,
+                            GLdouble alpha)
+    {
+      ::glColor4d (red, green, blue, alpha);
+    }
+
+    virtual void glColor4f (GLfloat red, GLfloat green, GLfloat blue,
+                            GLfloat alpha)
+    {
+      ::glColor4f (red, green, blue, alpha);
+    }
+
+    virtual void glColor4fv (const GLfloat *v)
+    {
+      ::glColor4fv (v);
+    }
+
+    virtual void glDeleteLists (GLuint list, GLsizei range)
+    {
+      ::glDeleteLists (list, range);
+    }
+
+    virtual void glDeleteTextures (GLsizei n, const GLuint *textures)
+    {
+      ::glDeleteTextures (n, textures);
+    }
+
+    virtual void glDepthFunc (GLenum func)
+    {
+      ::glDepthFunc (func);
+    }
+
+    virtual void glDisable (GLenum cap)
+    {
+      ::glDisable (cap);
+    }
+
+    virtual void glDrawPixels (GLsizei width, GLsizei height, GLenum format,
+                               GLenum type, const GLvoid *pixels)
+    {
+      ::glDrawPixels (width, height, format, type, pixels);
+    }
+
+    virtual void glEdgeFlag (GLboolean flag)
+    {
+      ::glEdgeFlag (flag);
+    }
+
+    virtual void glEnable (GLenum cap)
+    {
+      ::glEnable (cap);
+    }
+
+    virtual void glEndList (void)
+    {
+      ::glEndList ();
+    }
+
+    virtual void glEnd (void)
+    {
+      ::glEnd ();
+    }
+
+    virtual void glFinish (void)
+    {
+      ::glFinish ();
+    }
+
+    virtual GLuint glGenLists (GLsizei range)
+    {
+      return ::glGenLists (range);
+    }
+
+    virtual void glGenTextures (GLsizei n, GLuint *textures)
+    {
+      ::glGenTextures (n, textures);
+    }
+
+    virtual void glGetBooleanv (GLenum pname, GLboolean *data)
+    {
+      ::glGetBooleanv (pname, data);
+    }
+
+    virtual void glGetDoublev (GLenum pname, GLdouble *data)
+    {
+      ::glGetDoublev (pname, data);
+    }
+
+    virtual GLenum glGetError (void)
+    {
+      return ::glGetError ();
+    }
+
+    virtual void glGetFloatv (GLenum pname, GLfloat *data)
+    {
+      ::glGetFloatv (pname, data);
+    }
+
+    virtual void glGetIntegerv (GLenum pname, GLint *data)
+    {
+      ::glGetIntegerv (pname, data);
+    }
+
+    virtual const GLubyte * glGetString (GLenum name)
+    {
+      return ::glGetString (name);
+    }
+
+    virtual void glHint (GLenum target, GLenum mode)
+    {
+      ::glHint (target, mode);
+    }
+
+    virtual void glInitNames (void)
+    {
+      ::glInitNames ();
+    }
 
-#if defined (HAVE_GL_GLEXT_H)
-#  include <GL/glext.h>
-#elif defined (HAVE_OPENGL_GLEXT_H) || defined (HAVE_FRAMEWORK_OPENGL)
-#  include <OpenGL/glext.h>
-#endif
+    virtual GLboolean glIsEnabled (GLenum cap)
+    {
+      return ::glIsEnabled (cap);
+    }
+
+    virtual void glLightfv (GLenum light, GLenum pname, const GLfloat *params)
+    {
+      ::glLightfv (light, pname, params);
+    }
+
+    virtual void glLineStipple (GLint factor, GLushort pattern)
+    {
+      ::glLineStipple (factor, pattern);
+    }
+
+    virtual void glLineWidth (GLfloat width)
+    {
+      ::glLineWidth (width);
+    }
+
+    virtual void glLoadIdentity (void)
+    {
+      ::glLoadIdentity ();
+    }
+
+    virtual void glMaterialf (GLenum face, GLenum pname, GLfloat param)
+    {
+      ::glMaterialf (face, pname, param);
+    }
+
+    virtual void glMaterialfv (GLenum face, GLenum pname, const GLfloat *params)
+    {
+      ::glMaterialfv (face, pname, params);
+    }
+
+    virtual void glMatrixMode (GLenum mode)
+    {
+      ::glMatrixMode (mode);
+    }
+
+    virtual void glMultMatrixd (const GLdouble *m)
+    {
+      ::glMultMatrixd (m);
+    }
+
+    virtual void glNewList (GLuint list, GLenum mode)
+    {
+      ::glNewList (list, mode);
+    }
+
+    virtual void glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz)
+    {
+      ::glNormal3d (nx, ny, nz);
+    }
+
+    virtual void glNormal3dv (const GLdouble *v)
+    {
+      ::glNormal3dv (v);
+    }
+
+    virtual void glOrtho (GLdouble left, GLdouble right, GLdouble bottom,
+                          GLdouble top, GLdouble near_val, GLdouble far_val)
+    {
+      ::glOrtho (left, right, bottom, top, near_val, far_val);
+    }
+
+    virtual void glPixelStorei (GLenum pname, GLint param)
+    {
+      ::glPixelStorei (pname, param);
+    }
+
+    virtual void glPixelZoom (GLfloat xfactor, GLfloat yfactor)
+    {
+      ::glPixelZoom (xfactor, yfactor);
+    }
+
+    virtual void glPolygonMode (GLenum face, GLenum mode)
+    {
+      ::glPolygonMode (face, mode);
+    }
+
+    virtual void glPolygonOffset (GLfloat factor, GLfloat units)
+    {
+      ::glPolygonOffset (factor, units);
+    }
+
+    virtual void glPopAttrib (void)
+    {
+      ::glPopAttrib ();
+    }
+
+    virtual void glPopMatrix (void)
+    {
+      ::glPopMatrix ();
+    }
+
+    virtual void glPopName (void)
+    {
+      ::glPopName ();
+    }
+
+    virtual void glPushAttrib (GLbitfield mask)
+    {
+      ::glPushAttrib (mask);
+    }
+
+    virtual void glPushMatrix (void)
+    {
+      ::glPushMatrix ();
+    }
+
+    virtual void glPushName (GLuint name)
+    {
+      ::glPushName (name);
+    }
+
+    virtual void glRasterPos3d (GLdouble x, GLdouble y, GLdouble z)
+    {
+      ::glRasterPos3d (x, y, z);
+    }
+
+    virtual void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height,
+                               GLenum format, GLenum type, GLvoid *pixels)
+    {
+      ::glReadPixels (x, y, width, height, format, type, pixels);
+    }
+
+    virtual GLint glRenderMode (GLenum mode)
+    {
+      return ::glRenderMode (mode);
+    }
+
+    virtual void glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+    {
+      ::glRotated (angle, x, y, z);
+    }
+
+    virtual void glScaled (GLdouble x, GLdouble y, GLdouble z)
+    {
+      ::glScaled (x, y, z);
+    }
+
+    virtual void glScalef (GLfloat x, GLfloat y, GLfloat z)
+    {
+      ::glScalef (x, y, z);
+    }
+
+    virtual void glSelectBuffer (GLsizei size, GLuint *buffer)
+    {
+      ::glSelectBuffer (size, buffer);
+    }
+
+    virtual void glShadeModel (GLenum mode)
+    {
+      ::glShadeModel (mode);
+    }
+
+    virtual void glTexCoord2d (GLdouble s, GLdouble t)
+    {
+      ::glTexCoord2d (s, t);
+    }
+
+    virtual void glTexImage2D (GLenum target, GLint level, GLint internalFormat,
+                               GLsizei width, GLsizei height, GLint border,
+                               GLenum format, GLenum type, const GLvoid *pixels)
+    {
+      ::glTexImage2D (target, level, internalFormat, width, height, border,
+                      format, type, pixels);
+    }
+
+    virtual void glTexParameteri (GLenum target, GLenum pname, GLint param)
+    {
+      ::glTexParameteri (target, pname, param);
+    }
+
+    virtual void glTranslated (GLdouble x, GLdouble y, GLdouble z)
+    {
+      ::glTranslated (x, y, z);
+    }
+
+    virtual void glTranslatef (GLfloat x, GLfloat y, GLfloat z)
+    {
+      ::glTranslatef (x, y, z);
+    }
+
+    virtual void glVertex2d (GLdouble x, GLdouble y)
+    {
+      ::glVertex2d (x, y);
+    }
+
+    virtual void glVertex3d (GLdouble x, GLdouble y, GLdouble z)
+    {
+      ::glVertex3d (x, y, z);
+    }
+
+    virtual void glVertex3dv (const GLdouble *v)
+    {
+      ::glVertex3dv (v);
+    }
+
+    virtual void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
+    {
+      ::glViewport (x, y, width, height);
+    }
 
 #endif
+  };
+}
+
+
+#endif
--- a/libinterp/corefcn/oct-prcstrm.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-prcstrm.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -39,8 +39,8 @@
 octave_iprocstream::octave_iprocstream (const std::string& n,
                                         std::ios::openmode arg_md,
                                         octave::mach_info::float_format ff)
-  : octave_stdiostream (n, octave_popen (n.c_str (), "r"),
-                        arg_md, ff, octave_pclose)
+  : octave_stdiostream (n, octave::popen (n.c_str (), "r"),
+                        arg_md, ff, octave::pclose)
 { }
 
 octave_iprocstream::~octave_iprocstream (void)
@@ -58,8 +58,8 @@
 octave_oprocstream::octave_oprocstream (const std::string& n,
                                         std::ios::openmode arg_md,
                                         octave::mach_info::float_format ff)
-  : octave_stdiostream (n, octave_popen (n.c_str (), "w"),
-                        arg_md, ff, octave_pclose)
+  : octave_stdiostream (n, octave::popen (n.c_str (), "w"),
+                        arg_md, ff, octave::pclose)
 { }
 
 octave_oprocstream::~octave_oprocstream (void)
--- a/libinterp/corefcn/oct-procbuf.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-procbuf.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
 
 #include <cerrno>
 
-#include <iostream>
+#include <iomanip>
 
 // FIXME: we would prefer to avoid including these directly in Octave
 // sources, but eliminating them is complicated by the mingling of
@@ -78,7 +78,7 @@
   if (is_open ())
     return 0;
 
-  f = (octave_popen (command, (mode & std::ios::in) ? "r" : "w"));
+  f = (octave::popen (command, (mode & std::ios::in) ? "r" : "w"));
 
   if (! f)
     return 0;
@@ -183,7 +183,7 @@
 
   if (f)
     {
-      wstatus = octave_pclose (f);
+      wstatus = octave::pclose (f);
       f = 0;
     }
 
--- a/libinterp/corefcn/oct-stdstrm.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-stdstrm.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,6 +25,8 @@
 
 #include "octave-config.h"
 
+#include <iomanip>
+
 #include "oct-stream.h"
 #include "c-file-ptr-stream.h"
 
--- a/libinterp/corefcn/oct-stream.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-stream.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -91,9 +91,9 @@
       {
         dval = tc.double_value ();
       }
-    catch (const octave::execution_exception&)
-      {
-        octave::interpreter::recover_from_exception ();
+    catch (const execution_exception&)
+      {
+        interpreter::recover_from_exception ();
 
         conv_err = 1;
       }
@@ -102,7 +102,7 @@
       {
         if (! lo_ieee_isnan (dval))
           {
-            int ival = octave::math::nint (dval);
+            int ival = math::nint (dval);
 
             if (ival == dval)
               retval = ival;
@@ -122,9 +122,9 @@
     octave_idx_type retval = -1;
 
     if (lo_ieee_isnan (d))
-      ::error ("%s: NaN is invalid as size specification", who.c_str ());
-
-    if (octave::math::isinf (d))
+      ::error ("%s: NaN invalid as size specification", who.c_str ());
+
+    if (math::isinf (d))
       retval = -1;
     else
       {
@@ -136,7 +136,7 @@
           ::error ("%s: dimension too large for Octave's index type",
                    who.c_str ());
 
-        retval = octave::math::nint_big (d);
+        retval = math::nint_big (d);
       }
 
     return retval;
@@ -169,18 +169,26 @@
       {
         dnr = size(0);
 
-        if (octave::math::isinf (dnr))
-          ::error ("%s: invalid size specification", who.c_str ());
+        if (math::isinf (dnr))
+          ::error ("%s: infinite value invalid as size specification",
+                   who.c_str ());
 
         dnc = size(1);
       }
     else
-      ::error ("%s: invalid size specification", who.c_str ());
+      ::error ("%s: invalid size specification (must be 2-D)", who.c_str ());
 
     nr = get_size (dnr, who);
 
     if (dnc >= 0.0)
-      nc = get_size (dnc, who);
+      {
+        nc = get_size (dnc, who);
+
+        // Check for overflow.
+        if (nr > 0 && nc > 0
+            && nc > std::numeric_limits<octave_idx_type>::max () / nr)
+          ::error ("%s: size too large for Octave's index type", who.c_str ());
+      }
   }
 
   static std::string
@@ -2649,8 +2657,8 @@
       }
 
     if ((err & 4) && ! return_on_error)
-      error ("%s: Read error in field %d of row %d", who.c_str (),
-             done_after + 1, row + 1);
+      error ("%s: Read error in field %d of row %" OCTAVE_IDX_TYPE_FORMAT,
+             who.c_str (), done_after + 1, row + 1);
 
     // If file does not end in EOL, do not pad columns with NaN.
     bool uneven_columns = false;
@@ -3391,7 +3399,7 @@
                               Array<octave_idx_type> row, int& done_after)
   {
     const textscan_format_elt *elem = fmt_list.first ();
-    std::list<octave_value>::iterator out = retval.begin ();
+    auto out = retval.begin ();
     bool no_conversions = true;
     bool done = false;
     bool conversion_failed = false;       // Record for ReturnOnError
@@ -4574,7 +4582,7 @@
                          octave_idx_type& conversion_count,
                          const std::string& who)
   {
-    if (octave::application::interactive () && file_number () == 0)
+    if (application::interactive () && file_number () == 0)
       ::error ("%s: unable to read from stdin while running interactively",
                who.c_str ());
 
@@ -4902,8 +4910,8 @@
                       is.clear (is.rdstate () & (~std::ios::failbit));
 
                     // FIXME: is this the right thing to do?
-                    if (octave::application::interactive ()
-                        && ! octave::application::forced_interactive ()
+                    if (application::interactive ()
+                        && ! application::forced_interactive ()
                         && name () == "stdin")
                       {
                         is.clear ();
@@ -5198,8 +5206,8 @@
 
         // FIXME: is this the right thing to do?
 
-        if (octave::application::interactive ()
-            && ! octave::application::forced_interactive ()
+        if (application::interactive ()
+            && ! application::forced_interactive ()
             && name () == "stdin")
           {
             // Skip to end of line.
@@ -5292,7 +5300,7 @@
                             const std::string& who,
                             octave_idx_type& read_count)
   {
-    if (octave::application::interactive () && file_number () == 0)
+    if (application::interactive () && file_number () == 0)
       ::error ("%s: unable to read from stdin while running interactively",
                who.c_str ());
 
@@ -5304,7 +5312,7 @@
       invalid_operation (who, "reading");
     else
       {
-        octave::textscan scanner (who);
+        textscan scanner (who);
 
         retval = scanner.scan (*isp, fmt, ntimes, options, read_count);
       }
@@ -5437,7 +5445,7 @@
                       {
                         double dval = val(idx);
 
-                        if (octave::math::x_nint (dval) != dval || dval < 0 || dval > 255)
+                        if (math::x_nint (dval) != dval || dval < 0 || dval > 255)
                           break;
                       }
 
@@ -5464,7 +5472,7 @@
                   {
                     double dval = retval.double_value ();
 
-                    if (octave::math::x_nint (dval) == dval && dval >= 0 && dval < 256)
+                    if (math::x_nint (dval) == dval && dval >= 0 && dval < 256)
                       retval = static_cast<char> (dval);
                   }
               }
@@ -5513,8 +5521,8 @@
 
     double dval = val.double_value (true);
 
-    if (octave::math::x_nint (dval) == dval)
-      retval = octave::math::nint (dval);
+    if (math::x_nint (dval) == dval)
+      retval = math::nint (dval);
     else
       curr_state = conversion_error;
 
@@ -5533,15 +5541,15 @@
     switch (nsa)
       {
       case 2:
-        retval = octave_format (os, fmt, sa_1, sa_2, arg);
+        retval = octave::format (os, fmt, sa_1, sa_2, arg);
         break;
 
       case 1:
-        retval = octave_format (os, fmt, sa_1, arg);
+        retval = octave::format (os, fmt, sa_1, arg);
         break;
 
       case 0:
-        retval = octave_format (os, fmt, arg);
+        retval = octave::format (os, fmt, arg);
         break;
 
       default:
@@ -5553,7 +5561,7 @@
   }
 
   static size_t
-  do_printf_string (std::ostream& os, const octave::printf_format_elt *elt,
+  do_printf_string (std::ostream& os, const printf_format_elt *elt,
                     int nsa, int sa_1, int sa_2, const std::string& arg,
                     const std::string& who)
   {
@@ -5608,7 +5616,7 @@
       {
         double dval = val.double_value (true);
 
-        if (dval == octave::math::round (dval) && dval <= limit)
+        if (dval == math::round (dval) && dval <= limit)
           return true;
       }
 
@@ -5635,7 +5643,7 @@
 
         uint64_t limit = std::numeric_limits<uint64_t>::max ();
 
-        if (dval == octave::math::round (dval) && dval >= 0 && dval <= limit)
+        if (dval == math::round (dval) && dval >= 0 && dval <= limit)
           return true;
       }
 
@@ -5643,7 +5651,7 @@
   }
 
   static std::string
-  switch_to_g_format (const octave::printf_format_elt *elt)
+  switch_to_g_format (const printf_format_elt *elt)
   {
     std::string tfmt = elt->text;
 
@@ -6303,7 +6311,7 @@
                     octave_idx_type elts_read,
                     octave_idx_type nr, octave_idx_type nc, bool swap,
                     bool do_float_fmt_conv, bool do_NA_conv,
-                    octave::mach_info::float_format from_flt_fmt)
+                    mach_info::float_format from_flt_fmt)
   {
     typedef typename DST_T::element_type dst_elt_type;
 
@@ -6313,8 +6321,7 @@
 
     octave_idx_type j = 0;
 
-    for (std::list<void *>::const_iterator it = input_buf_list.begin ();
-         it != input_buf_list.end (); it++)
+    for (auto it = input_buf_list.cbegin (); it != input_buf_list.cend (); it++)
       {
         SRC_T *data = static_cast<SRC_T *> (*it);
 
@@ -6330,7 +6337,7 @@
                     else if (do_float_fmt_conv)
                       do_float_format_conversion (&data[i], sizeof (SRC_T),
                                                   1, from_flt_fmt,
-                                                  octave::mach_info::native_float_format ());
+                                                  mach_info::native_float_format ());
 
                     dst_elt_type tmp (data[i]);
 
@@ -6350,7 +6357,7 @@
                     else if (do_float_fmt_conv)
                       do_float_format_conversion (&data[i], sizeof (SRC_T),
                                                   1, from_flt_fmt,
-                                                  octave::mach_info::native_float_format ());
+                                                  mach_info::native_float_format ());
 
                     conv_data[j] = data[i];
                   }
@@ -6394,7 +6401,7 @@
     (std::list<void *>& input_buf_list, octave_idx_type input_buf_elts,
      octave_idx_type elts_read, octave_idx_type nr, octave_idx_type nc,
      bool swap, bool do_float_fmt_conv, bool do_NA_conv,
-     octave::mach_info::float_format from_flt_fmt);
+     mach_info::float_format from_flt_fmt);
 
 #define TABLE_ELT(T, U, V, W)                                           \
   conv_fptr_table[oct_data_conv::T][oct_data_conv::U] = convert_and_copy<V, W>
@@ -6512,19 +6519,19 @@
   {
     octave_value retval;
 
+    if (! stream_ok ())
+      return retval;
+
     octave_idx_type nr = -1;
     octave_idx_type nc = -1;
 
     bool one_elt_size_spec = false;
 
-    if (! stream_ok ())
-      return retval;
-
-    // FIXME: we may eventually want to make this extensible.
-
-    // FIXME: we need a better way to ensure that this
-    // numbering stays consistent with the order of the elements in the
-    // data_type enum in the oct_data_conv class.
+    // FIXME: We may eventually want to make this extensible.
+
+    // FIXME: We need a better way to ensure that this numbering stays
+    // consistent with the order of the elements in the data_type enum in the
+    // oct_data_conv class.
 
     // Expose this in a future version?
     size_t char_count = 0;
@@ -6569,9 +6576,6 @@
           nr = nc = 0;
       }
 
-    // FIXME: Ensure that this does not overflow.
-    //        Maybe try comparing nr * nc computed in double with
-    //        std::numeric_limits<octave_idx_type>::max ();
     octave_idx_type elts_to_read = nr * nc;
 
     bool read_to_eof = elts_to_read < 0;
@@ -6596,8 +6600,7 @@
 
     assert (input_buf_size >= 0);
 
-    // Must also work and return correct type object
-    // for 0 elements to read.
+    // Must also work and return correct type object for 0 elements to read.
     std::istream *isp = input_stream ();
 
     if (! isp)
@@ -6606,7 +6609,18 @@
       {
         std::istream& is = *isp;
 
-        std::list <void *> input_buf_list;
+        // Initialize eof_pos variable just once per function call
+        off_t eof_pos = 0;
+        off_t cur_pos = 0;
+        if (skip != 0 && is && ! is.eof ())
+          {
+            cur_pos = is.tellg ();
+            is.seekg (0, is.end);
+            eof_pos = is.tellg ();
+            is.seekg (cur_pos, is.beg);
+          }
+
+        std::list<void *> input_buf_list;
 
         while (is && ! is.eof ()
                && (read_to_eof || tmp_count < elts_to_read))
@@ -6626,6 +6640,7 @@
             size_t gcount = is.gcount ();
 
             char_count += gcount;
+            cur_pos += gcount;
 
             octave_idx_type nel = gcount / input_elt_size;
 
@@ -6633,30 +6648,22 @@
 
             input_buf_list.push_back (input_buf);
 
-            if (is && skip != 0 && nel == block_size)
+            if (skip != 0 && nel == block_size && is)
               {
-                // Seek to skip.
+                // Attempt to skip.
                 // If skip would move past EOF, position at EOF.
-
-                off_t orig_pos = tell ();
-
-                seek (0, SEEK_END);
-
-                off_t eof_pos = tell ();
-
-                // Is it possible for this to fail to return us to
-                // the original position?
-                seek (orig_pos, SEEK_SET);
-
-                off_t remaining = eof_pos - orig_pos;
+                off_t remaining = eof_pos - cur_pos;
 
                 if (remaining < skip)
-                  seek (0, SEEK_END);
+                  {
+                    is.seekg (0, is.end);
+                    cur_pos = eof_pos;
+                  }
                 else
-                  seek (skip, SEEK_CUR);
-
-                if (! is)
-                  break;
+                  {
+                    is.seekg (skip, is.cur);
+                    cur_pos += skip;
+                  }
               }
           }
 
@@ -6777,18 +6784,18 @@
   static bool
   convert_data (const T *data, void *conv_data, octave_idx_type n_elts,
                 oct_data_conv::data_type output_type,
-                octave::mach_info::float_format flt_fmt)
+                mach_info::float_format flt_fmt)
   {
     bool retval = true;
 
     bool swap = false;
 
-    if (octave::mach_info::words_big_endian ())
-      swap = (flt_fmt == octave::mach_info::flt_fmt_ieee_little_endian);
+    if (mach_info::words_big_endian ())
+      swap = (flt_fmt == mach_info::flt_fmt_ieee_little_endian);
     else
-      swap = (flt_fmt == octave::mach_info::flt_fmt_ieee_big_endian);
-
-    bool do_float_conversion = flt_fmt != octave::mach_info::float_format ();
+      swap = (flt_fmt == mach_info::flt_fmt_ieee_big_endian);
+
+    bool do_float_conversion = flt_fmt != mach_info::float_format ();
 
     typedef typename ultimate_element_type<T>::type ult_elt_type;
 
@@ -7283,7 +7290,7 @@
     return retval;
   }
 
-  stream_list::stream_list (interpreter&)
+  stream_list::stream_list (interpreter& interp)
     : list (), lookup_cache (list.end ()), m_stdin_file (-1),
       m_stdout_file (-1), m_stderr_file (-1)
   {
@@ -7294,7 +7301,10 @@
 
     // FIXME: we should be accessing octave_stdout from the interpreter.
 
-    stream stdout_stream = octave_ostream::create (&octave_stdout, "stdout");
+    output_system& output_sys = interp.get_output_system ();
+
+    stream stdout_stream
+      = octave_ostream::create (&(output_sys.__stdout__ ()), "stdout");
 
     stream stderr_stream = octave_ostream::create (&std::cerr, "stderr");
 
@@ -7385,7 +7395,7 @@
     if (fid < 3)
       err_invalid_file_id (fid, who);
 
-    ostrl_map::iterator iter = list.find (fid);
+    auto iter = list.find (fid);
 
     if (iter == list.end ())
       err_invalid_file_id (fid, who);
@@ -7432,7 +7442,7 @@
         list[2].flush ();
       }
 
-    for (ostrl_map::iterator iter = list.begin (); iter != list.end (); )
+    for (auto iter = list.begin (); iter != list.end (); )
       {
         int fid = iter->first;
         if (fid < 3)  // Don't delete stdin, stdout, stderr
--- a/libinterp/corefcn/oct-tex-lexer.in.ll	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct-tex-lexer.in.ll	Thu Dec 20 17:18:56 2018 -0500
@@ -62,7 +62,9 @@
 
 #include "unistd-wrappers.h"
 
-#include "txt-eng.h"
+#include "text-engine.h"
+
+// oct-tex-parser.h must be included after text-engine.h
 #include "oct-tex-parser.h"
 
 // FIXME: with bison 3.x, OCTAVE_TEX_STYPE appears in the generated
@@ -200,7 +202,7 @@
 void *
 octave_tex_realloc (void *ptr, yy_size_t size, yyscan_t)
 {
-  return realloc (ptr, size);
+return realloc (ptr, size);
 }
 
 void
@@ -209,40 +211,41 @@
   free (ptr);
 }
 
-bool
-text_parser_tex::init_lexer (const std::string& s)
+namespace octave
 {
-  if (! scanner)
-    octave_tex_lex_init (&scanner);
+  bool text_parser_tex::init_lexer (const std::string& s)
+  {
+    if (! scanner)
+      octave_tex_lex_init (&scanner);
 
-  if (scanner)
-    {
-      if (buffer_state)
-        {
-          octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
-                                     scanner);
-          buffer_state = nullptr;
-        }
+    if (scanner)
+      {
+        if (buffer_state)
+          {
+            octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
+                                       scanner);
+            buffer_state = nullptr;
+          }
 
-      buffer_state = octave_tex__scan_bytes (s.data (), s.length (), scanner);
-    }
+        buffer_state = octave_tex__scan_bytes (s.data (), s.length (), scanner);
+      }
 
-  return (scanner && buffer_state);
-}
+    return (scanner && buffer_state);
+  }
 
-void
-text_parser_tex::destroy_lexer (void)
-{
-  if (buffer_state)
-    {
-      octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
-                                 scanner);
-      buffer_state = nullptr;
-    }
+  void text_parser_tex::destroy_lexer (void)
+  {
+    if (buffer_state)
+      {
+        octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
+                                   scanner);
+        buffer_state = nullptr;
+      }
 
-  if (scanner)
-    {
-      octave_tex_lex_destroy (scanner);
-      scanner = nullptr;
-    }
+    if (scanner)
+      {
+        octave_tex_lex_destroy (scanner);
+        scanner = nullptr;
+      }
+  }
 }
--- a/libinterp/corefcn/oct-tex-parser.in.yy	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
-
-Copyright (C) 2013-2018 Michael Goffioul
-
-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/>.
-
-*/
-
-%{
-
-#define YYDEBUG 1
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include "txt-eng.h"
-#include "oct-tex-parser.h"
-
-extern int octave_tex_lex (YYSTYPE *, void *);
-static void yyerror (text_parser_tex& parser, const char *s);
-
-#define scanner parser.get_scanner ()
-#define yyalloc octave_tex_yyalloc
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-   // Disable this warning for code that is generated by Bison,
-   // including grammar rules.  Push the current state so we can
-   // restore the warning state prior to functions we define at
-   // the bottom of the file.
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-%}
-
-%API_PREFIX_DECL%
-
-%define api.pure
-%parse-param { text_parser_tex& parser }
-%lex-param { void *scanner }
-
-%code requires {#include <string>}
-
-%union
-{
-  // Leaf symbols produced by the scanner.
-  char                       ch;
-  double                     num;
-  int                        sym;
-
-  // Used for string buffering.
-  std::string*               str;
-
-  // Objects produced by the parser.
-  text_element*              e_base;
-  text_element_list*         e_list;
-}
-
-%token BF IT SL RM
-%token FONTNAME FONTSIZE
-%token COLOR COLOR_RGB
-%token START END SUPER SUB
-%token<ch> CH
-%token<num> NUM
-%token<sym> SYM
-
-%type<str> simple_string
-%type<e_base> string_element symbol_element
-%type<e_base> superscript_element subscript_element combined_script_element
-%type<e_base> font_modifier_element fontname_element fontsize_element
-%type<e_base> color_element
-%type<e_list> string_element_list scoped_string_element_list
-
-// Make sure there's no memory leak on parse error.
-%destructor { } <ch> <num> <sym>
-%destructor { delete $$; } <*>
-
-%nonassoc SCRIPT
-%nonassoc SUB SUPER
-
-%nonassoc STR
-%nonassoc CH
-
-%start string
-
-%%
-
-simple_string                   : CH
-                                  { $$ = new std::string (1, $1); }
-                                | simple_string CH
-                                  { $1->append (1, $2); $$ = $1; }
-                                ;
-
-symbol_element                  : SYM
-                                  { $$ = new text_element_symbol ($1); }
-                                ;
-
-font_modifier_element           : BF
-                                  { $$ = new text_element_fontstyle (text_element_fontstyle::bold); }
-                                | IT
-                                  { $$ = new text_element_fontstyle (text_element_fontstyle::italic); }
-                                | SL
-                                  { $$ = new text_element_fontstyle (text_element_fontstyle::oblique); }
-                                | RM
-                                  { $$ = new text_element_fontstyle (text_element_fontstyle::normal); }
-                                ;
-
-fontsize_element                : FONTSIZE START NUM END
-                                  { $$ = new text_element_fontsize ($3); }
-                                ;
-
-fontname_element                : FONTNAME START simple_string END
-                                  {
-                                    $$ = new text_element_fontname (*$3);
-                                    delete $3;
-                                  }
-                                ;
-
-color_element                   : COLOR START simple_string END
-                                  {
-                                    $$ = new text_element_color (*$3);
-                                    delete $3;
-                                  }
-                                | COLOR_RGB START NUM NUM NUM END
-                                  {
-                                    $$ = new text_element_color ($3, $4, $5);
-                                  }
-                                ;
-
-string_element                  : simple_string %prec STR
-                                  {
-                                    $$ = new text_element_string (*$1);
-                                    delete $1;
-                                  }
-                                | scoped_string_element_list
-                                  { $$ = $1; }
-                                | symbol_element
-                                | font_modifier_element
-                                | fontsize_element
-                                | fontname_element
-                                | color_element
-                                | superscript_element %prec SCRIPT
-                                | subscript_element %prec SCRIPT
-                                | combined_script_element
-                                ;
-
-superscript_element             : SUPER CH
-                                  { $$ = new text_element_superscript ($2); }
-                                | SUPER scoped_string_element_list
-                                  { $$ = new text_element_superscript ($2); }
-                                | SUPER symbol_element
-                                  { $$ = new text_element_superscript ($2); }
-                                ;
-
-subscript_element               : SUB CH
-                                  { $$ = new text_element_subscript ($2); }
-                                | SUB scoped_string_element_list
-                                  { $$ = new text_element_subscript ($2); }
-                                | SUB symbol_element
-                                  { $$ = new text_element_subscript ($2); }
-                                ;
-
-combined_script_element         : subscript_element superscript_element
-                                  { $$ = new text_element_combined ($1, $2); }
-                                | superscript_element subscript_element
-                                  { $$ = new text_element_combined ($1, $2); }
-                                ;
-
-string_element_list             : string_element
-                                  { $$ = new text_element_list ($1); }
-                                | string_element_list string_element
-                                  { $1->push_back ($2); $$ = $1; }
-                                ;
-
-scoped_string_element_list      : START string_element_list END
-                                  { $$ = $2; }
-                                | START END
-                                  { $$ = new text_element_list (); }
-                                ;
-
-string                          : // empty
-                                  { parser.set_parse_result (new text_element_string ("")); }
-                                | string_element_list
-                                  { parser.set_parse_result ($1); }
-                                ;
-
-%%
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-   // Restore prevailing warning state for remainder of the file.
-#  pragma GCC diagnostic pop
-#endif
-
-text_element*
-text_parser_tex::parse (const std::string& s)
-{
-  octave_tex_debug = 0;
-
-  if (init_lexer (s))
-    {
-      result = nullptr;
-
-      if (octave_tex_parse (*this) == 0)
-        return result;
-    }
-
-  return new text_element_string (s);
-}
-
-static void
-yyerror (text_parser_tex&, const char *s)
-{
-  fprintf (stderr, "TeX parse error: %s\n", s);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/oct-tex-parser.yy	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,235 @@
+/*
+
+Copyright (C) 2013-2018 Michael Goffioul
+
+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/>.
+
+*/
+
+%{
+
+#define YYDEBUG 1
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "text-engine.h"
+
+// oct-tex-parser.h must be included after text-engine.h
+#include "oct-tex-parser.h"
+
+extern int octave_tex_lex (YYSTYPE *, void *);
+ static void yyerror (octave::text_parser_tex& parser, const char *s);
+
+#define scanner parser.get_scanner ()
+#define yyalloc octave_tex_yyalloc
+
+#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+   // Disable this warning for code that is generated by Bison,
+   // including grammar rules.  Push the current state so we can
+   // restore the warning state prior to functions we define at
+   // the bottom of the file.
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+%}
+
+%define api.pure
+// No spaces inside the braces for the prefix definition!
+%define api.prefix {octave_tex_}
+%parse-param { octave::text_parser_tex& parser }
+%lex-param { void *scanner }
+
+%code requires {#include <string>}
+
+%union
+{
+  // Leaf symbols produced by the scanner.
+  char ch;
+  double num;
+  int sym;
+
+  // Used for string buffering.
+  std::string *str;
+
+  // Objects produced by the parser.
+  octave::text_element *e_base;
+  octave::text_element_list *e_list;
+}
+
+%token BF IT SL RM
+%token FONTNAME FONTSIZE
+%token COLOR COLOR_RGB
+%token START END SUPER SUB
+%token<ch> CH
+%token<num> NUM
+%token<sym> SYM
+
+%type<str> simple_string
+%type<e_base> string_element symbol_element
+%type<e_base> superscript_element subscript_element combined_script_element
+%type<e_base> font_modifier_element fontname_element fontsize_element
+%type<e_base> color_element
+%type<e_list> string_element_list scoped_string_element_list
+
+// Make sure there's no memory leak on parse error.
+%destructor { } <ch> <num> <sym>
+%destructor { delete $$; } <*>
+
+%nonassoc SCRIPT
+%nonassoc SUB SUPER
+
+%nonassoc STR
+%nonassoc CH
+
+%start string
+
+%%
+
+simple_string           : CH
+                          { $$ = new std::string (1, $1); }
+                        | simple_string CH
+                          { $1->append (1, $2); $$ = $1; }
+                        ;
+
+symbol_element          : SYM
+                          { $$ = new octave::text_element_symbol ($1); }
+                        ;
+
+font_modifier_element   : BF
+                          { $$ = new octave::text_element_fontstyle (octave::text_element_fontstyle::bold); }
+                        | IT
+                          { $$ = new octave::text_element_fontstyle (octave::text_element_fontstyle::italic); }
+                        | SL
+                          { $$ = new octave::text_element_fontstyle (octave::text_element_fontstyle::oblique); }
+                        | RM
+                          { $$ = new octave::text_element_fontstyle (octave::text_element_fontstyle::normal); }
+                        ;
+
+fontsize_element        : FONTSIZE START NUM END
+                          { $$ = new octave::text_element_fontsize ($3); }
+                        ;
+
+fontname_element        : FONTNAME START simple_string END
+                          {
+                            $$ = new octave::text_element_fontname (*$3);
+                            delete $3;
+                          }
+                        ;
+
+color_element           : COLOR START simple_string END
+                          {
+                            $$ = new octave::text_element_color (*$3);
+                            delete $3;
+                          }
+                        | COLOR_RGB START NUM NUM NUM END
+                          {
+                            $$ = new octave::text_element_color ($3, $4, $5);
+                          }
+                        ;
+
+string_element          : simple_string %prec STR
+                          {
+                            $$ = new octave::text_element_string (*$1);
+                            delete $1;
+                          }
+                        | scoped_string_element_list
+                          { $$ = $1; }
+                        | symbol_element
+                        | font_modifier_element
+                        | fontsize_element
+                        | fontname_element
+                        | color_element
+                        | superscript_element %prec SCRIPT
+                        | subscript_element %prec SCRIPT
+                        | combined_script_element
+                        ;
+
+superscript_element     : SUPER CH
+                          { $$ = new octave::text_element_superscript ($2); }
+                        | SUPER scoped_string_element_list
+                          { $$ = new octave::text_element_superscript ($2); }
+                        | SUPER symbol_element
+                          { $$ = new octave::text_element_superscript ($2); }
+                        ;
+
+subscript_element       : SUB CH
+                          { $$ = new octave::text_element_subscript ($2); }
+                        | SUB scoped_string_element_list
+                          { $$ = new octave::text_element_subscript ($2); }
+                        | SUB symbol_element
+                          { $$ = new octave::text_element_subscript ($2); }
+                        ;
+
+combined_script_element : subscript_element superscript_element
+                          { $$ = new octave::text_element_combined ($1, $2); }
+                        | superscript_element subscript_element
+                          { $$ = new octave::text_element_combined ($1, $2); }
+                        ;
+
+string_element_list     : string_element
+                          { $$ = new octave::text_element_list ($1); }
+                        | string_element_list string_element
+                          { $1->push_back ($2); $$ = $1; }
+                        ;
+
+scoped_string_element_list
+                        : START string_element_list END
+                          { $$ = $2; }
+                        | START END
+                          { $$ = new octave::text_element_list (); }
+                        ;
+
+string                  : // empty
+                          { parser.set_parse_result (new octave::text_element_string ("")); }
+                        | string_element_list
+                          { parser.set_parse_result ($1); }
+                        ;
+
+%%
+
+#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+   // Restore prevailing warning state for remainder of the file.
+#  pragma GCC diagnostic pop
+#endif
+
+namespace octave
+{
+  text_element*
+  text_parser_tex::parse (const std::string& s)
+  {
+    octave_tex_debug = 0;
+
+    if (init_lexer (s))
+      {
+        result = nullptr;
+
+        if (octave_tex_parse (*this) == 0)
+          return result;
+      }
+
+    return new text_element_string (s);
+  }
+}
+
+static void
+yyerror (octave::text_parser_tex&, const char *s)
+{
+  fprintf (stderr, "TeX parse error: %s\n", s);
+}
--- a/libinterp/corefcn/oct.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/oct.h	Thu Dec 20 17:18:56 2018 -0500
@@ -32,9 +32,6 @@
 #include "defun-dld.h"
 #include "error.h"
 #include "errwarn.h"
-// FIXME: gripes.h was deprecated in version 4.2 and will be removed
-// in version 5.
-#include "gripes.h"
 #include "help.h"
 #include "ovl.h"
 #include "pager.h"
--- a/libinterp/corefcn/octave-link.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/octave-link.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,7 +36,8 @@
 #include "oct-mutex.h"
 #include "ovl.h"
 #include "pager.h"
-#include "symscope.h"
+#include "syminfo.h"
+#include "symtab.h"
 
 static int
 octave_readline_hook (void)
@@ -69,12 +70,14 @@
   if (enabled ())
     {
       octave::symbol_table& symtab
-        = octave::__get_symbol_table__ ("octave_link::set_workspace");
+         = octave::__get_symbol_table__ ("octave_link::set_workspace");
 
-      octave::symbol_scope scope = symtab.current_scope ();
+      octave::call_stack& cs
+        = octave::__get_call_stack__ ("octave_link::set_workspace");
 
       instance->do_set_workspace (symtab.at_top_level (),
-                                  instance->debugging, scope, true);
+                                  instance->debugging,
+                                  cs.get_symbol_info (), true);
     }
 }
 
@@ -152,28 +155,6 @@
   return retval;
 }
 
-DEFUN (__octave_link_message_dialog__, args, ,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} __octave_link_message_dialog__ (@var{dlg}, @var{msg}, @var{title})
-Undocumented internal function.
-@end deftypefn */)
-{
-  octave_value retval;
-
-  if (args.length () == 3)
-    {
-      std::string dlg = args(0).xstring_value ("invalid arguments");
-      std::string msg = args(1).xstring_value ("invalid arguments");
-      std::string title = args(2).xstring_value ("invalid arguments");
-
-      octave::flush_stdout ();
-
-      retval = octave_link::message_dialog (dlg, msg, title);
-    }
-
-  return retval;
-}
-
 DEFUN (__octave_link_question_dialog__, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} __octave_link_question_dialog__ (@var{msg}, @var{title}, @var{btn1}, @var{btn2}, @var{btn3}, @var{default})
@@ -257,7 +238,7 @@
       nel -= 2;
       Cell items (dim_vector (1, nel));
 
-      std::list<std::string>::iterator it = items_lst.begin ();
+      auto it = items_lst.begin ();
 
       for (int idx = 0; idx < nel; idx++, it++)
         items.xelem (idx) = *it;
@@ -373,6 +354,25 @@
   return ovl (items);
 }
 
+
+DEFUN (__octave_link_named_icon__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __octave_link_dialog_icons__ (@var{icon_name})
+Undocumented internal function.
+@end deftypefn */)
+{
+  uint8NDArray retval;
+
+  if (args.length () > 0)
+    {
+      std::string icon_name = args(0).xstring_value ("invalid arguments");
+
+      retval = octave_link::get_named_icon (icon_name);
+    }
+
+  return ovl (retval);
+}
+
 DEFUN (__octave_link_show_preferences__, , ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} __octave_link_show_preferences__ ()
@@ -382,6 +382,68 @@
   return ovl (octave_link::show_preferences ());
 }
 
+DEFUN (__octave_link_gui_preference__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __octave_link_gui_preference__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  std::string key;
+  std::string value = "";
+
+  if (args.length () >= 1)
+    key = args(0).string_value();
+  else
+    error ("__octave_link_gui_preference__: "
+           "first argument must be the preference key");
+
+  if (args.length () >= 2)
+    value = args(1).string_value();
+
+  return ovl (octave_link::gui_preference (key, value));
+}
+
+DEFUN (__octave_link_file_remove__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __octave_link_file_remove__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  std::string old_name, new_name;
+
+  if (args.length () == 2)
+    {
+      old_name = args(0).string_value();
+      new_name = args(1).string_value();
+    }
+  else
+    error ("__octave_link_file_remove__: "
+           "old and new name expected as arguments");
+
+  octave_link::file_remove (old_name, new_name);
+
+  return ovl ();
+}
+
+DEFUN (__octave_link_file_renamed__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __octave_link_file_renamed__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  bool load_new;
+
+  if (args.length () == 1)
+    load_new = args(0).bool_value();
+  else
+    error ("__octave_link_file_renamed__: "
+           "first argument must be boolean for reload new named file");
+
+  octave_link::file_renamed (load_new);
+
+  return ovl ();
+}
+
 DEFMETHOD (openvar, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} openvar (@var{name})
--- a/libinterp/corefcn/octave-link.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/octave-link.h	Thu Dec 20 17:18:56 2018 -0500
@@ -31,15 +31,16 @@
 #include <string>
 
 #include "oct-mutex.h"
-
+#include "octave.h"
 #include "event-queue.h"
+#include "uint8NDArray.h"
 
 class octave_value;
 class string_vector;
 
 namespace octave
 {
-  class symbol_scope;
+  class symbol_info_list;
 }
 
 //! Provides threadsafe access to octave.
@@ -103,53 +104,12 @@
     return retval;
   }
 
-  template <typename T>
-  static void post_event (T *obj, void (T::*method) (void))
-  {
-    if (enabled ())
-      instance->do_post_event (obj, method);
-  }
-
-  template <typename T, typename A>
-  static void post_event (T *obj, void (T::*method) (A), A arg)
-  {
-    if (enabled ())
-      instance->do_post_event (obj, method, arg);
-  }
-
-  template <typename T, typename A>
-  static void post_event (T *obj, void (T::*method) (const A&), const A& arg)
+  template <typename T, typename... Params, typename... Args>
+  static void
+  post_event (T *obj, void (T::*method) (Params...), Args&&... args)
   {
     if (enabled ())
-      instance->do_post_event (obj, method, arg);
-  }
-
-  template <class T, class A, class B>
-  static void post_event (T *obj, void (T::*method) (const A&, const B&),
-                          const A& arg_a, const B& arg_b)
-  {
-    if (enabled ())
-      instance->do_post_event<T, A, B> (obj, method, arg_a, arg_b);
-  }
-
-  template <class T, class A, class B, class C>
-  static void post_event (T *obj,
-                          void (T::*method) (const A&, const B&, const C&),
-                          const A& arg_a, const B& arg_b, const C& arg_c)
-  {
-    if (enabled ())
-      instance->do_post_event<T, A, B, C> (obj, method, arg_a, arg_b, arg_c);
-  }
-
-  template <class T, class A, class B, class C, class D>
-  static void
-  post_event (T *obj,
-              void (T::*method) (const A&, const B&, const C&, const D&),
-              const A& arg_a, const B& arg_b, const C& arg_c, const D& arg_d)
-  {
-    if (enabled ())
-      instance->do_post_event<T, A, B, C, D>
-        (obj, method, arg_a, arg_b, arg_c, arg_d);
+      instance->do_post_event (obj, method, std::forward<Args> (args)...);
   }
 
   static void
@@ -189,13 +149,6 @@
     return enabled () ? instance->do_prompt_new_edit_file (file) : false;
   }
 
-  static int
-  message_dialog (const std::string& dlg, const std::string& msg,
-                  const std::string& title)
-  {
-    return enabled () ? instance->do_message_dialog (dlg, msg, title) : 0;
-  }
-
   static std::string
   question_dialog (const std::string& msg, const std::string& title,
                    const std::string& btn1, const std::string& btn2,
@@ -262,6 +215,20 @@
       instance->do_change_directory (dir);
   }
 
+  // Methods for removing/renaming files which might be open in editor
+  static void file_remove (const std::string& old_name,
+                           const std::string& new_name)
+  {
+    if (octave::application::is_gui_running () && enabled ())
+      instance->do_file_remove (old_name, new_name);
+  }
+
+  static void file_renamed (bool load_new)
+  {
+    if (octave::application::is_gui_running () && enabled ())
+      instance->do_file_renamed (load_new);
+  }
+
   // Preserves pending input.
   static void execute_command_in_terminal (const std::string& command)
   {
@@ -269,14 +236,21 @@
       instance->do_execute_command_in_terminal (command);
   }
 
+  static uint8NDArray
+  get_named_icon (const std::string& icon_name)
+  {
+    return (enabled () ?
+            instance->do_get_named_icon (icon_name) : uint8NDArray ());
+  }
+
   static void set_workspace (void);
 
   static void set_workspace (bool top_level,
-                             const octave::symbol_scope& scope,
+                             const octave::symbol_info_list& syminfo,
                              bool update_variable_editor = true)
   {
     if (enabled ())
-      instance->do_set_workspace (top_level, instance->debugging, scope,
+      instance->do_set_workspace (top_level, instance->debugging, syminfo,
                                   update_variable_editor);
   }
 
@@ -368,13 +342,6 @@
       }
   }
 
-  static void set_default_prompts (std::string& ps1, std::string& ps2,
-                                   std::string& ps4)
-  {
-    if (enabled ())
-      instance->do_set_default_prompts (ps1, ps2, ps4);
-  }
-
   static bool enable (void)
   {
     return instance_ok () ? instance->do_enable () : false;
@@ -416,6 +383,18 @@
       return false;
   }
 
+  static std::string
+  gui_preference (const std::string& key,
+                  const std::string& value)
+  {
+    if (enabled ())
+      {
+        return instance->do_gui_preference (key, value);
+      }
+    else
+      return "";
+  }
+
   static bool
   show_doc (const std::string & file)
   {
@@ -486,49 +465,10 @@
   void do_process_events (void);
   void do_discard_events (void);
 
-  template <typename T>
-  void do_post_event (T *obj, void (T::*method) (void))
-  {
-    gui_event_queue.add_method (obj, method);
-  }
-
-  template <typename T, typename A>
-  void do_post_event (T *obj, void (T::*method) (A), A arg)
-  {
-    gui_event_queue.add_method (obj, method, arg);
-  }
-
-  template <typename T, typename A>
-  void do_post_event (T *obj, void (T::*method) (const A&), const A& arg)
-  {
-    gui_event_queue.add_method (obj, method, arg);
-  }
-
-  template <class T, class A, class B>
-  void do_post_event (T *obj, void (T::*method) (const A&, const B&),
-                      const A& arg_a, const B& arg_b)
+  template <typename T, typename... Params, typename... Args>
+  void do_post_event (T *obj, void (T::*method) (Params...), Args&&... args)
   {
-    gui_event_queue.add_method<T, A, B>
-      (obj, method, arg_a, arg_b);
-  }
-
-  template <class T, class A, class B, class C>
-  void do_post_event (T *obj,
-                      void (T::*method) (const A&, const B&, const C&),
-                      const A& arg_a, const B& arg_b, const C& arg_c)
-  {
-    gui_event_queue.add_method<T, A, B, C>
-      (obj, method, arg_a, arg_b, arg_c);
-  }
-
-  template <class T, class A, class B, class C, class D>
-  void
-  do_post_event (T *obj,
-                 void (T::*method) (const A&, const B&, const C&, const D&),
-                 const A& arg_a, const B& arg_b, const C& arg_c, const D& arg_d)
-  {
-    gui_event_queue.add_method<T, A, B, C, D>
-      (obj, method, arg_a, arg_b, arg_c, arg_d);
+    gui_event_queue.add_method (obj, method, std::forward<Args> (args)...);
   }
 
   void
@@ -552,11 +492,6 @@
 
   virtual bool do_edit_file (const std::string& file) = 0;
   virtual bool do_prompt_new_edit_file (const std::string& file) = 0;
-
-  virtual int
-  do_message_dialog (const std::string& dlg, const std::string& msg,
-                     const std::string& title) = 0;
-
   virtual std::string
   do_question_dialog (const std::string& msg, const std::string& title,
                       const std::string& btn1, const std::string& btn2,
@@ -591,11 +526,18 @@
 
   virtual void do_change_directory (const std::string& dir) = 0;
 
+  virtual void do_file_remove (const std::string& old_name,
+                               const std::string& new_name) = 0;
+  virtual void do_file_renamed (bool) = 0;
+
   virtual void do_execute_command_in_terminal (const std::string& command) = 0;
 
+  virtual uint8NDArray
+  do_get_named_icon (const std::string& icon_name) = 0;
+
   virtual void
   do_set_workspace (bool top_level, bool debug,
-                    const octave::symbol_scope& scope,
+                    const octave::symbol_info_list& syminfo,
                     bool update_variable_editor) = 0;
 
   virtual void do_clear_workspace (void) = 0;
@@ -619,10 +561,10 @@
                                      const std::string& file, int line,
                                      const std::string& cond) = 0;
 
-  virtual void do_set_default_prompts (std::string& ps1, std::string& ps2,
-                                       std::string& ps4) = 0;
+  virtual void do_show_preferences (void) = 0;
 
-  virtual void do_show_preferences (void) = 0;
+  virtual std::string do_gui_preference (const std::string& key,
+                                         const std::string& value) = 0;
 
   virtual void do_show_doc (const std::string& file) = 0;
 
--- a/libinterp/corefcn/ordschur.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/ordschur.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -71,7 +71,7 @@
 [@var{U}, @var{S}] = ordschur (@var{U}, @var{S}, [0,1])
 @end example
 
-@seealso{schur}
+@seealso{schur, ordeig}
 @end deftypefn */)
 {
   if (args.length () != 3)
--- a/libinterp/corefcn/pager.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/pager.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -32,13 +32,13 @@
 #include "cmd-edit.h"
 #include "oct-env.h"
 #include "oct-syscalls.h"
-#include "singleton-cleanup.h"
 
 #include "defaults.h"
 #include "defun.h"
 #include "error.h"
 #include "errwarn.h"
 #include "input.h"
+#include "interpreter.h"
 #include "interpreter-private.h"
 #include "octave.h"
 #include "ovl.h"
@@ -49,226 +49,93 @@
 #include "utils.h"
 #include "variables.h"
 
-// Our actual connection to the external pager.
-static oprocstream *external_pager = nullptr;
-
-// TRUE means we write to the diary file.
-static bool write_to_diary_file = false;
-
-// The name of the current diary file.
-static std::string diary_file ("diary");
-
-// The diary file.
-static std::ofstream external_diary_file;
-
-static std::string
-default_pager (void)
-{
-  std::string pager_binary = octave::sys::env::getenv ("PAGER");
-
-  if (pager_binary.empty ())
-    pager_binary = octave::config::default_pager ();
-
-  return pager_binary;
-}
-
-// The shell command to run as the pager.
-static std::string VPAGER = default_pager ();
-
-// The options to pass to the pager.
-static std::string VPAGER_FLAGS;
-
-// TRUE means that if output is going to the pager, it is sent as soon
-// as it is available.  Otherwise, it is buffered and only sent to the
-// pager when it is time to print another prompt.
-static bool Vpage_output_immediately = false;
-
-// TRUE means all output intended for the screen should be passed
-// through the pager.
-static bool Vpage_screen_output = false;
-
-static bool really_flush_to_pager = false;
-
-static bool flushing_output_to_pager = false;
-
-static void
-clear_external_pager (void)
-{
-  if (external_pager)
-    {
-      octave::child_list& kids
-        = octave::__get_child_list__ ("clear_external_pager");
-
-      kids.remove (external_pager->pid ());
-
-      delete external_pager;
-      external_pager = nullptr;
-    }
-}
-
-static bool
-pager_event_handler (pid_t pid, int status)
-{
-  bool retval = false;
-
-  if (pid > 0)
-    {
-      if (octave::sys::wifexited (status) || octave::sys::wifsignaled (status))
-        {
-          // Avoid warning() since that will put us back in the pager,
-          // which would be bad news.
-
-          std::cerr << "warning: connection to external pager lost (pid = "
-                    << pid << ')' << std::endl;
-          std::cerr << "warning: flushing pending output (please wait)"
-                    << std::endl;
-
-          // Request removal of this PID from the list of child
-          // processes.
-
-          retval = true;
-        }
-    }
-
-  return retval;
-}
-
-static std::string
-pager_command (void)
-{
-  std::string cmd = VPAGER;
-
-  if (! (cmd.empty () || VPAGER_FLAGS.empty ()))
-    cmd += ' ' + VPAGER_FLAGS;
-
-  return cmd;
-}
-
-static void
-do_sync (const char *msg, int len, bool bypass_pager)
-{
-  if (msg && len > 0)
-    {
-      if (bypass_pager)
-        {
-          std::cout.write (msg, len);
-          std::cout.flush ();
-        }
-      else
-        {
-          if (! external_pager)
-            {
-              std::string pgr = pager_command ();
-
-              if (! pgr.empty ())
-                {
-                  external_pager = new oprocstream (pgr.c_str ());
-
-                  if (external_pager)
-                    {
-                      octave::child_list& kids
-                        = octave::__get_child_list__ ("do_sync");
-
-                      kids.insert (external_pager->pid (),
-                                   pager_event_handler);
-                    }
-                }
-            }
-
-          if (external_pager)
-            {
-              if (external_pager->good ())
-                {
-                  external_pager->write (msg, len);
-
-                  external_pager->flush ();
-
-#if defined (EPIPE)
-                  if (errno == EPIPE)
-                    external_pager->setstate (std::ios::failbit);
-#endif
-                }
-              else
-                {
-                  // FIXME: omething is not right with the
-                  // pager.  If it died then we should receive a
-                  // signal for that.  If there is some other problem,
-                  // then what?
-                }
-            }
-          else
-            {
-              std::cout.write (msg, len);
-              std::cout.flush ();
-            }
-        }
-    }
-}
-
-// Assume our terminal wraps long lines.
-
-static bool
-more_than_a_screenful (const char *s, int len)
-{
-  if (s)
-    {
-      int available_rows = octave::command_editor::terminal_rows () - 2;
-
-      int cols = octave::command_editor::terminal_cols ();
-
-      int count = 0;
-
-      int chars_this_line = 0;
-
-      for (int i = 0; i < len; i++)
-        {
-          if (*s++ == '\n')
-            {
-              count += chars_this_line / cols + 1;
-              chars_this_line = 0;
-            }
-          else
-            chars_this_line++;
-        }
-
-      if (count > available_rows)
-        return true;
-    }
-
-  return false;
-}
-
 namespace octave
 {
+  static bool
+  pager_event_handler (pid_t pid, int status)
+  {
+    bool retval = false;
+
+    if (pid > 0)
+      {
+        if (octave::sys::wifexited (status) || octave::sys::wifsignaled (status))
+          {
+            // Avoid warning() since that will put us back in the pager,
+            // which would be bad news.
+
+            std::cerr << "warning: connection to external pager lost (pid = "
+                      << pid << ')' << std::endl;
+            std::cerr << "warning: flushing pending output (please wait)"
+                      << std::endl;
+
+            // Request removal of this PID from the list of child
+            // processes.
+
+            retval = true;
+          }
+      }
+
+    return retval;
+  }
+
+  // Assume our terminal wraps long lines.
+
+  static bool
+  more_than_a_screenful (const char *s, int len)
+  {
+    if (s)
+      {
+        int available_rows = octave::command_editor::terminal_rows () - 2;
+
+        int cols = octave::command_editor::terminal_cols ();
+
+        int count = 0;
+
+        int chars_this_line = 0;
+
+        for (int i = 0; i < len; i++)
+          {
+            if (*s++ == '\n')
+              {
+                count += chars_this_line / cols + 1;
+                chars_this_line = 0;
+              }
+            else
+              chars_this_line++;
+          }
+
+        if (count > available_rows)
+          return true;
+      }
+
+    return false;
+  }
+
+  static std::string default_pager (void)
+  {
+    std::string pager_binary = sys::env::getenv ("PAGER");
+
+    if (pager_binary.empty ())
+      pager_binary = config::default_pager ();
+
+    return pager_binary;
+  }
+
   int
   pager_buf::sync (void)
   {
-    if (! application::interactive ()
-        || application::forced_interactive ()
-        || really_flush_to_pager
-        || (Vpage_screen_output && Vpage_output_immediately)
-        || ! Vpage_screen_output)
-      {
-        char *buf = eback ();
+    octave::output_system& output_sys
+      = octave::__get_output_system__ ("pager_buf::sync");
 
-        int len = pptr () - buf;
+    char *buf = eback ();
 
-        bool bypass_pager = (! application::interactive ()
-                             || application::forced_interactive ()
-                             || ! Vpage_screen_output
-                             || (really_flush_to_pager
-                                 && Vpage_screen_output
-                                 && ! Vpage_output_immediately
-                                 && ! more_than_a_screenful (buf, len)));
+    int len = pptr () - buf;
 
-        if (len > 0)
-          {
-            do_sync (buf, len, bypass_pager);
+    if (output_sys.sync (buf, len))
+      {
+        flush_current_contents_to_diary ();
 
-            flush_current_contents_to_diary ();
-
-            seekoff (0, std::ios::beg);
-          }
+        seekoff (0, std::ios::beg);
       }
 
     return 0;
@@ -295,7 +162,11 @@
   int
   diary_buf::sync (void)
   {
-    if (write_to_diary_file && external_diary_file)
+    output_system& output_sys = __get_output_system__ ("__stdout__");
+
+    std::ofstream& external_diary_file = output_sys.external_diary_file ();
+
+    if (output_sys.write_to_diary_file () && external_diary_file)
       {
         char *buf = eback ();
 
@@ -310,8 +181,6 @@
     return 0;
   }
 
-  pager_stream *pager_stream::instance = nullptr;
-
   pager_stream::pager_stream (void) : std::ostream (nullptr), pb (nullptr)
   {
     pb = new pager_buf ();
@@ -325,24 +194,21 @@
     delete pb;
   }
 
-  std::ostream&
-  pager_stream::stream (void)
+  std::ostream& pager_stream::stream (void)
   {
-    return instance_ok () ? *instance : std::cout;
+    return *this;
   }
 
-  void
-  pager_stream::flush_current_contents_to_diary (void)
+  void pager_stream::flush_current_contents_to_diary (void)
   {
-    if (instance_ok ())
-      instance->do_flush_current_contents_to_diary ();
+    if (pb)
+      pb->flush_current_contents_to_diary ();
   }
 
-  void
-  pager_stream::set_diary_skip (void)
+  void pager_stream::set_diary_skip (void)
   {
-    if (instance_ok ())
-      instance->do_set_diary_skip ();
+    if (pb)
+      pb->set_diary_skip ();
   }
 
   // Reinitialize the pager buffer to avoid hanging on to large internal
@@ -350,29 +216,7 @@
   // called when the pager is not in use.  For example, just before
   // getting command-line input.
 
-  void
-  pager_stream::reset (void)
-  {
-    if (instance_ok ())
-      instance->do_reset ();
-  }
-
-  void
-  pager_stream::do_flush_current_contents_to_diary (void)
-  {
-    if (pb)
-      pb->flush_current_contents_to_diary ();
-  }
-
-  void
-  pager_stream::do_set_diary_skip (void)
-  {
-    if (pb)
-      pb->set_diary_skip ();
-  }
-
-  void
-  pager_stream::do_reset (void)
+  void pager_stream::reset (void)
   {
     delete pb;
     pb = new pager_buf ();
@@ -380,27 +224,6 @@
     setf (unitbuf);
   }
 
-  bool
-  pager_stream::instance_ok (void)
-  {
-    bool retval = true;
-
-    if (! instance)
-      {
-        instance = new pager_stream ();
-
-        if (instance)
-          singleton_cleanup_list::add (cleanup_instance);
-      }
-
-    if (! instance)
-      error ("unable to create pager_stream object!");
-
-    return retval;
-  }
-
-  diary_stream *diary_stream::instance = nullptr;
-
   diary_stream::diary_stream (void) : std::ostream (nullptr), db (nullptr)
   {
     db = new diary_buf ();
@@ -414,10 +237,9 @@
     delete db;
   }
 
-  std::ostream&
-  diary_stream::stream (void)
+  std::ostream& diary_stream::stream (void)
   {
-    return instance_ok () ? *instance : std::cout;
+    return *this;
   }
 
   // Reinitialize the diary buffer to avoid hanging on to large internal
@@ -425,15 +247,7 @@
   // called when the pager is not in use.  For example, just before
   // getting command-line input.
 
-  void
-  diary_stream::reset (void)
-  {
-    if (instance_ok ())
-      instance->do_reset ();
-  }
-
-  void
-  diary_stream::do_reset (void)
+  void diary_stream::reset (void)
   {
     delete db;
     db = new diary_buf ();
@@ -441,82 +255,243 @@
     setf (unitbuf);
   }
 
-  bool
-  diary_stream::instance_ok (void)
+  void flush_stdout (void)
   {
-    bool retval = true;
+    output_system& output_sys = __get_output_system__ ("flush_stdout");
 
-    if (! instance)
-      {
-        instance = new diary_stream ();
+    output_sys.flush_stdout ();
+  }
 
-        if (instance)
-          singleton_cleanup_list::add (cleanup_instance);
-      }
+  output_system::output_system (interpreter& interp)
+    : m_interpreter (interp), m_pager_stream (), m_diary_stream (),
+      m_external_pager (nullptr), m_external_diary_file (),
+      m_diary_file_name ("diary"), m_PAGER (default_pager ()),
+      m_PAGER_FLAGS (), m_page_output_immediately (false),
+      m_page_screen_output (false), m_write_to_diary_file (false),
+      m_really_flush_to_pager (false), m_flushing_output_to_pager (false)
+  { }
 
-    if (! instance)
-      error ("unable to create diary_stream object!");
+  octave_value output_system::PAGER (const octave_value_list& args,
+                                     int nargout)
+  {
+    return set_internal_variable (m_PAGER, args, nargout, "PAGER", false);
+  }
 
-    return retval;
+  octave_value output_system::PAGER_FLAGS (const octave_value_list& args,
+                                           int nargout)
+  {
+    return set_internal_variable (m_PAGER_FLAGS, args, nargout,
+                                  "PAGER_FLAGS", false);
   }
 
-  void
-  flush_stdout (void)
+  octave_value
+  output_system::page_output_immediately (const octave_value_list& args,
+                                          int nargout)
+  {
+    return set_internal_variable (m_page_output_immediately, args, nargout,
+                                  "page_output_immediately");
+  }
+
+  octave_value
+  output_system::page_screen_output (const octave_value_list& args,
+                                     int nargout)
+  {
+    return set_internal_variable (m_page_screen_output, args, nargout,
+                                  "page_screen_output");
+  }
+
+  std::string output_system::pager_command (void) const
   {
-    if (! flushing_output_to_pager)
+    std::string cmd = m_PAGER;
+
+    if (! (cmd.empty () || m_PAGER_FLAGS.empty ()))
+      cmd += ' ' + m_PAGER_FLAGS;
+
+    return cmd;
+  }
+
+  void output_system::reset (void)
+  {
+    flush_stdout ();
+
+    m_pager_stream.reset ();
+    m_diary_stream.reset ();
+  }
+
+  void output_system::flush_stdout (void)
+  {
+    if (! m_flushing_output_to_pager)
       {
         unwind_protect frame;
 
-        frame.protect_var (really_flush_to_pager);
-        frame.protect_var (flushing_output_to_pager);
+        frame.protect_var (m_really_flush_to_pager);
+        frame.protect_var (m_flushing_output_to_pager);
 
-        really_flush_to_pager = true;
-        flushing_output_to_pager = true;
+        m_really_flush_to_pager = true;
+        m_flushing_output_to_pager = true;
 
-        octave_stdout.flush ();
+        std::ostream& pager_ostream = m_pager_stream.stream ();
+
+        pager_ostream.flush ();
 
         clear_external_pager ();
       }
   }
-}
+
+  void output_system::close_diary (void)
+  {
+    // Try to flush the current buffer to the diary now, so that things
+    // like
+    //
+    // function foo ()
+    //   diary on;
+    //   ...
+    //   diary off;
+    // endfunction
+    //
+    // will do the right thing.
+
+    m_pager_stream.flush_current_contents_to_diary ();
+
+    if (m_external_diary_file.is_open ())
+      {
+        octave_diary.flush ();
+        m_external_diary_file.close ();
+      }
+  }
+
+  void output_system::open_diary (void)
+  {
+    close_diary ();
+
+    // If there is pending output in the pager buf, it should not go
+    // into the diary file.
+
+    m_pager_stream.set_diary_skip ();
+
+    m_external_diary_file.open (m_diary_file_name.c_str (), std::ios::app);
+
+    if (! m_external_diary_file)
+      error ("diary: can't open diary file '%s'", m_diary_file_name.c_str ());
+  }
 
-static void
-close_diary_file (void)
-{
-  // Try to flush the current buffer to the diary now, so that things
-  // like
-  //
-  // function foo ()
-  //   diary on;
-  //   ...
-  //   diary off;
-  // endfunction
-  //
-  // will do the right thing.
+  bool output_system::sync (const char *buf, int len)
+  {
+    if (! application::interactive ()
+        || application::forced_interactive ()
+        || m_really_flush_to_pager
+        || (m_page_screen_output && m_page_output_immediately)
+        || ! m_page_screen_output)
+      {
+        bool bypass_pager = (! application::interactive ()
+                             || application::forced_interactive ()
+                             || ! m_page_screen_output
+                             || (m_really_flush_to_pager
+                                 && m_page_screen_output
+                                 && ! m_page_output_immediately
+                                 && ! more_than_a_screenful (buf, len)));
+
+        if (len > 0)
+          {
+            do_sync (buf, len, bypass_pager);
 
-  octave::pager_stream::flush_current_contents_to_diary ();
+            return true;
+          }
+      }
+
+    return false;
+  }
+
+  void output_system::clear_external_pager (void)
+  {
+    if (m_external_pager)
+      {
+        child_list& kids = m_interpreter.get_child_list ();
+
+        kids.remove (m_external_pager->pid ());
+
+        delete m_external_pager;
+        m_external_pager = nullptr;
+      }
+  }
 
-  if (external_diary_file.is_open ())
-    {
-      octave_diary.flush ();
-      external_diary_file.close ();
-    }
-}
+  void output_system::start_external_pager (void)
+  {
+    if (m_external_pager)
+      return;
+
+    std::string pgr = pager_command ();
+
+    if (! pgr.empty ())
+      {
+        m_external_pager = new oprocstream (pgr.c_str ());
+
+        if (m_external_pager)
+          {
+            octave::child_list& kids = m_interpreter.get_child_list ();
+
+            kids.insert (m_external_pager->pid (),
+                         pager_event_handler);
+          }
+      }
+  }
+
+  void output_system::do_sync (const char *msg, int len, bool bypass_pager)
+  {
+    if (msg && len > 0)
+      {
+        if (bypass_pager)
+          {
+            std::cout.write (msg, len);
+            std::cout.flush ();
+          }
+        else
+          {
+            start_external_pager ();
 
-static void
-open_diary_file (void)
-{
-  close_diary_file ();
+            if (m_external_pager)
+              {
+                if (m_external_pager->good ())
+                  {
+                    m_external_pager->write (msg, len);
+
+                    m_external_pager->flush ();
 
-  // If there is pending output in the pager buf, it should not go
-  // into the diary file.
-
-  octave::pager_stream::set_diary_skip ();
+#if defined (EPIPE)
+                    if (errno == EPIPE)
+                      m_external_pager->setstate (std::ios::failbit);
+#endif
+                  }
+                else
+                  {
+                    // FIXME: something is not right with the
+                    // pager.  If it died then we should receive a
+                    // signal for that.  If there is some other problem,
+                    // then what?
+                  }
+              }
+            else
+              {
+                std::cout.write (msg, len);
+                std::cout.flush ();
+              }
+          }
+      }
+  }
 
-  external_diary_file.open (diary_file.c_str (), std::ios::app);
+  std::ostream& __stdout__ (void)
+  {
+    output_system& output_sys = __get_output_system__ ("__stdout__");
+
+    return output_sys.__stdout__ ();
+  }
 
-  if (! external_diary_file)
-    error ("diary: can't open diary file '%s'", diary_file.c_str ());
+  std::ostream& __diary__ (void)
+  {
+    output_system& output_sys = __get_output_system__ ("__diary__");
+
+    return output_sys.__diary__ ();
+  }
 }
 
 DEFUN (diary, args, nargout,
@@ -558,22 +533,22 @@
   if (nargin > 1)
     print_usage ();
 
-  if (diary_file.empty ())
-    diary_file = "diary";
+  octave::output_system& output_sys = octave::__get_output_system__ ("Fdiary");
 
   if (nargout > 0)
     {
       // Querying diary variables
       if (nargout == 1)
-        return ovl (write_to_diary_file);
+        return ovl (output_sys.write_to_diary_file ());
       else
-        return ovl (write_to_diary_file, diary_file);
+        return ovl (output_sys.write_to_diary_file (),
+                    output_sys.diary_file_name ());
     }
 
   if (nargin == 0)
     {
-      write_to_diary_file = ! write_to_diary_file;
-      open_diary_file ();
+      output_sys.write_to_diary_file (! output_sys.write_to_diary_file ());
+      output_sys.open_diary ();
     }
   else
     {
@@ -581,27 +556,27 @@
 
       if (arg == "on")
         {
-          write_to_diary_file = true;
-          open_diary_file ();
+          output_sys.write_to_diary_file (true);
+          output_sys.open_diary ();
         }
       else if (arg == "off")
         {
-          close_diary_file ();
-          write_to_diary_file = false;
+          output_sys.close_diary ();
+          output_sys.write_to_diary_file (false);
         }
       else
         {
-          diary_file = arg;
-          write_to_diary_file = true;
-          open_diary_file ();
+          output_sys.diary_file_name (arg);
+          output_sys.write_to_diary_file (true);
+          output_sys.open_diary ();
         }
     }
 
   return ovl ();
 }
 
-DEFUN (more, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (more, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} more
 @deftypefnx {} {} more on
 @deftypefnx {} {} more off
@@ -618,19 +593,21 @@
   if (nargin > 1)
     print_usage ();
 
+  octave::output_system& output_sys = interp.get_output_system ();
+
   if (nargin > 0)
     {
       std::string arg = args(0).xstring_value (R"(more: argument must be string "on" or "off")");
 
       if (arg == "on")
-        Vpage_screen_output = true;
+        output_sys.page_screen_output (true);
       else if (arg == "off")
-        Vpage_screen_output = false;
+        output_sys.page_screen_output (false);
       else
         error (R"(more: argument must be "on" or "off")");
     }
   else
-    Vpage_screen_output = ! Vpage_screen_output;
+    output_sys.page_screen_output (! output_sys.page_screen_output ());
 
   return ovl ();
 }
@@ -651,8 +628,8 @@
   return ovl (size);
 }
 
-DEFUN (page_output_immediately, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (page_output_immediately, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} page_output_immediately ()
 @deftypefnx {} {@var{old_val} =} page_output_immediately (@var{new_val})
 @deftypefnx {} {} page_output_immediately (@var{new_val}, "local")
@@ -668,11 +645,13 @@
 @seealso{page_screen_output, more, PAGER, PAGER_FLAGS}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (page_output_immediately);
+  octave::output_system& output_sys = interp.get_output_system ();
+
+  return output_sys.page_output_immediately (args, nargout);
 }
 
-DEFUN (page_screen_output, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (page_screen_output, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} page_screen_output ()
 @deftypefnx {} {@var{old_val} =} page_screen_output (@var{new_val})
 @deftypefnx {} {} page_screen_output (@var{new_val}, "local")
@@ -690,11 +669,13 @@
 @seealso{more, page_output_immediately, PAGER, PAGER_FLAGS}
 @end deftypefn */)
 {
-  return SET_INTERNAL_VARIABLE (page_screen_output);
+  octave::output_system& output_sys = interp.get_output_system ();
+
+  return output_sys.page_screen_output (args, nargout);
 }
 
-DEFUN (PAGER, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PAGER, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PAGER ()
 @deftypefnx {} {@var{old_val} =} PAGER (@var{new_val})
 @deftypefnx {} {} PAGER (@var{new_val}, "local")
@@ -711,11 +692,13 @@
 @seealso{PAGER_FLAGS, page_output_immediately, more, page_screen_output}
 @end deftypefn */)
 {
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (PAGER);
+  octave::output_system& output_sys = interp.get_output_system ();
+
+  return output_sys.PAGER (args, nargout);
 }
 
-DEFUN (PAGER_FLAGS, args, nargout,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (PAGER_FLAGS, interp, args, nargout,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} PAGER_FLAGS ()
 @deftypefnx {} {@var{old_val} =} PAGER_FLAGS (@var{new_val})
 @deftypefnx {} {} PAGER_FLAGS (@var{new_val}, "local")
@@ -728,5 +711,7 @@
 @seealso{PAGER, more, page_screen_output, page_output_immediately}
 @end deftypefn */)
 {
-  return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (PAGER_FLAGS);
+  octave::output_system& output_sys = interp.get_output_system ();
+
+  return output_sys.PAGER_FLAGS (args, nargout);
 }
--- a/libinterp/corefcn/pager.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/pager.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,14 +25,18 @@
 
 #include "octave-config.h"
 
+#include <fstream>
 #include <iosfwd>
 #include <sstream>
 #include <string>
 
-#include <sys/types.h>
+class octave_value;
+class oprocstream;
 
 namespace octave
 {
+  class interpreter;
+
   class
   OCTINTERP_API
   pager_buf : public std::stringbuf
@@ -58,12 +62,10 @@
   OCTINTERP_API
   pager_stream : public std::ostream
   {
-  protected:
+  public:
 
     pager_stream (void);
 
-  public:
-
     // No copying!
 
     pager_stream (const pager_stream&) = delete;
@@ -72,28 +74,16 @@
 
     ~pager_stream (void);
 
-    static void flush_current_contents_to_diary (void);
+    void flush_current_contents_to_diary (void);
 
-    static void set_diary_skip (void);
+    void set_diary_skip (void);
 
-    static std::ostream& stream (void);
+    std::ostream& stream (void);
 
-    static void reset (void);
+    void reset (void);
 
   private:
 
-    void do_flush_current_contents_to_diary (void);
-
-    void do_set_diary_skip (void);
-
-    void do_reset (void);
-
-    static pager_stream *instance;
-
-    static bool instance_ok (void);
-
-    static void cleanup_instance (void) { delete instance; instance = nullptr; }
-
     pager_buf *pb;
   };
 
@@ -114,12 +104,10 @@
   OCTINTERP_API
   diary_stream : public std::ostream
   {
-  protected:
+  public:
 
     diary_stream (void);
 
-  public:
-
     // No copying!
 
     diary_stream (const diary_stream&) = delete;
@@ -128,24 +116,194 @@
 
     ~diary_stream (void);
 
-    static std::ostream& stream (void);
+    std::ostream& stream (void);
 
-    static void reset (void);
+    void reset (void);
 
   private:
 
-    void do_reset (void);
-
-    static diary_stream *instance;
-
-    static bool instance_ok (void);
-
-    static void cleanup_instance (void) { delete instance; instance = nullptr; }
-
     diary_buf *db;
   };
 
   extern OCTAVE_API void flush_stdout (void);
+
+  class output_system
+  {
+  public:
+
+    output_system (interpreter& interp);
+
+    output_system (const output_system&) = delete;
+
+    output_system& operator = (const output_system&) = delete;
+
+    ~output_system (void) = default;
+
+    pager_stream& pager (void) { return m_pager_stream; }
+
+    diary_stream& diary (void) { return m_diary_stream; }
+
+    std::string diary_file_name (void) const { return m_diary_file_name; }
+
+    std::string diary_file_name (const std::string& nm)
+    {
+      std::string val = m_diary_file_name;
+      m_diary_file_name = nm.empty () ? "diary" : nm;
+      return val;
+    }
+
+    octave_value PAGER (const octave_value_list& args, int nargout);
+
+    std::string PAGER (void) const { return m_PAGER; }
+
+    std::string PAGER (const std::string& s)
+    {
+      std::string val = m_PAGER;
+      m_PAGER = s;
+      return val;
+    }
+
+    octave_value PAGER_FLAGS (const octave_value_list& args, int nargout);
+
+    std::string PAGER_FLAGS (void) const { return m_PAGER_FLAGS; }
+
+    std::string PAGER_FLAGS (const std::string& s)
+    {
+      std::string val = m_PAGER_FLAGS;
+      m_PAGER_FLAGS = s;
+      return val;
+    }
+
+    octave_value page_output_immediately (const octave_value_list& args,
+                                          int nargout);
+
+    bool page_output_immediately (void) const
+    {
+      return m_page_output_immediately;
+    }
+
+    bool page_output_immediately (bool flag)
+    {
+      bool val = m_page_output_immediately;
+      m_page_output_immediately = flag;
+      return val;
+    }
+
+    octave_value page_screen_output (const octave_value_list& args,
+                                     int nargout);
+
+    bool page_screen_output (void) const { return m_page_screen_output; }
+
+    bool page_screen_output (bool flag)
+    {
+      bool val = m_page_screen_output;
+      m_page_screen_output = flag;
+      return val;
+    }
+
+    bool write_to_diary_file (void) const
+    {
+      return m_write_to_diary_file;
+    }
+
+    bool write_to_diary_file (bool flag)
+    {
+      bool val = m_write_to_diary_file;
+      m_write_to_diary_file = flag;
+      return val;
+    }
+
+    bool really_flush_to_pager (void) const
+    {
+      return m_really_flush_to_pager;
+    }
+
+    bool really_flush_to_pager (bool flag)
+    {
+      bool val = m_really_flush_to_pager;
+      m_really_flush_to_pager = flag;
+      return val;
+    }
+
+    bool flushing_output_to_pager (void) const
+    {
+      return m_flushing_output_to_pager;
+    }
+
+    bool flushing_output_to_pager (bool flag)
+    {
+      bool val = m_flushing_output_to_pager;
+      m_flushing_output_to_pager = flag;
+      return val;
+    }
+
+    std::string pager_command (void) const;
+
+    std::ofstream& external_diary_file (void) { return m_external_diary_file; }
+
+    void reset (void);
+
+    void flush_stdout (void);
+
+    bool sync (const char *msg, int len);
+
+    void clear_external_pager (void);
+
+    void open_diary (void);
+
+    void close_diary (void);
+
+    std::ostream& __stdout__ (void) { return m_pager_stream.stream (); }
+
+    std::ostream& __diary__ (void) { return m_diary_stream.stream (); }
+
+  private:
+
+    interpreter& m_interpreter;
+
+    pager_stream m_pager_stream;
+
+    diary_stream m_diary_stream;
+
+    // Our actual connection to the external pager.
+    oprocstream *m_external_pager = nullptr;
+
+    // The diary file.
+    std::ofstream m_external_diary_file;
+
+    // The name of the current diary file.
+    std::string m_diary_file_name;
+
+    // The shell command to run as the pager.
+    std::string m_PAGER;
+
+    // The options to pass to the pager.
+    std::string m_PAGER_FLAGS;
+
+    // TRUE means that if output is going to the pager, it is sent as soon
+    // as it is available.  Otherwise, it is buffered and only sent to the
+    // pager when it is time to print another prompt.
+    bool m_page_output_immediately;
+
+    // TRUE means all output intended for the screen should be passed
+    // through the pager.
+    bool m_page_screen_output;
+
+    // TRUE means we write to the diary file.
+    bool m_write_to_diary_file;
+
+    bool m_really_flush_to_pager;
+
+    bool m_flushing_output_to_pager;
+
+    void start_external_pager (void);
+
+    void do_sync (const char *msg, int len, bool bypass_pager);
+  };
+
+  extern std::ostream& __stdout__ (void);
+
+  extern std::ostream& __diary__ (void);
 }
 
 #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
@@ -171,8 +329,8 @@
 
 #endif
 
-#define octave_stdout (octave::pager_stream::stream ())
+#define octave_stdout (octave::__stdout__ ())
 
-#define octave_diary (octave::diary_stream::stream ())
+#define octave_diary (octave::__diary__ ())
 
 #endif
--- a/libinterp/corefcn/pr-output.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/pr-output.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,6 @@
 #include <cmath>
 
 #include <iomanip>
-#include <iostream>
 #include <limits>
 #include <list>
 #include <sstream>
@@ -41,6 +40,7 @@
 #include "lo-mappers.h"
 #include "mach-info.h"
 #include "oct-cmplx.h"
+#include "oct-string.h"
 #include "quit.h"
 
 #include "Cell.h"
@@ -236,115 +236,6 @@
 }
 
 template <typename T>
-static inline std::string
-rational_approx (T val, int len)
-{
-  std::string s;
-
-  if (len <= 0)
-    len = 10;
-
-  if (octave::math::isinf (val))
-    s = "1/0";
-  else if (octave::math::isnan (val))
-    s = "0/0";
-  else if (val < std::numeric_limits<int>::min ()
-           || val > std::numeric_limits<int>::max ()
-           || octave::math::x_nint (val) == val)
-    {
-      std::ostringstream buf;
-      buf.flags (std::ios::fixed);
-      buf << std::setprecision (0) << octave::math::round (val);
-      s = buf.str ();
-    }
-  else
-    {
-      T lastn = 1;
-      T lastd = 0;
-      T n = octave::math::round (val);
-      T d = 1;
-      T frac = val - n;
-      int m = 0;
-
-      std::ostringstream buf2;
-      buf2.flags (std::ios::fixed);
-      buf2 << std::setprecision (0) << static_cast<int> (n);
-      s = buf2.str ();
-
-      while (true)
-        {
-          T flip = 1 / frac;
-          T step = octave::math::round (flip);
-          T nextn = n;
-          T nextd = d;
-
-          // Have we converged to 1/intmax ?
-          if (std::abs (flip) > static_cast<T> (std::numeric_limits<int>::max ()))
-            {
-              lastn = n;
-              lastd = d;
-              break;
-            }
-
-          frac = flip - step;
-          n = step * n + lastn;
-          d = step * d + lastd;
-          lastn = nextn;
-          lastd = nextd;
-
-          std::ostringstream buf;
-          buf.flags (std::ios::fixed);
-          buf << std::setprecision (0) << static_cast<int> (n)
-              << '/' << static_cast<int> (d);
-          m++;
-
-          if (n < 0 && d < 0)
-            {
-              // Double negative, string can be two characters longer..
-              if (buf.str ().length () > static_cast<unsigned int> (len + 2))
-                break;
-            }
-          else if (buf.str ().length () > static_cast<unsigned int> (len))
-            break;
-
-          if (std::abs (n) > std::numeric_limits<int>::max ()
-              || std::abs (d) > std::numeric_limits<int>::max ())
-            break;
-
-          s = buf.str ();
-        }
-
-      if (lastd < 0)
-        {
-          // Move sign to the top
-          lastd = - lastd;
-          lastn = - lastn;
-          std::ostringstream buf;
-          buf.flags (std::ios::fixed);
-          buf << std::setprecision (0) << static_cast<int> (lastn)
-              << '/' << static_cast<int> (lastd);
-          s = buf.str ();
-        }
-    }
-
-  return s;
-}
-
-/*
-%!assert (rats (2.0005, 9), "4001/2000")
-%!assert (rats (-2.0005, 10), "-4001/2000")
-%!assert (strtrim (rats (2.0005, 30)), "4001/2000")
-%!assert (pi - str2num (rats (pi, 30)), 0, 4 * eps)
-%!assert (e - str2num (rats (e, 30)), 0, 4 * eps)
-%!assert (rats (123, 2), " *")
-
-%!test
-%! v = 1 / double (intmax);
-%! err = v - str2num (rats(v, 12));
-%! assert (err, 0, 4 * eps);
-*/
-
-template <typename T>
 std::ostream&
 operator << (std::ostream& os, const pr_rational_float<T>& prf)
 {
@@ -2664,7 +2555,7 @@
 
               if (pr_as_read_syntax)
                 {
-                  os << '"' << undo_string_escapes (row) << '"';
+                  os << '"' << octave::undo_string_escapes (row) << '"';
 
                   if (i < nstr - 1)
                     os << "; ";
@@ -3286,6 +3177,20 @@
   return ovl (string_vector (lst));
 }
 
+/*
+%!assert (rats (2.0005, 9), "4001/2000")
+%!assert (rats (-2.0005, 10), "-4001/2000")
+%!assert (strtrim (rats (2.0005, 30)), "4001/2000")
+%!assert (pi - str2num (rats (pi, 30)), 0, 4 * eps)
+%!assert (e - str2num (rats (e, 30)), 0, 4 * eps)
+%!assert (rats (123, 2), " *")
+
+%!test
+%! v = 1 / double (intmax);
+%! err = v - str2num (rats(v, 12));
+%! assert (err, 0, 4 * eps);
+*/
+
 DEFUN (disp, args, nargout,
        classes: cell char double function_handle int8 int16 int32 int64 logical single struct uint8 uint16 uint32 uint64
        doc: /* -*- texinfo -*-
@@ -3482,7 +3387,7 @@
   // disp is done.
 
   bool print_newlines = false;
-  if (valid_identifier (name))
+  if (octave::valid_identifier (name))
     print_newlines = value.print_name_tag (octave_stdout, name);
 
   // Use feval so that dispatch will also work for disp.
@@ -4020,6 +3925,7 @@
 
 @example
 @group
+fixed_point_format (true)
 logspace (1, 7, 5)'
 ans =
 
--- a/libinterp/corefcn/procstream.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/procstream.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <iomanip>
 
 #include "procstream.h"
 
--- a/libinterp/corefcn/procstream.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/procstream.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,7 @@
 
 #include "octave-config.h"
 
-#include <istream>
-#include <ostream>
+#include <iosfwd>
 #include <string>
 
 #include <sys/types.h>
--- a/libinterp/corefcn/quad.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/quad.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,9 +26,6 @@
 
 #include <string>
 
-#include <iomanip>
-#include <iostream>
-
 #include "Quad.h"
 #include "lo-mappers.h"
 
--- a/libinterp/corefcn/qz.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/qz.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,11 +36,8 @@
 #include <cctype>
 #include <cmath>
 
-#if defined (DEBUG) || defined (DEBUG_SORT) || defined (DEBUG_EIG)
-#  include <iostream>
-#  if defined (DEBUG_EIG)
-#    include <iomanip>
-#  endif
+#if defined (DEBUG_EIG)
+#  include <iomanip>
 #endif
 
 #include "f77-fcn.h"
@@ -53,6 +50,7 @@
 #include "errwarn.h"
 #include "ovl.h"
 #if defined (DEBUG) || defined (DEBUG_SORT)
+#  include "pager.h"
 #  include "pr-output.h"
 #endif
 
@@ -164,14 +162,14 @@
 (@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}.
-@seealso{eig, balance, lu, chol, hess, qr, qzhess, schur, svd}
+@seealso{eig, ordeig, balance, lu, chol, hess, qr, qzhess, schur, svd}
 @end deftypefn */)
 {
   int nargin = args.length ();
 
 #if defined (DEBUG)
-  std::cout << "qz: nargin = " << nargin
-            << ", nargout = " << nargout << std::endl;
+  octave_stdout << "qz: nargin = " << nargin
+                << ", nargout = " << nargout << std::endl;
 #endif
 
   if (nargin < 2 || nargin > 3 || nargout > 7)
@@ -181,7 +179,7 @@
     error ("qz: invalid number of output arguments for form 3 call");
 
 #if defined (DEBUG)
-  std::cout << "qz: determine ordering option" << std::endl;
+  octave_stdout << "qz: determine ordering option" << std::endl;
 #endif
 
   // Determine ordering option.
@@ -209,9 +207,9 @@
                                    F77_CHAR_ARG_LEN (1));
 
 #if defined (DEBUG_EIG)
-      std::cout << "qz: initial value of safmin="
-                << setiosflags (std::ios::scientific)
-                << safmin << std::endl;
+      octave_stdout << "qz: initial value of safmin="
+                    << setiosflags (std::ios::scientific)
+                    << safmin << std::endl;
 #endif
 
       // Some machines (e.g., DEC alpha) get safmin = 0;
@@ -219,7 +217,8 @@
       if (safmin == 0)
         {
 #if defined (DEBUG_EIG)
-          std::cout << "qz: DANGER WILL ROBINSON: safmin is 0!" << std::endl;
+          octave_stdout << "qz: DANGER WILL ROBINSON: safmin is 0!"
+                        << std::endl;
 #endif
 
           F77_FUNC (xdlamch, XDLAMCH) (F77_CONST_CHAR_ARG2 ("E", 1),
@@ -227,15 +226,15 @@
                                        F77_CHAR_ARG_LEN (1));
 
 #if defined (DEBUG_EIG)
-          std::cout << "qz: safmin set to "
-                    << setiosflags (std::ios::scientific)
-                    << safmin << std::endl;
+          octave_stdout << "qz: safmin set to "
+                        << setiosflags (std::ios::scientific)
+                        << safmin << std::endl;
 #endif
         }
     }
 
 #if defined (DEBUG)
-  std::cout << "qz: check matrix A" << std::endl;
+  octave_stdout << "qz: check matrix A" << std::endl;
 #endif
 
   // Matrix A: check dimensions.
@@ -243,7 +242,8 @@
   F77_INT nc = octave::to_f77_int (args(0).columns ());
 
 #if defined (DEBUG)
-  std::cout << "Matrix A dimensions: (" << nn << ',' << nc << ')' << std::endl;
+  octave_stdout << "Matrix A dimensions: (" << nn << ',' << nc << ')'
+                << std::endl;
 #endif
 
   if (args(0).isempty ())
@@ -264,7 +264,7 @@
     aa = args(0).matrix_value ();
 
 #if defined (DEBUG)
-  std::cout << "qz: check matrix B" << std::endl;
+  octave_stdout << "qz: check matrix B" << std::endl;
 #endif
 
   // Extract argument 2 (bb, or cbb if complex).
@@ -322,8 +322,7 @@
     {
 #if defined (DEBUG)
       if (comp_q == 'V')
-        std::cout << "qz: performing balancing; CQ=" << std::endl
-                  << CQ << std::endl;
+        octave_stdout << "qz: performing balancing; CQ =\n" << CQ << std::endl;
 #endif
       if (args(0).isreal ())
         caa = ComplexMatrix (aa);
@@ -349,8 +348,7 @@
     {
 #if defined (DEBUG)
       if (comp_q == 'V')
-        std::cout << "qz: performing balancing; QQ=" << std::endl
-                  << QQ << std::endl;
+        octave_stdout << "qz: performing balancing; QQ =\n" << QQ << std::endl;
 #endif
 
       F77_XFCN (dggbal, DGGBAL,
@@ -379,7 +377,7 @@
 
 #if defined (DEBUG)
       if (comp_q == 'V')
-        std::cout << "qz: balancing done; QQ=" << std::endl << QQ << std::endl;
+        octave_stdout << "qz: balancing done; QQ =\n" << QQ << std::endl;
 #endif
     }
 
@@ -396,7 +394,7 @@
 
 #if defined (DEBUG)
       if (comp_z == 'V')
-        std::cout << "qz: balancing done; ZZ=" << std::endl << ZZ << std::endl;
+        octave_stdout << "qz: balancing done; ZZ=\n" << ZZ << std::endl;
 #endif
     }
 #endif
@@ -472,43 +470,43 @@
   else
     {
 #if defined (DEBUG)
-      std::cout << "qz: performing qr decomposition of bb" << std::endl;
+      octave_stdout << "qz: performing qr decomposition of bb" << std::endl;
 #endif
 
       // Compute the QR factorization of bb.
       octave::math::qr<Matrix> bqr (bb);
 
 #if defined (DEBUG)
-      std::cout << "qz: qr (bb) done; now performing qz decomposition"
-                << std::endl;
+      octave_stdout << "qz: qr (bb) done; now performing qz decomposition"
+                    << std::endl;
 #endif
 
       bb = bqr.R ();
 
 #if defined (DEBUG)
-      std::cout << "qz: extracted bb" << std::endl;
+      octave_stdout << "qz: extracted bb" << std::endl;
 #endif
 
       aa = (bqr.Q ()).transpose () * aa;
 
 #if defined (DEBUG)
-      std::cout << "qz: updated aa " << std::endl;
-      std::cout << "bqr.Q () = " << std::endl << bqr.Q () << std::endl;
+      octave_stdout << "qz: updated aa " << std::endl;
+      octave_stdout << "bqr.Q () =\n" << bqr.Q () << std::endl;
 
       if (comp_q == 'V')
-        std::cout << "QQ =" << QQ << std::endl;
+        octave_stdout << "QQ =" << QQ << std::endl;
 #endif
 
       if (comp_q == 'V')
         QQ = QQ * bqr.Q ();
 
 #if defined (DEBUG)
-      std::cout << "qz: precursors done..." << std::endl;
+      octave_stdout << "qz: precursors done..." << std::endl;
 #endif
 
 #if defined (DEBUG)
-      std::cout << "qz: comp_q = " << comp_q << ", comp_z = " << comp_z
-                << std::endl;
+      octave_stdout << "qz: comp_q = " << comp_q << ", comp_z = " << comp_z
+                    << std::endl;
 #endif
 
       // Reduce to generalized Hessenberg form.
@@ -549,8 +547,7 @@
 
 #if defined (DEBUG)
           if (comp_q == 'V')
-            std::cout << "qz: balancing done; QQ=" << std::endl
-                      << QQ << std::endl;
+            octave_stdout << "qz: balancing done; QQ=\n" << QQ << std::endl;
 #endif
         }
 
@@ -567,8 +564,7 @@
 
 #if defined (DEBUG)
           if (comp_z == 'V')
-            std::cout << "qz: balancing done; ZZ=" << std::endl
-                      << ZZ << std::endl;
+            octave_stdout << "qz: balancing done; ZZ=\n" << ZZ << std::endl;
 #endif
         }
 
@@ -582,8 +578,8 @@
         error ("qz: cannot re-order complex QZ decomposition");
 
 #if defined (DEBUG_SORT)
-      std::cout << "qz: ordering eigenvalues: ord_job = "
-                << ord_job << std::endl;
+      octave_stdout << "qz: ordering eigenvalues: ord_job = "
+                    << ord_job << std::endl;
 #endif
 
       Array<F77_LOGICAL> select (dim_vector (nn, 1));
@@ -640,24 +636,23 @@
                  info));
 
 #if defined (DEBUG_SORT)
-      std::cout << "qz: back from dtgsen: aa=" << std::endl;
-      octave_print_internal (std::cout, aa, 0);
-      std::cout << std::endl << "bb="  << std::endl;
-      octave_print_internal (std::cout, bb, 0);
-
+      octave_stdout << "qz: back from dtgsen: aa =\n";
+      octave_print_internal (octave_stdout, aa);
+      octave_stdout << "\nbb =\n";
+      octave_print_internal (octave_stdout, bb);
       if (comp_z == 'V')
         {
-          std::cout << std::endl << "ZZ="  << std::endl;
-          octave_print_internal (std::cout, ZZ, 0);
+          octave_stdout << "\nZZ =\n";
+          octave_print_internal (octave_stdout, ZZ);
         }
-      std::cout << std::endl << "qz: info=" << info << std::endl;
-      std::cout << "alphar = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) alphar, 0);
-      std::cout << std::endl << "alphai = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) alphai, 0);
-      std::cout << std::endl << "beta = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) betar, 0);
-      std::cout << std::endl;
+      octave_stdout << "\nqz: info=" << info;
+      octave_stdout << "\nalphar =\n";
+      octave_print_internal (octave_stdout, Matrix (alphar));
+      octave_stdout << "\nalphai =\n";
+      octave_print_internal (octave_stdout, Matrix (alphai));
+      octave_stdout << "\nbeta =\n";
+      octave_print_internal (octave_stdout, Matrix (betar));
+      octave_stdout << std::endl;
 #endif
     }
 
@@ -678,7 +673,7 @@
       else
         {
 #if defined (DEBUG)
-          std::cout << "qz: computing generalized eigenvalues" << std::endl;
+          octave_stdout << "qz: computing generalized eigenvalues" << std::endl;
 #endif
 
           // Return finite generalized eigenvalues.
@@ -728,7 +723,7 @@
       else
         {
 #if defined (DEBUG)
-          std::cout << "qz: computing generalized eigenvectors" << std::endl;
+          octave_stdout << "qz: computing generalized eigenvectors" << std::endl;
 #endif
 
           VL = QQ;
@@ -818,9 +813,9 @@
       if (nargin == 3)
         {
 #if defined (DEBUG)
-          std::cout << "qz: sort: retval(3) = gev = " << std::endl;
-          octave_print_internal (std::cout, ComplexMatrix (gev));
-          std::cout << std::endl;
+          octave_stdout << "qz: sort: retval(3) = gev =\n";
+          octave_print_internal (octave_stdout, ComplexMatrix (gev));
+          octave_stdout << std::endl;
 #endif
           retval(3) = gev;
         }
@@ -855,11 +850,11 @@
         if (complex_case)
           {
 #if defined (DEBUG)
-            std::cout << "qz: retval(1) = cbb = " << std::endl;
-            octave_print_internal (std::cout, cbb, 0);
-            std::cout << std::endl << "qz: retval(0) = caa = " <<std::endl;
-            octave_print_internal (std::cout, caa, 0);
-            std::cout << std::endl;
+            octave_stdout << "qz: retval(1) = cbb =\n";
+            octave_print_internal (octave_stdout, cbb);
+            octave_stdout << "\nqz: retval(0) = caa =\n";
+            octave_print_internal (octave_stdout, caa);
+            octave_stdout << std::endl;
 #endif
             retval(1) = cbb;
             retval(0) = caa;
@@ -867,11 +862,11 @@
         else
           {
 #if defined (DEBUG)
-            std::cout << "qz: retval(1) = bb = " << std::endl;
-            octave_print_internal (std::cout, bb, 0);
-            std::cout << std::endl << "qz: retval(0) = aa = " <<std::endl;
-            octave_print_internal (std::cout, aa, 0);
-            std::cout << std::endl;
+            octave_stdout << "qz: retval(1) = bb =\n";
+            octave_print_internal (octave_stdout, bb);
+            octave_stdout << "\nqz: retval(0) = aa =\n";
+            octave_print_internal (octave_stdout, aa);
+            octave_stdout << std::endl;
 #endif
             retval(1) = bb;
             retval(0) = aa;
@@ -882,7 +877,7 @@
     case 1:
     case 0:
 #if defined (DEBUG)
-      std::cout << "qz: retval(0) = gev = " << gev << std::endl;
+      octave_stdout << "qz: retval(0) = gev = " << gev << std::endl;
 #endif
       retval(0) = gev;
       break;
@@ -893,7 +888,7 @@
     }
 
 #if defined (DEBUG)
-  std::cout << "qz: exiting (at long last)" << std::endl;
+  octave_stdout << "qz: exiting (at long last)" << std::endl;
 #endif
 
   return retval;
--- a/libinterp/corefcn/rand.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/rand.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -118,10 +118,10 @@
 
   octave::unwind_protect frame;
   // Restore current distribution on any exit.
-  frame.add_fcn (octave_rand::distribution,
-                 octave_rand::distribution ());
+  frame.add_fcn (octave::rand::distribution,
+                 octave::rand::distribution ());
 
-  octave_rand::distribution (distribution);
+  octave::rand::distribution (distribution);
 
   switch (nargin)
     {
@@ -150,21 +150,21 @@
             std::string s_arg = tmp.string_value ();
 
             if (s_arg == "dist")
-              retval = octave_rand::distribution ();
+              retval = octave::rand::distribution ();
             else if (s_arg == "seed")
-              retval = octave_rand::seed ();
+              retval = octave::rand::seed ();
             else if (s_arg == "state" || s_arg == "twister")
-              retval = octave_rand::state (fcn);
+              retval = octave::rand::state (fcn);
             else if (s_arg == "uniform")
-              octave_rand::uniform_distribution ();
+              octave::rand::uniform_distribution ();
             else if (s_arg == "normal")
-              octave_rand::normal_distribution ();
+              octave::rand::normal_distribution ();
             else if (s_arg == "exponential")
-              octave_rand::exponential_distribution ();
+              octave::rand::exponential_distribution ();
             else if (s_arg == "poisson")
-              octave_rand::poisson_distribution ();
+              octave::rand::poisson_distribution ();
             else if (s_arg == "gamma")
-              octave_rand::gamma_distribution ();
+              octave::rand::gamma_distribution ();
             else
               error ("%s: unrecognized string argument", fcn);
           }
@@ -207,11 +207,11 @@
           }
         else if (tmp.is_matrix_type ())
           {
-            Array<int> iv;
+            Array<octave_idx_type> iv;
 
             try
               {
-                iv = tmp.int_vector_value (true);
+                iv = tmp.octave_idx_type_vector_value (true);
               }
             catch (octave::execution_exception& e)
               {
@@ -250,11 +250,11 @@
                   {
                     double d = args(idx+1).double_value ();
 
-                    octave_rand::seed (d);
+                    octave::rand::seed (d);
                   }
                 else if (args(idx+1).is_string ()
                          && args(idx+1).string_value () == "reset")
-                  octave_rand::reset ();
+                  octave::rand::reset ();
                 else
                   error ("%s: seed must be a real scalar", fcn);
               }
@@ -262,7 +262,7 @@
               {
                 if (args(idx+1).is_string ()
                     && args(idx+1).string_value () == "reset")
-                  octave_rand::reset (fcn);
+                  octave::rand::reset (fcn);
                 else
                   {
                     ColumnVector s =
@@ -274,7 +274,7 @@
                       if (octave::math::isinf (s.xelem (i)))
                         s.xelem (i) = 0.0;
 
-                    octave_rand::state (s, fcn);
+                    octave::rand::state (s, fcn);
                   }
               }
             else
@@ -286,10 +286,7 @@
 
             for (int i = 0; i < nargin; i++)
               {
-                octave_idx_type elt =
-                  args(idx+i).xidx_type_value (
-                    "%s: dimension must be a scalar or array of integers",
-                    fcn);
+                octave_idx_type elt = args(idx+i).idx_type_value (true);
 
                 // Negative dimensions treated as zero for Matlab compatibility
                 dims(i) = (elt >= 0 ? elt : 0);
@@ -313,7 +310,7 @@
       if (additional_arg)
         {
           if (a.numel () == 1)
-            return octave_rand::float_nd_array (dims, a(0));
+            return octave::rand::float_nd_array (dims, a(0));
           else
             {
               if (a.dims () != dims)
@@ -324,20 +321,20 @@
               float *v = m.fortran_vec ();
 
               for (octave_idx_type i = 0; i < len; i++)
-                v[i] = octave_rand::float_scalar (a(i));
+                v[i] = octave::rand::float_scalar (a(i));
 
               return m;
             }
         }
       else
-        return octave_rand::float_nd_array (dims);
+        return octave::rand::float_nd_array (dims);
     }
   else
     {
       if (additional_arg)
         {
           if (a.numel () == 1)
-            return octave_rand::nd_array (dims, a(0));
+            return octave::rand::nd_array (dims, a(0));
           else
             {
               if (a.dims () != dims)
@@ -348,13 +345,13 @@
               double *v = m.fortran_vec ();
 
               for (octave_idx_type i = 0; i < len; i++)
-                v[i] = octave_rand::scalar (a(i));
+                v[i] = octave::rand::scalar (a(i));
 
               return m;
             }
         }
       else
-        return octave_rand::nd_array (dims);
+        return octave::rand::nd_array (dims);
     }
 }
 
@@ -538,7 +535,16 @@
 %!assert (__rand_sample__ (NaN), __rand_sample__ (0))
 */
 
-static std::string current_distribution = octave_rand::distribution ();
+/*
+## Check that negative dimensions are treated as zero for Matlab compatibility
+%!assert (size (rand (1, -1, 2)), [1, 0, 2])
+
+## Test input validation
+%!error <conversion of 1.1 to.* failed> rand (1, 1.1)
+%!error <dimensions must be .* array of integers> rand ([1, 1.1])
+*/
+
+static std::string current_distribution = octave::rand::distribution ();
 
 DEFUN (randn, args, ,
        doc: /* -*- texinfo -*-
@@ -1131,7 +1137,7 @@
   bool short_shuffle = m < n/5;
 
   // Generate random numbers.
-  NDArray r = octave_rand::nd_array (dim_vector (1, m));
+  NDArray r = octave::rand::nd_array (dim_vector (1, m));
   double *rvec = r.fortran_vec ();
 
   octave_idx_type idx_len = (short_shuffle ? m : n);
--- a/libinterp/corefcn/regexp.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/regexp.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -374,7 +374,7 @@
   bool extra_options = false;
   parse_options (options, args, who, 2, extra_options);
 
-  octave::regexp::match_data rx_lst
+  const octave::regexp::match_data rx_lst
     = octave::regexp::match (pattern, buffer, options, who);
 
   string_vector named_pats = rx_lst.named_patterns ();
@@ -408,7 +408,7 @@
 
   if (options.once ())
     {
-      octave::regexp::match_data::const_iterator p = rx_lst.begin ();
+      auto p = rx_lst.begin ();
 
       retval(4) = (sz ? p->tokens () : Cell ());
       retval(3) = (sz ? p->match_string () : "");
--- a/libinterp/corefcn/schur.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/schur.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -122,7 +122,7 @@
 The Schur@tie{}decomposition is used to compute eigenvalues of a square
 matrix, and has applications in the solution of algebraic @nospell{Riccati}
 equations in control (see @code{are} and @code{dare}).
-@seealso{rsf2csf, ordschur, lu, chol, hess, qr, qz, svd}
+@seealso{rsf2csf, ordschur, ordeig, lu, chol, hess, qr, qz, svd}
 @end deftypefn */)
 {
   int nargin = args.length ();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/settings.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,93 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+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 "interpreter.h"
+#include "ov.h"
+#include "ovl.h"
+#include "settings.h"
+#include "variables.h"
+
+namespace octave
+{
+  settings::settings (void)
+    : m_display_tokens (false), m_token_count (0),
+      m_lexer_debug_flag (false)
+  { }
+
+  octave_value settings::display_tokens (const octave_value_list& args,
+                                         int nargout)
+  {
+    return set_internal_variable (m_display_tokens, args, nargout,
+                                  "__display_tokens__");
+  }
+
+  octave_value settings::lexer_debug_flag (const octave_value_list& args,
+                                           int nargout)
+  {
+    return set_internal_variable (m_lexer_debug_flag, args, nargout,
+                                  "__lexer_debug_flag__");
+  }
+}
+
+DEFMETHOD (__display_tokens__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __display_tokens__ ()
+Query or set the internal variable that determines whether Octave's
+lexer displays tokens as they are read.
+@seealso{__lexer_debug_flag__, __token_count__}
+@end deftypefn */)
+{
+  octave::settings& stgs = interp.get_settings ();
+
+  return stgs.display_tokens (args, nargout);
+}
+
+DEFMETHOD (__token_count__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __token_count__ ()
+Return the number of language tokens processed since Octave startup.
+@seealso{__lexer_debug_flag__, __display_tokens__}
+@end deftypefn */)
+{
+  octave::settings& stgs = interp.get_settings ();
+
+  return octave_value (stgs.token_count ());
+}
+
+DEFMETHOD (__lexer_debug_flag__, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{val} =} __lexer_debug_flag__ ()
+@deftypefnx {} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val})
+Query or set the internal flag that determines whether Octave's lexer prints
+debug information as it processes an expression.
+@seealso{__display_tokens__, __token_count__, __parse_debug_flag__}
+@end deftypefn */)
+{
+  octave::settings& stgs = interp.get_settings ();
+
+  return stgs.lexer_debug_flag (args, nargout);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/settings.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,90 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+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_settings_h)
+#define octave_settings_h 1
+
+#include "octave-config.h"
+
+class octave_value_list;
+
+namespace octave
+{
+  // Most settings for the interpreter are stored in the classes which
+  // they affect (intput_system, output_system, load_path, etc.  Some
+  // don't really fit anywhere else.  For example, there is no single
+  // lexer or parser object, so we store settings for those things
+  // here.
+
+  class settings
+  {
+  public:
+
+    settings (void);
+
+    settings (const settings&) = delete;
+
+    settings& operator = (const settings&) = delete;
+
+    ~settings (void) = default;
+
+    octave_value display_tokens (const octave_value_list& args, int nargout);
+
+    bool display_tokens (void) const { return m_display_tokens; }
+
+    bool display_tokens (bool flag)
+    {
+      bool val = m_display_tokens;
+      m_display_tokens = flag;
+      return val;
+    }
+
+    // Read only.
+    size_t token_count (void) const { return m_token_count; }
+
+    void increment_token_count (void) { ++m_token_count; }
+
+    octave_value lexer_debug_flag (const octave_value_list& args, int nargout);
+
+    bool lexer_debug_flag (void) const { return m_lexer_debug_flag; }
+
+    bool lexer_debug_flag (bool flag)
+    {
+      bool val = m_lexer_debug_flag;
+      m_lexer_debug_flag = flag;
+      return val;
+    }
+
+  private:
+
+    // Display tokens as they are processed, for debugging.
+    bool m_display_tokens = false;
+
+    // Number of tokens processed since interpreter startup.
+    size_t m_token_count = 0;
+
+    // Internal variable for lexer debugging state.
+    bool m_lexer_debug_flag = false;
+  };
+}
+
+#endif
--- a/libinterp/corefcn/sighandlers.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sighandlers.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,6 @@
 #include "quit.h"
 #include "signal-wrappers.h"
 
-#include "bp-table.h"
 #include "defun.h"
 #include "error.h"
 #include "input.h"
@@ -51,8 +50,6 @@
 #include "octave.h"
 #include "oct-map.h"
 #include "pager.h"
-#include "pt-bp.h"
-#include "pt-eval.h"
 #include "sighandlers.h"
 #include "sysdep.h"
 #include "utils.h"
@@ -186,8 +183,7 @@
     static const bool have_sigusr2
       = octave_get_sig_number ("SIGUSR2", &sigusr2);
 
-    octave::child_list& kids
-      = octave::__get_child_list__ ("respond_to_pending_signals");
+    child_list& kids = __get_child_list__ ("respond_to_pending_signals");
 
     for (int sig = 0; sig < octave_num_signals (); sig++)
       {
--- a/libinterp/corefcn/sighandlers.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sighandlers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -80,60 +80,4 @@
   extern OCTINTERP_API bool Vdebug_on_interrupt;
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::interrupt_handler' instead")
-typedef octave::interrupt_handler octave_interrupt_handler;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sig_handler' instead")
-typedef octave::sig_handler octave_sig_handler;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::pipe_handler_error_count' instead")
-static auto& pipe_handler_error_count = octave::pipe_handler_error_count;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::can_interrupt' instead")
-static auto& can_interrupt = octave::can_interrupt;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::set_signal_handler' instead")
-inline octave::sig_handler *
-octave_set_signal_handler (int sig, octave::sig_handler *handler,
-                           bool restart_syscalls = true)
-{
-  return octave::set_signal_handler (sig, handler, restart_syscalls);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::set_signal_handler' instead")
-inline octave::sig_handler *
-octave_set_signal_handler (const char *signame, octave::sig_handler *handler,
-                           bool restart_syscalls = true)
-{
-  return octave::set_signal_handler (signame, handler, restart_syscalls);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::set_signal_handler' instead")
-const auto install_signal_handlers = octave::install_signal_handlers;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::respond_to_pending_signals' instead")
-const auto octave_signal_handler = octave::respond_to_pending_signals;
-
-namespace octave
-{
-  OCTAVE_DEPRECATED (4.4, "use 'octave::respond_to_pending_signals' instead")
-  const auto signal_handler = respond_to_pending_signals;
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::interrupt_handler' instead")
-const auto octave_catch_interrupts = octave::catch_interrupts;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::ignore_interrupts' instead")
-const auto octave_ignore_interrupts = octave::ignore_interrupts;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::set_interrupt_handler' instead")
-const auto octave_set_interrupt_handler = octave::set_interrupt_handler;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::Vdebug_on_interrupt' instead")
-static auto& Vdebug_on_interrupt = octave::Vdebug_on_interrupt;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -54,6 +54,27 @@
   return ovl (args(0).issparse ());
 }
 
+/*
+%!assert (issparse (sparse (1)), true)
+%!assert (issparse (1), false)
+%!assert (issparse (sparse (false)), true)
+%!assert (issparse (true), false)
+%!assert (issparse (sparse (single ([1 2]))), true)
+%!assert (issparse (single ([1, 2])), false)
+%!assert (issparse (sparse ([1+i, 2]')), true)
+%!assert (issparse ([1+i, 2]'), false)
+
+%!assert (issparse ([]), false)
+%!assert (issparse (sparse([])), true)
+%!assert (issparse ("test"), false)
+%!assert (issparse (struct ("one", {1})), false)
+%!assert (issparse (cell (1)), false)
+
+## Test input validation
+%!error issparse ()
+%!error issparse (1,2)
+*/
+
 DEFUN (sparse, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{s} =} sparse (@var{a})
@@ -151,12 +172,12 @@
       octave_idx_type m = 0;
       octave_idx_type n = 0;
 
-      get_dimensions (args(0), args(1), "sparse", m, n);
+      octave::get_dimensions (args(0), args(1), "sparse", m, n);
 
-      if (m >= 0 && n >= 0)
-        retval = SparseMatrix (m, n);
-      else
+      if (m < 0 || n < 0)
         error ("sparse: dimensions must be non-negative");
+
+      retval = SparseMatrix (m, n);
     }
   else if (nargin >= 3)
     {
@@ -184,7 +205,7 @@
 
       if (nargin == 5)
         {
-          get_dimensions (args(3), args(4), "sparse", m, n);
+          octave::get_dimensions (args(3), args(4), "sparse", m, n);
 
           if (m < 0 || n < 0)
             error ("sparse: dimensions must be non-negative");
@@ -220,6 +241,11 @@
   return retval;
 }
 
+/*
+## Tests for sparse constructor are in test/sparse.tst
+%!assert (1);
+*/
+
 DEFUN (spalloc, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{s} =} spalloc (@var{m}, @var{n}, @var{nz})
@@ -270,8 +296,28 @@
   if (nargin == 3)
     nz = args(2).idx_type_value ();
 
-  if (m >= 0 && n >= 0 && nz >= 0)
-    return ovl (SparseMatrix (dim_vector (m, n), nz));
-  else
-    error ("spalloc: M,N,NZ must be non-negative");
+  if (m < 0 || n < 0 || nz < 0)
+    error ("spalloc: M, N, and NZ must be non-negative");
+
+  return ovl (SparseMatrix (dim_vector (m, n), nz));
 }
+
+/*
+%!assert (issparse (spalloc (1,1)))
+%!assert (spalloc (1,1), sparse (1,1))
+%!test
+%! s = spalloc (1,1,5);
+%! assert (s, sparse (1,1));
+%! assert (nzmax (s), 5);
+%!assert (spalloc (1,2), sparse (1,2))
+%!assert (spalloc (1,2,2), sparse (1,2))
+%!assert (spalloc (2,1), sparse (2,1))
+%!assert (spalloc (2,1,2), sparse (2,1))
+
+%!error spalloc ()
+%!error spalloc (1)
+%!error spalloc (1,2,3,4)
+%!error <M, N, and NZ must be non-negative> spalloc (-1, 1, 1)
+%!error <M, N, and NZ must be non-negative> spalloc (1, -1, 1)
+%!error <M, N, and NZ must be non-negative> spalloc (1, 1, -1)
+*/
--- a/libinterp/corefcn/str2double.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,426 +0,0 @@
-/*
-
-Copyright (C) 2010-2018 Jaroslav Hajek
-Copyright (C) 2010 VZLU Prague
-
-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 <string>
-#include <cctype>
-#include <sstream>
-#include <algorithm>
-
-#include "lo-ieee.h"
-
-#include "Cell.h"
-#include "ov.h"
-#include "defun.h"
-#include "errwarn.h"
-#include "utils.h"
-
-static inline bool
-is_imag_unit (int c)
-{ return c == 'i' || c == 'j'; }
-
-static double
-single_num (std::istringstream& is)
-{
-  double num = 0.0;
-
-  char c = is.peek ();
-
-  // Skip spaces.
-  while (isspace (c))
-    {
-      is.get ();
-      c = is.peek ();
-    }
-
-  if (std::toupper (c) == 'I')
-    {
-      // It's infinity.
-      is.get ();
-      char c1 = is.get ();
-      char c2 = is.get ();
-      if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f')
-        {
-          num = octave::numeric_limits<double>::Inf ();
-          is.peek (); // May set EOF bit.
-        }
-      else
-        is.setstate (std::ios::failbit); // indicate that read has failed.
-    }
-  else if (c == 'N')
-    {
-      // It's NA or NaN
-      is.get ();
-      char c1 = is.get ();
-      if (c1 == 'A')
-        {
-          num = octave_NA;
-          is.peek (); // May set EOF bit.
-        }
-      else
-        {
-          char c2 = is.get ();
-          if (c1 == 'a' && c2 == 'N')
-            {
-              num = octave::numeric_limits<double>::NaN ();
-              is.peek (); // May set EOF bit.
-            }
-          else
-            is.setstate (std::ios::failbit); // indicate that read has failed.
-        }
-    }
-  else
-    is >> num;
-
-  return num;
-}
-
-static std::istringstream&
-extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign)
-{
-  have_sign = imag = false;
-
-  char c = is.peek ();
-
-  // Skip leading spaces.
-  while (isspace (c))
-    {
-      is.get ();
-      c = is.peek ();
-    }
-
-  bool negative = false;
-
-  // Accept leading sign.
-  if (c == '+' || c == '-')
-    {
-      have_sign = true;
-      negative = c == '-';
-      is.get ();
-      c = is.peek ();
-    }
-
-  // Skip spaces after sign.
-  while (isspace (c))
-    {
-      is.get ();
-      c = is.peek ();
-    }
-
-  // Imaginary number (i*num or just i), or maybe 'inf'.
-  if (c == 'i')
-    {
-      // possible infinity.
-      is.get ();
-      c = is.peek ();
-
-      if (is.eof ())
-        {
-          // just 'i' and string is finished.  Return immediately.
-          imag = true;
-          num = (negative ? -1.0 : 1.0);
-          return is;
-        }
-      else
-        {
-          if (std::tolower (c) != 'n')
-            imag = true;
-          is.unget ();
-        }
-    }
-  else if (c == 'j')
-    imag = true;
-
-  // It's i*num or just i
-  if (imag)
-    {
-      is.get ();
-      c = is.peek ();
-      // Skip spaces after imaginary unit.
-      while (isspace (c))
-        {
-          is.get ();
-          c = is.peek ();
-        }
-
-      if (c == '*')
-        {
-          // Multiplier follows, we extract it as a number.
-          is.get ();
-          num = single_num (is);
-          if (is.good ())
-            c = is.peek ();
-        }
-      else
-        num = 1.0;
-    }
-  else
-    {
-      // It's num, num*i, or numi.
-      num = single_num (is);
-      if (is.good ())
-        {
-          c = is.peek ();
-
-          // Skip spaces after number.
-          while (isspace (c))
-            {
-              is.get ();
-              c = is.peek ();
-            }
-
-          if (c == '*')
-            {
-              is.get ();
-              c = is.peek ();
-
-              // Skip spaces after operator.
-              while (isspace (c))
-                {
-                  is.get ();
-                  c = is.peek ();
-                }
-
-              if (is_imag_unit (c))
-                {
-                  imag = true;
-                  is.get ();
-                  c = is.peek ();
-                }
-              else
-                is.setstate (std::ios::failbit); // indicate read has failed.
-            }
-          else if (is_imag_unit (c))
-            {
-              imag = true;
-              is.get ();
-              c = is.peek ();
-            }
-        }
-    }
-
-  if (is.good ())
-    {
-      // Skip trailing spaces.
-      while (isspace (c))
-        {
-          is.get ();
-          c = is.peek ();
-        }
-    }
-
-  if (negative)
-    num = -num;
-
-  return is;
-}
-
-static inline void
-set_component (Complex& c, double num, bool imag)
-{
-#if defined (HAVE_CXX_COMPLEX_SETTERS)
-  if (imag)
-    c.imag (num);
-  else
-    c.real (num);
-#elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
-  if (imag)
-    c.imag () = num;
-  else
-    c.real () = num;
-#else
-  if (imag)
-    c = Complex (c.real (), num);
-  else
-    c = Complex (num, c.imag ());
-#endif
-}
-
-static Complex
-str2double1 (const std::string& str_arg)
-{
-  Complex val (0.0, 0.0);
-
-  std::string str = str_arg;
-
-  // FIXME: removing all commas doesn't allow actual parsing.
-  //        Example: "1,23.45" is wrong, but passes Octave.
-  str.erase (std::remove (str.begin (), str.end(), ','), str.end ());
-  std::istringstream is (str);
-
-  double num;
-  bool i1, i2, s1, s2;
-
-  if (is.eof ())
-    val = octave::numeric_limits<double>::NaN ();
-  else if (! extract_num (is, num, i1, s1))
-    val = octave::numeric_limits<double>::NaN ();
-  else
-    {
-      set_component (val, num, i1);
-
-      if (! is.eof ())
-        {
-          if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
-            val = octave::numeric_limits<double>::NaN ();
-          else
-            set_component (val, num, i2);
-        }
-    }
-
-  return val;
-}
-
-DEFUN (str2double, args, ,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} str2double (@var{s})
-Convert a string to a real or complex number.
-
-The string must be in one of the following formats where a and b are real
-numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:
-
-@itemize
-@item a + bi
-
-@item a + b*i
-
-@item a + i*b
-
-@item bi + a
-
-@item b*i + a
-
-@item i*b + a
-@end itemize
-
-If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where
-the brackets indicate optional arguments and @qcode{'d'} indicates zero or
-more digits.  The special input values @code{Inf}, @code{NaN}, and @code{NA}
-are also accepted.
-
-@var{s} may be a character string, character matrix, or cell array.  For
-character arrays the conversion is repeated for every row, and a double or
-complex array is returned.  Empty rows in @var{s} are deleted and not
-returned in the numeric array.  For cell arrays each character string
-element is processed and a double or complex array of the same dimensions as
-@var{s} is returned.
-
-For unconvertible scalar or character string input @code{str2double} returns
-a NaN@.  Similarly, for character array input @code{str2double} returns a
-NaN for any row of @var{s} that could not be converted.  For a cell array,
-@code{str2double} returns a NaN for any element of @var{s} for which
-conversion fails.  Note that numeric elements in a mixed string/numeric
-cell array are not strings and the conversion will fail for these elements
-and return NaN.
-
-@code{str2double} can replace @code{str2num}, and it avoids the security
-risk of using @code{eval} on unknown data.
-@seealso{str2num}
-@end deftypefn */)
-{
-  if (args.length () != 1)
-    print_usage ();
-
-  octave_value retval;
-
-  if (args(0).is_string ())
-    {
-      if (args(0).rows () == 0 || args(0).columns () == 0)
-        retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
-      else if (args(0).rows () == 1 && args(0).ndims () == 2)
-        retval = str2double1 (args(0).string_value ());
-      else
-        {
-          const string_vector sv = args(0).string_vector_value ();
-
-          retval = sv.map<Complex> (str2double1);
-        }
-    }
-  else if (args(0).iscell ())
-    {
-      const Cell cell = args(0).cell_value ();
-
-      ComplexNDArray output (cell.dims (), octave::numeric_limits<double>::NaN ());
-
-      for (octave_idx_type i = 0; i < cell.numel (); i++)
-        {
-          if (cell(i).is_string ())
-            output(i) = str2double1 (cell(i).string_value ());
-        }
-      retval = output;
-    }
-  else
-    retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
-
-  return retval;
-}
-
-/*
-%!assert (str2double ("1"), 1)
-%!assert (str2double ("-.1e-5"), -1e-6)
-%!testif ; ! ismac ()
-%! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
-%!xtest <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]);
-%!assert (str2double ("1,222.5"), 1222.5)
-%!assert (str2double ("i"), i)
-%!assert (str2double ("2j"), 2i)
-%!assert (str2double ("2 + j"), 2+j)
-%!assert (str2double ("i*2 + 3"), 3+2i)
-%!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
-%!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
-%!assert (str2double (char ("2 + j","1.25e-3","-05")), [2+i; 1.25e-3; -5])
-%!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
-%!assert (str2double (1), NaN)
-%!assert (str2double ("1 2 3 4"), NaN)
-%!assert (str2double ("Hello World"), NaN)
-%!assert (str2double ("NaN"), NaN)
-%!assert (str2double ("NA"), NA)
-%!assert (str2double ("Inf"), Inf)
-%!assert (str2double ("iNF"), Inf)
-%!assert (str2double ("-Inf"), -Inf)
-%!assert (str2double ("Inf*i"), complex (0, Inf))
-%!assert (str2double ("iNF*i"), complex (0, Inf))
-%!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
-%!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
-%!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
-%!testif ; ! ismac ()
-%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
-%!xtest <47413>
-%! if (! ismac ()), return; endif
-%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
-%!testif ; ! ismac ()
-%! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
-%!xtest <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)
-*/
--- a/libinterp/corefcn/strfind.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/strfind.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -186,7 +186,7 @@
         @}
 @end group
 @end example
-@seealso{findstr, strmatch, regexp, regexpi, find}
+@seealso{regexp, regexpi, find}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -255,7 +255,7 @@
         error ("strfind: first argument must be a string or cell array of strings");
     }
   else if (argpat.iscell ())
-    retval = do_simple_cellfun (Fstrfind, "strfind", args);
+    retval = octave::do_simple_cellfun (Fstrfind, "strfind", args);
   else
     error ("strfind: PATTERN must be a string or cell array of strings");
 
@@ -372,7 +372,7 @@
 @end group
 @end example
 
-@seealso{regexprep, strfind, findstr}
+@seealso{regexprep, strfind}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -433,7 +433,7 @@
         error ("strrep: S must be a string or cell array of strings");
     }
   else if (argpat.iscell () || argrep.iscell ())
-    retval = do_simple_cellfun (Fstrrep, "strrep", args);
+    retval = octave::do_simple_cellfun (Fstrrep, "strrep", args);
   else
     error ("strrep: PTN and REP arguments must be strings or cell arrays of strings");
 
--- a/libinterp/corefcn/strfns.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/strfns.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -32,6 +32,7 @@
 #include "dMatrix.h"
 #include "localcharset-wrapper.h"
 #include "uniconv-wrappers.h"
+#include "unistr-wrappers.h"
 
 #include "Cell.h"
 #include "defun.h"
@@ -657,11 +658,13 @@
 %!assert (strncmp ("abce", "aBc", 3), false)
 %!assert (strncmp (100, 100, 1), false)
 %!assert (strncmp ("abce", {"abcd", "bca", "abc"}, 3), logical ([1, 0, 1]))
-%!assert (strncmp ("abc",  {"abcd", "bca", "abc"}, 4), logical ([0, 0, 0]))
+%!assert (strncmp ("abc",  {"abcd", "bca", "abc"}, 4), logical ([0, 0, 1]))
 %!assert (strncmp ({"abcd", "bca", "abc"},"abce", 3), logical ([1, 0, 1]))
 %!assert (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3), logical ([1, 1, 0]))
 %!assert (strncmp ("abc", {"abcd", 10}, 2), logical ([1, 0]))
 
+%!assert <*54373> (strncmp ("abc", "abc", 100))
+
 %!error strncmp ()
 %!error strncmp ("abc", "def")
 */
@@ -732,6 +735,139 @@
 
 /*
 %!assert (strncmpi ("abc123", "ABC456", 3), true)
+
+%!assert <*54373> (strncmpi ("abc", "abC", 100))
+*/
+
+DEFUN (str2double, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} str2double (@var{s})
+Convert a string to a real or complex number.
+
+The string must be in one of the following formats where a and b are real
+numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:
+
+@itemize
+@item a + bi
+
+@item a + b*i
+
+@item a + i*b
+
+@item bi + a
+
+@item b*i + a
+
+@item i*b + a
+@end itemize
+
+If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where
+the brackets indicate optional arguments and @qcode{'d'} indicates zero or
+more digits.  The special input values @code{Inf}, @code{NaN}, and @code{NA}
+are also accepted.
+
+@var{s} may be a character string, character matrix, or cell array.  For
+character arrays the conversion is repeated for every row, and a double or
+complex array is returned.  Empty rows in @var{s} are deleted and not
+returned in the numeric array.  For cell arrays each character string
+element is processed and a double or complex array of the same dimensions as
+@var{s} is returned.
+
+For unconvertible scalar or character string input @code{str2double} returns
+a NaN@.  Similarly, for character array input @code{str2double} returns a
+NaN for any row of @var{s} that could not be converted.  For a cell array,
+@code{str2double} returns a NaN for any element of @var{s} for which
+conversion fails.  Note that numeric elements in a mixed string/numeric
+cell array are not strings and the conversion will fail for these elements
+and return NaN.
+
+@code{str2double} can replace @code{str2num}, and it avoids the security
+risk of using @code{eval} on unknown data.
+@seealso{str2num}
+@end deftypefn */)
+{
+  if (args.length () != 1)
+    print_usage ();
+
+  octave_value retval;
+
+  if (args(0).is_string ())
+    {
+      if (args(0).rows () == 0 || args(0).columns () == 0)
+        retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
+      else if (args(0).rows () == 1 && args(0).ndims () == 2)
+        retval = octave::string::str2double (args(0).string_value ());
+      else
+        {
+          const string_vector sv = args(0).string_vector_value ();
+
+          retval = sv.map<Complex> (octave::string::str2double);
+        }
+    }
+  else if (args(0).iscell ())
+    {
+      const Cell cell = args(0).cell_value ();
+
+      ComplexNDArray output (cell.dims (), octave::numeric_limits<double>::NaN ());
+
+      for (octave_idx_type i = 0; i < cell.numel (); i++)
+        {
+          if (cell(i).is_string ())
+            output(i) = octave::string::str2double (cell(i).string_value ());
+        }
+      retval = output;
+    }
+  else
+    retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
+
+  return retval;
+}
+
+/*
+%!assert (str2double ("1"), 1)
+%!assert (str2double ("-.1e-5"), -1e-6)
+%!testif ; ! ismac ()
+%! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
+%!xtest <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]);
+%!assert (str2double ("1,222.5"), 1222.5)
+%!assert (str2double ("i"), i)
+%!assert (str2double ("2j"), 2i)
+%!assert (str2double ("2 + j"), 2+j)
+%!assert (str2double ("i*2 + 3"), 3+2i)
+%!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
+%!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
+%!assert (str2double (char ("2 + j","1.25e-3","-05")), [2+i; 1.25e-3; -5])
+%!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
+%!assert (str2double (1), NaN)
+%!assert (str2double ("1 2 3 4"), NaN)
+%!assert (str2double ("Hello World"), NaN)
+%!assert (str2double ("NaN"), NaN)
+%!assert (str2double ("NA"), NA)
+%!assert (str2double ("Inf"), Inf)
+%!assert (str2double ("iNF"), Inf)
+%!assert (str2double ("-Inf"), -Inf)
+%!assert (str2double ("Inf*i"), complex (0, Inf))
+%!assert (str2double ("iNF*i"), complex (0, Inf))
+%!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
+%!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
+%!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
+%!testif ; ! ismac ()
+%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
+%!xtest <47413>
+%! if (! ismac ()), return; endif
+%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
+%!testif ; ! ismac ()
+%! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
+%!xtest <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)
 */
 
 DEFUN (__native2unicode__, args, ,
@@ -840,6 +976,60 @@
   return ovl (retval);
 }
 
+DEFUN (unicode_idx, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {@var{idx} =} unicode_idx (@var{str})
+Return an array with the indices for each UTF-8 encoded character in @var{str}.
+
+@example
+@group
+unicode_idx ("aäbc")
+     @result{} [1, 2, 2, 3, 4]
+@end group
+@end example
+
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin != 1)
+    print_usage ();
+
+  charNDArray str = args(0).xchar_array_value ("STR must be a string");
+  Array<octave_idx_type> p (dim_vector (str.ndims (), 1));
+  charNDArray str_p;
+  if (str.ndims () > 1)
+  {
+    for (octave_idx_type i=0; i < str.ndims (); i++)
+      p(i) = i;
+    p(0) = 1;
+    p(1) = 0;
+    str_p = str.permute (p);
+  }
+
+  const uint8_t *src = reinterpret_cast<const uint8_t *> (str_p.data ());
+  octave_idx_type srclen = str.numel ();
+
+  NDArray idx (str_p.dims ());
+
+  octave_idx_type u8_char_num = 1;
+  for (octave_idx_type i = 0; i < srclen; u8_char_num++)
+  {
+    int mblen = octave_u8_strmblen_wrapper (src + i);
+    if (mblen < 1)
+      mblen = 1;
+    for (octave_idx_type j = 0; j < mblen; j++)
+      idx (i+j) = u8_char_num;
+    i += mblen;
+  }
+
+  return ovl(str.ndims () > 1 ? idx.permute (p, true) : idx);
+}
+
+/*
+%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6]);
+*/
+
 DEFUN (list_in_columns, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} list_in_columns (@var{arg}, @var{width}, @var{prefix})
--- a/libinterp/corefcn/sub2ind.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sub2ind.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -131,7 +131,7 @@
           e.set_pos_if_unset (nargin-1, j+1);
           e.set_var ();
           std::string msg = e.message ();
-          error_with_id (e.err_id (), msg.c_str ());
+          error_with_id (e.err_id (), "%s", msg.c_str ());
         }
     }
 
--- a/libinterp/corefcn/svd.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/svd.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -168,7 +168,7 @@
 {
   int nargin = args.length ();
 
-  if (nargin < 1 || nargin > 2 || nargout == 2 || nargout > 3)
+  if (nargin < 1 || nargin > 2 || nargout > 3)
     print_usage ();
 
   octave_value arg = args(0);
@@ -198,6 +198,9 @@
 
           if (nargout == 0 || nargout == 1)
             retval(0) = sigma.extract_diag ();
+          else if (nargout == 2)
+            retval = ovl (result.left_singular_matrix (),
+                          sigma);
           else
             retval = ovl (result.left_singular_matrix (),
                           sigma,
@@ -219,6 +222,9 @@
 
           if (nargout == 0 || nargout == 1)
             retval(0) = sigma.extract_diag ();
+          else if (nargout == 2)
+            retval = ovl (result.left_singular_matrix (),
+                          sigma);
           else
             retval = ovl (result.left_singular_matrix (),
                           sigma,
@@ -243,6 +249,9 @@
 
           if (nargout == 0 || nargout == 1)
             retval(0) = sigma.extract_diag ();
+          else if (nargout == 2)
+            retval = ovl (result.left_singular_matrix (),
+                          sigma);
           else
             retval = ovl (result.left_singular_matrix (),
                           sigma,
@@ -264,6 +273,9 @@
 
           if (nargout == 0 || nargout == 1)
             retval(0) = sigma.extract_diag ();
+          else if (nargout == 2)
+            retval = ovl (result.left_singular_matrix (),
+                          sigma);
           else
             retval = ovl (result.left_singular_matrix (),
                           sigma,
@@ -280,9 +292,9 @@
 %!assert (svd ([1, 2; 2, 1]), [3; 1], sqrt (eps))
 
 %!test
-a = [1, 2; 3, 4] + [5, 6; 7, 8]*i;
-[u,s,v] = svd (a);
-assert (a, u * s * v', 128 * eps);
+%! a = [1, 2; 3, 4] + [5, 6; 7, 8]*i;
+%! [u,s,v] = svd (a);
+%! assert (a, u * s * v', 128 * eps);
 
 %!test
 %! [u, s, v] = svd ([1, 2; 2, 1]);
@@ -362,7 +374,6 @@
 
 %!error svd ()
 %!error svd ([1, 2; 4, 5], 2, 3)
-%!error [u, v] = svd ([1, 2; 3, 4])
 */
 
 DEFUN (svd_driver, args, nargout,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/syminfo.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,573 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+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 <iomanip>
+#include <list>
+#include <ostream>
+#include <sstream>
+
+#include "Cell.h"
+#include "octave-preserve-stream-state.h"
+#include "ov.h"
+#include "oct-map.h"
+#include "pager.h"
+#include "syminfo.h"
+
+namespace octave
+{
+  void
+  symbol_info::display_line (std::ostream& os,
+                             const std::list<whos_parameter>& params) const
+  {
+    std::string dims_str = m_value.get_dims_str ();
+
+    auto i = params.begin ();
+
+    octave::preserve_stream_state stream_state (os);
+
+    while (i != params.end ())
+      {
+        whos_parameter param = *i;
+
+        if (param.command != '\0')
+          {
+            // Do the actual printing.
+
+            switch (param.modifier)
+              {
+              case 'l':
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                break;
+
+              case 'r':
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+                break;
+
+              case 'c':
+                if (param.command == 's')
+                  {
+                    int front = param.first_parameter_length
+                      - dims_str.find ('x');
+                    int back = param.parameter_length
+                      - dims_str.length ()
+                      - front;
+                    front = (front > 0) ? front : 0;
+                    back = (back > 0) ? back : 0;
+
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (front)
+                       << ""
+                       << std::resetiosflags (std::ios::left)
+                       << dims_str
+                       << std::setiosflags (std::ios::left)
+                       << std::setw (back)
+                       << ""
+                       << std::resetiosflags (std::ios::left);
+                  }
+                else
+                  {
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (param.parameter_length);
+                  }
+                break;
+
+              default:
+                error ("whos_line_format: modifier '%c' unknown",
+                       param.modifier);
+
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+              }
+
+            switch (param.command)
+              {
+              case 'a':
+                {
+                  char tmp[6];
+
+                  tmp[0] = (m_is_automatic ? 'a' : ' ');
+                  tmp[1] = (m_is_complex ? 'c' : ' ');
+                  tmp[2] = (m_is_formal ? 'f' : ' ');
+                  tmp[3] = (m_is_global ? 'g' : ' ');
+                  tmp[4] = (m_is_persistent ? 'p' : ' ');
+                  tmp[5] = 0;
+
+                  os << tmp;
+                }
+                break;
+
+              case 'b':
+                os << m_value.byte_size ();
+                break;
+
+              case 'c':
+                os << m_value.class_name ();
+                break;
+
+              case 'e':
+                os << m_value.numel ();
+                break;
+
+              case 'n':
+                os << m_name;
+                break;
+
+              case 's':
+                if (param.modifier != 'c')
+                  os << dims_str;
+                break;
+
+              case 't':
+                os << m_value.type_name ();
+                break;
+
+              default:
+                error ("whos_line_format: command '%c' unknown",
+                       param.command);
+              }
+
+            os << std::resetiosflags (std::ios::left)
+               << std::resetiosflags (std::ios::right);
+            i++;
+          }
+        else
+          {
+            os << param.text;
+            i++;
+          }
+      }
+  }
+
+  // FIXME: should we be using std::map<symbol_info> instead of a list?
+
+  octave_value symbol_info_list::varval (const std::string& name) const
+  {
+    for (const auto& syminfo : m_lst)
+      {
+        if (name == syminfo.name ())
+          return syminfo.value ();
+      }
+
+    return octave_value ();
+  }
+
+  octave_map
+  symbol_info_list::map_value (const std::string& caller_function_name,
+                               int nesting_level) const
+  {
+    size_t len = m_lst.size ();
+
+    Cell name_info (len, 1);
+    Cell size_info (len, 1);
+    Cell bytes_info (len, 1);
+    Cell class_info (len, 1);
+    Cell global_info (len, 1);
+    Cell sparse_info (len, 1);
+    Cell complex_info (len, 1);
+    Cell nesting_info (len, 1);
+    Cell persistent_info (len, 1);
+
+    size_t j = 0;
+
+    for (const auto& syminfo : m_lst)
+      {
+        octave_scalar_map ni;
+
+        ni.assign ("function", caller_function_name);
+        ni.assign ("level", nesting_level);
+
+        name_info(j) = syminfo.name ();
+        global_info(j) = syminfo.is_global ();
+        persistent_info(j) = syminfo.is_persistent ();
+
+        octave_value val = syminfo.value ();
+
+        size_info(j) = val.size ();
+        bytes_info(j) = val.byte_size ();
+        class_info(j) = val.class_name ();
+        sparse_info(j) = val.issparse ();
+        complex_info(j) = val.iscomplex ();
+        nesting_info(j) = ni;
+
+        j++;
+      }
+
+    octave_map info;
+
+    info.assign ("name", name_info);
+    info.assign ("size", size_info);
+    info.assign ("bytes", bytes_info);
+    info.assign ("class", class_info);
+    info.assign ("global", global_info);
+    info.assign ("sparse", sparse_info);
+    info.assign ("complex", complex_info);
+    info.assign ("nesting", nesting_info);
+    info.assign ("persistent", persistent_info);
+
+    return info;
+  }
+
+  void
+  symbol_info_list::print_descriptor (std::ostream& os,
+                                      const std::list<whos_parameter> params) const
+  {
+    std::ostringstream param_buf;
+
+    octave::preserve_stream_state stream_state (os);
+
+    for (const auto& param : params)
+      {
+        if (param.command != '\0')
+          {
+            // Do the actual printing
+            switch (param.modifier)
+              {
+              case 'l':
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::left)
+                          << std::setw (param.parameter_length);
+                break;
+
+              case 'r':
+                os << std::setiosflags (std::ios::right)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::right)
+                          << std::setw (param.parameter_length);
+                break;
+
+              case 'c':
+                if (param.command != 's')
+                  {
+                    os << std::setiosflags (std::ios::left)
+                       << std::setw (param.parameter_length);
+                    param_buf << std::setiosflags (std::ios::left)
+                              << std::setw (param.parameter_length);
+                  }
+                break;
+
+              default:
+                os << std::setiosflags (std::ios::left)
+                   << std::setw (param.parameter_length);
+                param_buf << std::setiosflags (std::ios::left)
+                          << std::setw (param.parameter_length);
+              }
+
+            if (param.command == 's' && param.modifier == 'c')
+              {
+                if (param.modifier == 'c')
+                  {
+                    int a = param.first_parameter_length - param.balance;
+                    a = (a < 0 ? 0 : a);
+                    int b = param.parameter_length - a - param.text.length ();
+                    b = (b < 0 ? 0 : b);
+                    os << std::setiosflags (std::ios::left) << std::setw (a)
+                       << "" << std::resetiosflags (std::ios::left) << param.text
+                       << std::setiosflags (std::ios::left)
+                       << std::setw (b) << ""
+                       << std::resetiosflags (std::ios::left);
+                    param_buf << std::setiosflags (std::ios::left)
+                              << std::setw (a)
+                              << "" << std::resetiosflags (std::ios::left)
+                              << param.line
+                              << std::setiosflags (std::ios::left)
+                              << std::setw (b) << ""
+                              << std::resetiosflags (std::ios::left);
+                  }
+              }
+            else
+              {
+                os << param.text;
+                param_buf << param.line;
+              }
+            os << std::resetiosflags (std::ios::left)
+               << std::resetiosflags (std::ios::right);
+            param_buf << std::resetiosflags (std::ios::left)
+                      << std::resetiosflags (std::ios::right);
+          }
+        else
+          {
+            os << param.text;
+            param_buf << param.line;
+          }
+      }
+
+    os << param_buf.str ();
+  }
+
+  void symbol_info_list::display (std::ostream& os, const std::string& format)
+  {
+    if (! m_lst.empty ())
+      {
+        size_t bytes = 0;
+        size_t elements = 0;
+
+        std::list<whos_parameter> params = parse_whos_line_format (format);
+
+        print_descriptor (os, params);
+
+        octave_stdout << "\n";
+
+        for (const auto& syminfo : m_lst)
+          {
+            syminfo.display_line (os, params);
+
+            octave_value val = syminfo.value ();
+
+            elements += val.numel ();
+            bytes += val.byte_size ();
+          }
+
+        os << "\nTotal is " << elements
+           << (elements == 1 ? " element" : " elements")
+           << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
+           << "\n";
+      }
+  }
+
+  std::list<whos_parameter>
+  symbol_info_list::parse_whos_line_format (const std::string& format)
+  {
+    int idx;
+    size_t format_len = format.length ();
+    char garbage;
+    std::list<whos_parameter> params;
+
+    size_t bytes1;
+    int elements1;
+
+    std::string param_string = "abcenst";
+    Array<int> param_length (dim_vector (param_string.length (), 1));
+    Array<std::string> param_names (dim_vector (param_string.length (), 1));
+    size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
+
+    pos_a = param_string.find ('a'); // Attributes
+    pos_b = param_string.find ('b'); // Bytes
+    pos_c = param_string.find ('c'); // Class
+    pos_e = param_string.find ('e'); // Elements
+    pos_n = param_string.find ('n'); // Name
+    pos_s = param_string.find ('s'); // Size
+    pos_t = param_string.find ('t'); // Type
+
+    param_names(pos_a) = "Attr";
+    param_names(pos_b) = "Bytes";
+    param_names(pos_c) = "Class";
+    param_names(pos_e) = "Elements";
+    param_names(pos_n) = "Name";
+    param_names(pos_s) = "Size";
+    param_names(pos_t) = "Type";
+
+    for (size_t i = 0; i < param_string.length (); i++)
+      param_length(i) = param_names(i).length ();
+
+    // The attribute column needs size 5.
+    param_length(pos_a) = 5;
+
+    // Calculating necessary spacing for name column,
+    // bytes column, elements column and class column
+
+    for (const auto& syminfo : m_lst)
+      {
+        std::stringstream ss1, ss2;
+        std::string str;
+
+        str = syminfo.name ();
+        param_length(pos_n) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_n)))
+                               ? str.length () : param_length(pos_n));
+
+        octave_value val = syminfo.value ();
+
+        str = val.type_name ();
+        param_length(pos_t) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_t)))
+                               ? str.length () : param_length(pos_t));
+
+        elements1 = val.numel ();
+        ss1 << elements1;
+        str = ss1.str ();
+        param_length(pos_e) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_e)))
+                               ? str.length () : param_length(pos_e));
+
+        bytes1 = val.byte_size ();
+        ss2 << bytes1;
+        str = ss2.str ();
+        param_length(pos_b) = ((str.length ()
+                                > static_cast<size_t> (param_length(pos_b)))
+                               ? str.length () : param_length (pos_b));
+      }
+
+    idx = 0;
+    while (static_cast<size_t> (idx) < format_len)
+      {
+        whos_parameter param;
+        param.command = '\0';
+
+        if (format[idx] == '%')
+          {
+            bool error_encountered = false;
+            param.modifier = 'r';
+            param.parameter_length = 0;
+
+            int a = 0;
+            int b = -1;
+            int balance = 1;
+            unsigned int items;
+            size_t pos;
+            std::string cmd;
+
+            // Parse one command from format
+            cmd = format.substr (idx, format.length ());
+            pos = cmd.find (';');
+            if (pos == std::string::npos)
+              error ("parameter without ; in format");
+
+            cmd = cmd.substr (0, pos+1);
+
+            idx += cmd.length ();
+
+            // FIXME: use iostream functions instead of sscanf!
+
+            if (cmd.find_first_of ("crl") != 1)
+              items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
+                              &garbage, &param.command, &a, &b, &balance);
+            else
+              items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
+                              &garbage, &param.modifier, &param.command,
+                              &a, &b, &balance) - 1;
+
+            if (items < 2)
+              error ("whos_line_format: found parameter structure without command");
+
+            // Exception case of bare class command 'c' without modifier 'l/r'
+            if (param.modifier == 'c'
+                && param_string.find (param.command) == std::string::npos)
+              {
+                param.modifier = 'r';
+                param.command = 'c';
+              }
+
+            // Insert data into parameter
+            param.first_parameter_length = 0;
+            pos = param_string.find (param.command);
+            if (pos == std::string::npos)
+              error ("whos_line_format: '%c' is not a command", param.command);
+
+            param.parameter_length = param_length(pos);
+            param.text = param_names(pos);
+            param.line.assign (param_names(pos).length (), '=');
+
+            param.parameter_length = (a > param.parameter_length
+                                      ? a : param.parameter_length);
+            if (param.command == 's' && param.modifier == 'c' && b > 0)
+              param.first_parameter_length = b;
+
+            if (param.command == 's')
+              {
+                // Have to calculate space needed for printing
+                // matrix dimensions Space needed for Size column is
+                // hard to determine in prior, because it depends on
+                // dimensions to be shown.  That is why it is
+                // recalculated for each Size-command int first,
+                // rest = 0, total;
+                int rest = 0;
+                int first = param.first_parameter_length;
+                int total = param.parameter_length;
+
+                for (const auto& syminfo : m_lst)
+                  {
+                    octave_value val = syminfo.value ();
+                    std::string dims_str = val.get_dims_str ();
+                    int first1 = dims_str.find ('x');
+                    int total1 = dims_str.length ();
+                    int rest1 = total1 - first1;
+                    rest = (rest1 > rest ? rest1 : rest);
+                    first = (first1 > first ? first1 : first);
+                    total = (total1 > total ? total1 : total);
+                  }
+
+                if (param.modifier == 'c')
+                  {
+                    if (first < balance)
+                      first += balance - first;
+                    if (rest + balance < param.parameter_length)
+                      rest += param.parameter_length - rest - balance;
+
+                    param.parameter_length = first + rest;
+                    param.first_parameter_length = first;
+                    param.balance = balance;
+                  }
+                else
+                  {
+                    param.parameter_length = total;
+                    param.first_parameter_length = 0;
+                  }
+              }
+            else if (param.modifier == 'c')
+              error ("whos_line_format: modifier 'c' not available for command '%c'",
+                     param.command);
+
+            // What happens if format contains negative numbers
+            // at param_length positions?
+            param.balance = (b < 0 ? 0 : param.balance);
+            param.first_parameter_length = (b < 0
+                                            ? 0
+                                            : param.first_parameter_length);
+            param.parameter_length = (a < 0
+                                      ? 0
+                                      : (param.parameter_length
+                                         < param_length(pos_s)
+                                         ? param_length(pos_s)
+                                         : param.parameter_length));
+
+            // Parameter will not be pushed into parameter list if ...
+            if (! error_encountered)
+              params.push_back (param);
+          }
+        else
+          {
+            // Text string, to be printed as it is ...
+            std::string text;
+            size_t pos;
+            text = format.substr (idx, format.length ());
+            pos = text.find ('%');
+            if (pos != std::string::npos)
+              text = text.substr (0, pos);
+
+            // Push parameter into list ...
+            idx += text.length ();
+            param.text=text;
+            param.line.assign (text.length (), ' ');
+            params.push_back (param);
+          }
+      }
+
+    return params;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/syminfo.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,120 @@
+/*
+
+Copyright (C) 2018 John W. Eaton
+
+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_syminfo_h)
+#define octave_syminfo_h 1
+
+#include "octave-config.h"
+
+#include <string>
+#include <iosfwd>
+
+#include "base-list.h"
+
+#include "ov.h"
+
+class octave_map;
+
+namespace octave
+{
+  struct whos_parameter
+  {
+    char command;
+    char modifier;
+    int parameter_length;
+    int first_parameter_length;
+    int balance;
+    std::string text;
+    std::string line;
+  };
+
+  class symbol_info
+  {
+  public:
+
+    symbol_info (const std::string& name, const octave_value& value,
+                 bool is_automatic, bool is_complex, bool is_formal,
+                 bool is_global, bool is_persistent)
+      : m_name (name), m_value (value), m_is_automatic (is_automatic),
+        m_is_complex (is_complex), m_is_formal (is_formal),
+        m_is_global (is_global), m_is_persistent (is_persistent)
+    { }
+
+    std::string name (void) const { return m_name; }
+
+    octave_value value (void) const { return m_value; }
+
+    bool is_automatic (void) const { return m_is_automatic; }
+
+    bool is_complex (void) const { return m_is_complex; }
+
+    bool is_formal (void) const { return m_is_formal; }
+
+    bool is_global (void) const { return m_is_global; }
+
+    bool is_persistent (void) const { return m_is_persistent; }
+
+    void display_line (std::ostream& os,
+                       const std::list<whos_parameter>& params) const;
+  private:
+
+    std::string m_name;
+    octave_value m_value;
+    bool m_is_automatic;
+    bool m_is_complex;
+    bool m_is_formal;
+    bool m_is_global;
+    bool m_is_persistent;
+  };
+
+  class symbol_info_list : public base_list<symbol_info>
+  {
+  public:
+
+    symbol_info_list (void) = default;
+
+    symbol_info_list (const symbol_info_list&) = default;
+
+    symbol_info_list& operator = (const symbol_info_list&) = default;
+
+    ~symbol_info_list (void) = default;
+
+    octave_value varval (const std::string& name) const;
+
+    octave_map map_value (const std::string& caller_function_name,
+                          int nesting_level) const;
+
+    // Print a line of information for a given symbol.
+    void print_descriptor (std::ostream& os,
+                           const std::list<whos_parameter> params) const;
+
+    void display (std::ostream& os, const std::string& format);
+
+    // Parse FORMAT, and return a parameter list,
+    // containing all information needed to print the given
+    // attributes of the symbols.
+    std::list<whos_parameter>
+    parse_whos_line_format (const std::string& format);
+  };
+}
+
+#endif
--- a/libinterp/corefcn/symscope.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/symscope.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -39,49 +39,57 @@
 
 namespace octave
 {
+  void symbol_scope_rep::install_auto_fcn_vars (void)
+  {
+    install_auto_fcn_var (".argn.");
+    install_auto_fcn_var (".ignored.");
+    install_auto_fcn_var (".nargin.");
+    install_auto_fcn_var (".nargout.");
+    install_auto_fcn_var (".saved_warning_states.");
+  }
+
+  void symbol_scope_rep::install_auto_fcn_var (const std::string& name)
+  {
+    insert (name, true);
+    mark_hidden (name);
+    mark_automatic (name);
+  }
+
   octave_value
-  symbol_scope_rep::find (const std::string& name,
-                          const octave_value_list& args,
-                          bool skip_variables, bool local_funcs)
+  symbol_scope_rep::find (const std::string& name)
   {
-    // Variable.
-
     symbol_table& symtab
       = __get_symbol_table__ ("symbol_scope_rep::find");
 
-    if (! skip_variables)
-      {
-        table_iterator p = m_symbols.find (name);
+    // Variable.
+
+    table_iterator p = m_symbols.find (name);
 
-        if (p != m_symbols.end ())
-          {
-            symbol_record sr = p->second;
+    if (p != m_symbols.end ())
+      {
+        symbol_record sr = p->second;
 
-            if (sr.is_global ())
-              return symtab.global_varval (name);
-            else
-              {
-                octave_value val = sr.varval (m_context);
+        if (sr.is_global ())
+          return symtab.global_varval (name);
+        else
+          {
+            octave_value val = sr.varval (m_context);
 
-                if (val.is_defined ())
-                  return val;
-              }
+            if (val.is_defined ())
+              return val;
           }
       }
 
-    if (local_funcs)
-      {
-        // Subfunction.  I think it only makes sense to check for
-        // subfunctions if we are currently executing a function defined
-        // from a .m file.
+    // Subfunction.  I think it only makes sense to check for
+    // subfunctions if we are currently executing a function defined
+    // from a .m file.
 
-        octave_value fcn = find_subfunction (name);
+    octave_value fcn = find_subfunction (name);
 
-        if (fcn.is_defined ())
-          return fcn;
-      }
+    if (fcn.is_defined ())
+      return fcn;
 
-    return symtab.fcn_table_find (name, args, local_funcs);
+    return symtab.fcn_table_find (name, ovl ());
   }
 
   symbol_record&
@@ -95,7 +103,7 @@
 
         auto t_parent = m_parent.lock ();
 
-        if (m_is_nested && t_parent && t_parent->look_nonlocal (name, ret))
+        if (is_nested () && t_parent && t_parent->look_nonlocal (name, ret))
           return m_symbols[name] = ret;
         else
           {
@@ -114,7 +122,10 @@
   {
     std::map<std::string, octave_value> m
       = {{ "name", m_name },
+         { "nesting_depth", m_nesting_depth },
+         { "is_static", m_is_static },
          { "symbols", dump_symbols_map () },
+         { "subfunction_names", string_vector (m_subfunction_names) },
          { "subfunctions", dump_function_map (m_subfunctions) }};
 
     return octave_value (m);
@@ -170,6 +181,39 @@
   }
 
   void
+  symbol_scope_rep::set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent)
+  {
+    m_primary_parent = std::weak_ptr<symbol_scope_rep> (parent);
+  }
+
+  bool
+  symbol_scope_rep::is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const
+  {
+    if (is_nested ())
+      {
+        // Since is_nested is true, the following should always return a
+        // valid scope.
+
+        auto t_primary_parent = m_primary_parent.lock ();
+
+        if (t_primary_parent)
+          {
+            // SCOPE is the primary parent of this scope: this scope is a
+            // child of SCOPE.
+            if (t_primary_parent == scope)
+              return true;
+
+            // SCOPE and this scope share the same primary parent: they are
+            // siblings.
+            if (t_primary_parent == scope->primary_parent_scope_rep ())
+              return true;
+          }
+      }
+
+    return false;
+  }
+
+  void
   symbol_scope_rep::update_nest (void)
   {
     auto t_parent = m_parent.lock ();
@@ -182,7 +226,7 @@
             symbol_record& ours = nm_sr.second;
 
             if (! ours.is_formal ()
-                && m_is_nested && t_parent->look_nonlocal (nm_sr.first, ours))
+                && is_nested () && t_parent->look_nonlocal (nm_sr.first, ours))
               {
                 if (ours.is_global () || ours.is_persistent ())
                   error ("global and persistent may only be used in the topmost level in which a nested variable is used");
@@ -190,7 +234,7 @@
           }
 
         // The scopes of nested functions are static.
-        if (m_is_nested)
+        if (is_nested ())
           m_is_static = true;
       }
     else if (m_children.size ())
@@ -212,7 +256,7 @@
       {
         auto t_parent = m_parent.lock ();
 
-        if (m_is_nested && t_parent)
+        if (is_nested () && t_parent)
           return t_parent->look_nonlocal (name, result);
       }
     else if (! p->second.is_automatic ())
--- a/libinterp/corefcn/symscope.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/symscope.h	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,6 @@
 #include "octave-config.h"
 
 #include <deque>
-#include <limits>
 #include <list>
 #include <map>
 #include <memory>
@@ -66,8 +65,8 @@
 
     symbol_scope_rep (const std::string& name = "")
       : m_name (name), m_symbols (), m_subfunctions (), m_fcn (nullptr),
-        m_parent (), m_children (), m_is_nested (false),
-        m_is_static (false), m_context (0)
+        m_parent (), m_primary_parent (), m_children (),
+        m_nesting_depth (0), m_is_static (false), m_context (0)
     { }
 
     // No copying!
@@ -83,9 +82,15 @@
       m_symbols[sr.name ()] = sr;
     }
 
-    bool is_nested (void) const { return m_is_nested; }
+    void install_auto_fcn_vars (void);
+
+    void install_auto_fcn_var (const std::string& name);
 
-    void mark_nested (void) { m_is_nested = true; }
+    bool is_nested (void) const { return m_nesting_depth > 0; }
+
+    size_t nesting_depth (void) const { return m_nesting_depth; }
+
+    void set_nesting_depth (size_t depth) { m_nesting_depth = depth; }
 
     bool is_static (void) const { return m_is_static; }
 
@@ -96,6 +101,11 @@
       return m_parent.lock ();
     }
 
+    std::shared_ptr<symbol_scope_rep> primary_parent_scope_rep (void) const
+    {
+      return m_primary_parent.lock ();
+    }
+
     std::shared_ptr<symbol_scope_rep> dup (void) const
     {
       std::shared_ptr<symbol_scope_rep> new_sid
@@ -105,6 +115,7 @@
         new_sid->insert_symbol_record (nm_sr.second.dup (new_sid));
 
       new_sid->m_parent = m_parent;
+      new_sid->m_primary_parent = m_primary_parent;
 
       return new_sid;
     }
@@ -121,7 +132,7 @@
 
     symbol_record find_symbol (const std::string& name)
     {
-      table_iterator p = m_symbols.find (name);
+      auto p = m_symbols.find (name);
 
       if (p == m_symbols.end ())
         return insert (name);
@@ -170,16 +181,14 @@
         }
     }
 
-    octave_value
-    find (const std::string& name, const octave_value_list& args,
-          bool skip_variables, bool local_funcs);
+    octave_value find (const std::string& name);
 
     symbol_record&
     insert (const std::string& name, bool force_add = false);
 
     void rename (const std::string& old_name, const std::string& new_name)
     {
-      table_iterator p = m_symbols.find (old_name);
+      auto p = m_symbols.find (old_name);
 
       if (p != m_symbols.end ())
         {
@@ -196,7 +205,7 @@
     void assign (const std::string& name, const octave_value& value,
                  bool force_add)
     {
-      table_iterator p = m_symbols.find (name);
+      auto p = m_symbols.find (name);
 
       if (p == m_symbols.end ())
         {
@@ -216,7 +225,7 @@
 
     void force_assign (const std::string& name, const octave_value& value)
     {
-      table_iterator p = m_symbols.find (name);
+      auto p = m_symbols.find (name);
 
       if (p == m_symbols.end ())
         {
@@ -260,7 +269,7 @@
 
     void pop_context (void)
     {
-      table_iterator tbl_it = m_symbols.begin ();
+      auto tbl_it = m_symbols.begin ();
 
       while (tbl_it != m_symbols.end ())
         {
@@ -303,11 +312,11 @@
 
     void clear_variable (const std::string& name)
     {
-      table_iterator p = m_symbols.find (name);
+      auto p = m_symbols.find (name);
 
       if (p != m_symbols.end ())
         p->second.clear (m_context);
-      else if (m_is_nested)
+      else if (is_nested ())
         {
           std::shared_ptr<symbol_scope_rep> psr = parent_scope_rep ();
 
@@ -331,7 +340,7 @@
             }
         }
 
-      if (m_is_nested)
+      if (is_nested ())
         {
           std::shared_ptr<symbol_scope_rep> psr = parent_scope_rep ();
 
@@ -355,7 +364,7 @@
             }
         }
 
-      if (m_is_nested)
+      if (is_nested ())
         {
           std::shared_ptr<symbol_scope_rep> psr = parent_scope_rep ();
 
@@ -544,6 +553,10 @@
 
     void set_parent (const std::shared_ptr<symbol_scope_rep>& parent);
 
+    void set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent);
+
+    bool is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const;
+
     void update_nest (void);
 
     bool look_nonlocal (const std::string& name, symbol_record& result);
@@ -582,13 +595,18 @@
 
     std::weak_ptr<symbol_scope_rep> m_parent;
 
+    //! Primary (top) parent of nested function (may be null).  Used
+    //! to determine whether two nested functions are related.
+
+    std::weak_ptr<symbol_scope_rep> m_primary_parent;
+
     //! Child nested functions.
 
     std::vector<symbol_scope> m_children;
 
     //! If true, then this scope belongs to a nested function.
 
-    bool m_is_nested;
+    size_t m_nesting_depth;
 
     //! If true then no variables can be added.
 
@@ -628,15 +646,26 @@
         m_rep->insert_symbol_record (sr);
     }
 
+    void install_auto_fcn_vars (void)
+    {
+      if (m_rep)
+        m_rep->install_auto_fcn_vars ();
+    }
+
     bool is_nested (void) const
     {
       return m_rep ? m_rep->is_nested () : false;
     }
 
-    void mark_nested (void)
+    void set_nesting_depth (size_t depth)
     {
       if (m_rep)
-        m_rep->mark_nested ();
+        m_rep->set_nesting_depth (depth);
+    }
+
+    size_t nesting_depth (void) const
+    {
+      return m_rep ? m_rep->nesting_depth () : 0;
     }
 
     bool is_static (void) const
@@ -655,6 +684,11 @@
       return m_rep ? m_rep->parent_scope_rep () : nullptr;
     }
 
+    std::shared_ptr<symbol_scope_rep> primary_parent_scope (void) const
+    {
+      return m_rep ? m_rep->primary_parent_scope_rep () : nullptr;
+    }
+
     symbol_scope dup (void) const
     {
       return symbol_scope (m_rep ? m_rep->dup () : nullptr);
@@ -682,13 +716,9 @@
         m_rep->inherit (donor_scope.get_rep ());
     }
 
-    octave_value
-    find (const std::string& name, const octave_value_list& args,
-          bool skip_variables, bool local_funcs)
+    octave_value find (const std::string& name)
     {
-      return (m_rep
-              ? m_rep->find (name, args, skip_variables, local_funcs)
-              : octave_value ());
+      return m_rep ? m_rep->find (name) : octave_value ();
     }
 
     symbol_record&
@@ -944,6 +974,17 @@
         m_rep->set_parent (p.get_rep ());
     }
 
+    void set_primary_parent (const symbol_scope& p)
+    {
+      if (m_rep)
+        m_rep->set_primary_parent (p.get_rep ());
+    }
+
+    bool is_relative (const symbol_scope& scope) const
+    {
+      return m_rep ? m_rep->is_relative (scope.get_rep ()) : false;
+    }
+
     void update_nest (void)
     {
       if (m_rep)
--- a/libinterp/corefcn/symtab.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/symtab.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -97,7 +97,7 @@
     bool retval = false;
 
     octave_value ov_fcn
-      = octave::load_fcn_from_file (ff, dir_name, dispatch_type,
+      = load_fcn_from_file (ff, dir_name, dispatch_type,
                                     package_name);
 
     if (ov_fcn.is_defined ())
@@ -167,7 +167,8 @@
 
                             if (! dispatch_type.empty ())
                               {
-                                load_path& lp = __get_load_path__ ("out_of_date_check");
+                                load_path& lp
+                                  = __get_load_path__ ("out_of_date_check");
 
                                 file = lp.find_method (dispatch_type, nm,
                                                        dir_name, pack);
@@ -210,7 +211,8 @@
 
                             if (file.empty ())
                               {
-                                load_path& lp = __get_load_path__ ("out_of_date_check");
+                                load_path& lp
+                                  = __get_load_path__ ("out_of_date_check");
                                 file = lp.find_fcn (nm, dir_name, pack);
                               }
                           }
@@ -283,8 +285,8 @@
                     // breakpoints associated with it
                     if (clear_breakpoints)
                       {
-                        octave::bp_table& bptab
-                          = octave::__get_bp_table__ ("out_of_date_check");
+                        bp_table& bptab
+                          = __get_bp_table__ ("out_of_date_check");
 
                         bptab.remove_all_breakpoints_in_file (canonical_nm,
                                                               true);
@@ -355,15 +357,6 @@
   }
 
   octave_value
-  symbol_table::find (const std::string& name, const octave_value_list& args,
-                      bool skip_variables, bool local_funcs)
-  {
-    return (m_current_scope
-            ? m_current_scope.find (name, args, skip_variables, local_funcs)
-            : octave_value ());
-  }
-
-  octave_value
   symbol_table::builtin_find (const std::string& name)
   {
     fcn_table_iterator p = m_fcn_table.find (name);
@@ -387,17 +380,17 @@
 
   octave_value
   symbol_table::fcn_table_find (const std::string& name,
-                                const octave_value_list& args, bool local_funcs)
+                                const octave_value_list& args)
   {
     fcn_table_iterator p = m_fcn_table.find (name);
 
     if (p != m_fcn_table.end ())
-      return p->second.find (args, local_funcs);
+      return p->second.find (args);
     else
       {
         fcn_info finfo (name);
 
-        octave_value fcn = finfo.find (args, local_funcs);
+        octave_value fcn = finfo.find (args);
 
         if (fcn.is_defined ())
           m_fcn_table[name] = finfo;
@@ -410,93 +403,43 @@
 
   octave_value
   symbol_table::find_function (const std::string& name,
-                               const octave_value_list& args, bool local_funcs)
-  {
-    octave_value retval;
-
-    if (! name.empty () && name[0] == '@')
-      {
-        // Look for a class specific function.
-        std::string dispatch_type =
-          name.substr (1, name.find_first_of (sys::file_ops::dir_sep_str ()) - 1);
-
-        std::string method;
-        size_t pos = name.find_last_of (sys::file_ops::dir_sep_str ());
-        if (pos != std::string::npos)
-          method = name.substr (pos + 1);
-
-        retval = find_method (method, dispatch_type);
-      }
-    else
-      {
-        size_t pos = name.find_first_of ('>');
-
-        if (pos == std::string::npos)
-          retval = find (name, args, true, local_funcs);
-        else
-          {
-            std::string fcn_scope = name.substr (0, pos);
-            symbol_scope stored_scope = m_current_scope;
-            m_current_scope = m_top_scope;
-            octave_value parent = find_function (name.substr (0, pos),
-                                                 octave_value_list (), false);
-
-            if (parent.is_defined ())
-              {
-                octave_function *parent_fcn = parent.function_value ();
-
-                if (parent_fcn)
-                  {
-                    m_current_scope = parent_fcn->scope ();
-
-                    if (m_current_scope && m_current_scope != m_top_scope)
-                      retval = find_function (name.substr (pos + 1), args);
-                  }
-              }
-
-            m_current_scope = stored_scope;
-          }
-      }
-
-    return retval;
-  }
-
-  // look for @class/method>subfunction
-  octave_value
-  symbol_table::find_submethod (const std::string& name,
-                                const std::string& dispatch_type)
+                               const octave_value_list& args)
   {
     octave_value fcn;
 
-    std::string full_name = '@' + dispatch_type +
-      sys::file_ops::dir_sep_str () + name;
-    size_t pos = full_name.find_first_of ('>');
-
-    if (pos != std::string::npos)
+    if (m_current_scope)
       {
-        std::string fcn_scope = full_name.substr (0, pos);
-        symbol_scope stored_scope = m_current_scope;
-        m_current_scope = m_top_scope;
-        octave_value parent = find_function (full_name.substr (0, pos),
-                                             octave_value_list (), false);
-        if (parent.is_defined ())
-          {
-            octave_function *parent_fcn = parent.function_value ();
+        fcn = m_current_scope.find_subfunction (name);
 
-            if (parent_fcn)
-              {
-                m_current_scope = parent_fcn->scope ();
-
-                if (m_current_scope && m_current_scope != m_top_scope)
-                  fcn = find_function (full_name.substr (pos + 1),
-                                       octave_value_list ());
-              }
-          }
-
-        m_current_scope = stored_scope;
+        if (fcn.is_defined ())
+          return fcn;
       }
 
-    return fcn;
+    return fcn_table_find (name, args);
+  }
+
+  // FIXME: this function only finds legacy class methods, not
+  // classdef methods.
+
+  octave_value
+  symbol_table::find_method (const std::string& name,
+                             const std::string& dispatch_type)
+  {
+    fcn_table_const_iterator p = m_fcn_table.find (name);
+
+    if (p != m_fcn_table.end ())
+      return p->second.find_method (dispatch_type);
+    else
+      {
+        fcn_info finfo (name);
+
+        octave_value fcn = finfo.find_method (dispatch_type);
+
+        if (fcn.is_defined ())
+          m_fcn_table[name] = finfo;
+
+        return fcn;
+      }
   }
 
   template <template <typename, typename...> class C, typename V,
--- a/libinterp/corefcn/symtab.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/symtab.h	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,6 @@
 #include "octave-config.h"
 
 #include <deque>
-#include <limits>
 #include <list>
 #include <map>
 #include <set>
@@ -106,19 +105,14 @@
         m_current_scope.set_context (context);
     }
 
-    symbol_record find_symbol (const std::string& name, symbol_scope& sid)
-    {
-      return sid ? sid.find_symbol (name) : symbol_record ();
-    }
-
     symbol_record find_symbol (const std::string& name)
     {
-      return find_symbol (name, m_current_scope);
+      return m_current_scope.find_symbol (name);
     }
 
     symbol_record find_global_symbol (const std::string& name)
     {
-      symbol_record sym = find_symbol (name, m_global_scope);
+      symbol_record sym = m_global_scope.find_symbol (name);
 
       sym.mark_global ();
 
@@ -139,13 +133,6 @@
 
     bool at_top_level (void) { return m_current_scope == m_top_scope; }
 
-    // Find a value corresponding to the given name in the table.
-    octave_value
-    find (const std::string& name,
-          const octave_value_list& args = octave_value_list (),
-          bool skip_variables = false,
-          bool local_funcs = true);
-
     void assign (const std::string& name, const octave_value& value, bool force_add)
     {
       if (m_current_scope)
@@ -196,38 +183,10 @@
       return val.is_defined ();
     }
 
+    // FIXME: this function only finds legacy class methods, not
+    // classdef methods.
     octave_value
-    find_method (const std::string& name, const std::string& dispatch_type)
-    {
-      fcn_table_const_iterator p = m_fcn_table.find (name);
-
-      if (p != m_fcn_table.end ())
-        {
-          octave_value fcn = p->second.find_method (dispatch_type);
-
-          if (! fcn.is_defined ())
-            fcn = find_submethod (name, dispatch_type);
-
-          return fcn;
-        }
-      else
-        {
-          fcn_info finfo (name);
-
-          octave_value fcn = finfo.find_method (dispatch_type);
-
-          if (! fcn.is_defined ())
-            fcn = find_submethod (name, dispatch_type);
-
-          if (fcn.is_defined ())
-            m_fcn_table[name] = finfo;
-
-          return fcn;
-        }
-    }
-
-    octave_value
-    find_submethod (const std::string& name, const std::string& dispatch_type);
+    find_method (const std::string& name, const std::string& dispatch_type);
 
     octave_value
     find_built_in_function (const std::string& name)
@@ -241,7 +200,7 @@
     octave_value
     find_autoload (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       return (p != m_fcn_table.end ()
               ? p->second.find_autoload () : octave_value ());
@@ -251,17 +210,15 @@
 
     octave_value
     fcn_table_find (const std::string& name,
-                    const octave_value_list& args = octave_value_list (),
-                    bool local_funcs = true);
+                    const octave_value_list& args = octave_value_list ());
 
     octave_value
     find_function (const std::string& name,
-                   const octave_value_list& args = octave_value_list (),
-                   bool local_funcs = true);
+                   const octave_value_list& args = octave_value_list ());
 
     octave_value find_user_function (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       return (p != m_fcn_table.end ()
               ? p->second.find_user_function () : octave_value ());
@@ -269,7 +226,7 @@
 
     octave_value find_cmdline_function (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       return (p != m_fcn_table.end ()
               ? p->second.find_cmdline_function () : octave_value ());
@@ -278,7 +235,7 @@
     void install_cmdline_function (const std::string& name,
                                    const octave_value& fcn)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -303,7 +260,7 @@
                                  const octave_value& fcn,
                                  const std::string& file_name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -324,7 +281,7 @@
     void install_user_function (const std::string& name,
                                 const octave_value& fcn)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -347,7 +304,7 @@
     void install_built_in_function (const std::string& name,
                                     const octave_value& fcn)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -383,7 +340,7 @@
 
     void clear_functions (bool force = false)
     {
-      fcn_table_iterator p = m_fcn_table.begin ();
+      auto p = m_fcn_table.begin ();
 
       while (p != m_fcn_table.end ())
         (p++)->second.clear (force);
@@ -408,7 +365,7 @@
     {
       glob_match pattern (pat);
 
-      fcn_table_iterator p = m_fcn_table.begin ();
+      auto p = m_fcn_table.begin ();
 
       while (p != m_fcn_table.end ())
         {
@@ -431,7 +388,7 @@
 
     void clear_user_function (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -447,7 +404,7 @@
     // This clears oct and mex files, including autoloads.
     void clear_dld_function (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -460,7 +417,7 @@
 
     void clear_mex_functions (void)
     {
-      fcn_table_iterator p = m_fcn_table.begin ();
+      auto p = m_fcn_table.begin ();
 
       while (p != m_fcn_table.end ())
         (p++)->second.clear_mex_function ();
@@ -491,7 +448,7 @@
     void install_built_in_dispatch (const std::string& name,
                                     const std::string& klass)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
 
       if (p != m_fcn_table.end ())
         {
@@ -669,7 +626,7 @@
 
     fcn_info * get_fcn_info (const std::string& name)
     {
-      fcn_table_iterator p = m_fcn_table.find (name);
+      auto p = m_fcn_table.find (name);
       return p != m_fcn_table.end () ? &p->second : nullptr;
     }
 
@@ -722,13 +679,6 @@
   extern bool out_of_date_check (octave_value& function,
                                  const std::string& dispatch_type = "",
                                  bool check_relative = true);
-
-  extern OCTINTERP_API std::string
-  get_dispatch_type (const octave_value_list& args);
-
-  extern OCTINTERP_API std::string
-  get_dispatch_type (const octave_value_list& args,
-                     builtin_type_t& builtin_type);
 }
 
 #endif
--- a/libinterp/corefcn/syscalls.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/syscalls.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -42,7 +42,6 @@
 #include "oct-env.h"
 #include "oct-syscalls.h"
 #include "oct-uname.h"
-
 #include "defun.h"
 #include "error.h"
 #include "errwarn.h"
@@ -52,6 +51,7 @@
 #include "ovl.h"
 #include "oct-stdstrm.h"
 #include "oct-stream.h"
+#include "octave-link.h"
 #include "sysdep.h"
 #include "utils.h"
 #include "variables.h"
@@ -141,8 +141,8 @@
     return ovl (-1, "");
 }
 
-DEFUNX ("exec", Fexec, args, ,
-        doc: /* -*- texinfo -*-
+DEFMETHODX ("exec", Fexec, interp, args, ,
+            doc: /* -*- texinfo -*-
 @deftypefn {} {[@var{err}, @var{msg}] =} exec (@var{file}, @var{args})
 Replace current process with a new process.
 
@@ -191,7 +191,9 @@
       exec_args[0] = exec_file;
     }
 
-  octave_history_write_timestamp ();
+  octave::history_system& history_sys = interp.get_history_system ();
+
+  history_sys.write_timestamp ();
 
   if (! octave::command_history::ignoring_entries ())
     octave::command_history::clean_up_and_save ();
@@ -288,7 +290,7 @@
   pid = octave::sys::popen2 (exec_file, arg_list, sync_mode, filedesc, msg);
 
   if (pid < 0)
-    error (msg.c_str ());
+    error ("%s", msg.c_str ());
 
   FILE *ifile = fdopen (filedesc[1], "r");
   FILE *ofile = fdopen (filedesc[0], "w");
@@ -852,7 +854,7 @@
   @result{} err = 0
   @result{} msg =
 @end example
-@seealso{lstat, ls, dir}
+@seealso{lstat, ls, dir, isfile, isfolder}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -1088,8 +1090,12 @@
 
   std::string msg;
 
+  octave_link::file_remove (name, "");
+
   int status = octave::sys::unlink (name, msg);
 
+  octave_link::file_renamed (status == 0);
+
   return ovl (status, msg);
 }
 
--- a/libinterp/corefcn/sysdep.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sysdep.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -64,8 +64,8 @@
 #include "lo-sysinfo.h"
 #include "mach-info.h"
 #include "oct-env.h"
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
-#include "unsetenv-wrapper.h"
 
 #include "builtin-defun-decls.h"
 #include "Cell.h"
@@ -122,26 +122,26 @@
 
   if (h != INVALID_HANDLE_VALUE)
     {
-      MODULEENTRY32 mod_info;
+      MODULEENTRY32W mod_info;
 
       ZeroMemory (&mod_info, sizeof (mod_info));
       mod_info.dwSize = sizeof (mod_info);
 
-      if (Module32First (h, &mod_info))
+      if (Module32FirstW (h, &mod_info))
         {
           do
             {
-              std::string mod_name (mod_info.szModule);
+              std::string mod_name (octave::sys::u8_from_wstring (mod_info.szModule));
 
               if (mod_name.find ("octinterp") != std::string::npos)
                 {
-                  bin_dir = mod_info.szExePath;
+                  bin_dir = octave::sys::u8_from_wstring (mod_info.szExePath);
                   if (! bin_dir.empty () && bin_dir.back () != '\\')
                     bin_dir.push_back ('\\');
                   break;
                 }
             }
-          while (Module32Next (h, &mod_info));
+          while (Module32NextW (h, &mod_info));
         }
 
       CloseHandle (h);
@@ -166,33 +166,35 @@
 
 #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?
+namespace octave
+{
+  // 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)
-{
+  void set_application_id (void)
+  {
 #if defined (__MINGW32__) || defined (_MSC_VER)
 
-  typedef HRESULT (WINAPI *SETCURRENTAPPID)(PCWSTR AppID);
+    typedef HRESULT (WINAPI *SETCURRENTAPPID)(PCWSTR AppID);
 
-  HMODULE hShell = LoadLibrary ("shell32.dll");
+    HMODULE hShell = LoadLibrary ("shell32.dll");
 
-  if (hShell)
-    {
-      SETCURRENTAPPID pfnSetCurrentProcessExplicitAppUserModelID =
-        reinterpret_cast<SETCURRENTAPPID> (GetProcAddress (hShell,
-                                           "SetCurrentProcessExplicitAppUserModelID"));
+    if (hShell)
+      {
+        SETCURRENTAPPID pfnSetCurrentProcessExplicitAppUserModelID =
+          reinterpret_cast<SETCURRENTAPPID> (GetProcAddress (hShell,
+                                                             "SetCurrentProcessExplicitAppUserModelID"));
 
-      if (pfnSetCurrentProcessExplicitAppUserModelID)
-        pfnSetCurrentProcessExplicitAppUserModelID (L"gnu.octave." VERSION);
+        if (pfnSetCurrentProcessExplicitAppUserModelID)
+          pfnSetCurrentProcessExplicitAppUserModelID (L"gnu.octave." VERSION);
 
-      FreeLibrary (hShell);
-    }
+        FreeLibrary (hShell);
+      }
 
 #endif
+  }
 }
 
 DEFUN (__open_with_system_app__, args, ,
@@ -209,8 +211,9 @@
   octave_value retval;
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-  HINSTANCE status = ShellExecute (0, 0, file.c_str (), 0, 0,
-                                   SW_SHOWNORMAL);
+  HINSTANCE status = ShellExecuteW (0, 0,
+                                    octave::sys::u8_to_wstring (file).c_str (),
+                                    0, 0, SW_SHOWNORMAL);
 
   // ShellExecute returns a value greater than 32 if successful.
   retval = (reinterpret_cast<ptrdiff_t> (status) > 32);
@@ -249,364 +252,368 @@
 }
 #endif
 
-// Return TRUE if FILE1 and FILE2 refer to the same (physical) file.
+namespace octave
+{
+  // Return TRUE if FILE1 and FILE2 refer to the same (physical) file.
 
-bool
-same_file_internal (const std::string& file1, const std::string& file2)
-{
+  bool same_file_internal (const std::string& file1, const std::string& file2)
+  {
 #if defined (OCTAVE_USE_WINDOWS_API)
 
-  bool retval = false;
+    bool retval = false;
 
-  const char *f1 = file1.c_str ();
-  const char *f2 = file2.c_str ();
-
-  bool f1_is_dir = GetFileAttributes (f1) & FILE_ATTRIBUTE_DIRECTORY;
-  bool f2_is_dir = GetFileAttributes (f2) & FILE_ATTRIBUTE_DIRECTORY;
+    std::wstring file1w = octave::sys::u8_to_wstring (file1);
+    std::wstring file2w = octave::sys::u8_to_wstring (file2);
+    const wchar_t *f1 = file1w.c_str ();
+    const wchar_t *f2 = file2w.c_str ();
 
-  // Windows native code
-  // Reference: http://msdn2.microsoft.com/en-us/library/aa363788.aspx
+    bool f1_is_dir = GetFileAttributesW (f1) & FILE_ATTRIBUTE_DIRECTORY;
+    bool f2_is_dir = GetFileAttributesW (f2) & FILE_ATTRIBUTE_DIRECTORY;
+
+    // Windows native code
+    // Reference: http://msdn2.microsoft.com/en-us/library/aa363788.aspx
 
-  DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+    DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
-  HANDLE hfile1
-    = CreateFile (f1, 0, share, 0, OPEN_EXISTING,
-                  f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+    HANDLE hfile1
+      = CreateFileW (f1, 0, share, 0, OPEN_EXISTING,
+                     f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
-  if (hfile1 != INVALID_HANDLE_VALUE)
-    {
-      HANDLE hfile2
-        = CreateFile (f2, 0, share, 0, OPEN_EXISTING,
-                      f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+    if (hfile1 != INVALID_HANDLE_VALUE)
+      {
+        HANDLE hfile2
+          = CreateFileW (f2, 0, share, 0, OPEN_EXISTING,
+                         f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
-      if (hfile2 != INVALID_HANDLE_VALUE)
-        {
-          BY_HANDLE_FILE_INFORMATION hfi1;
-          BY_HANDLE_FILE_INFORMATION hfi2;
+        if (hfile2 != INVALID_HANDLE_VALUE)
+          {
+            BY_HANDLE_FILE_INFORMATION hfi1;
+            BY_HANDLE_FILE_INFORMATION hfi2;
 
-          if (GetFileInformationByHandle (hfile1, &hfi1)
-              && GetFileInformationByHandle (hfile2, &hfi2))
-            {
-              retval = (hfi1.dwVolumeSerialNumber == hfi2.dwVolumeSerialNumber
-                        && hfi1.nFileIndexHigh == hfi2.nFileIndexHigh
-                        && hfi1.nFileIndexLow == hfi2.nFileIndexLow);
-            }
+            if (GetFileInformationByHandle (hfile1, &hfi1)
+                && GetFileInformationByHandle (hfile2, &hfi2))
+              {
+                retval = (hfi1.dwVolumeSerialNumber == hfi2.dwVolumeSerialNumber
+                          && hfi1.nFileIndexHigh == hfi2.nFileIndexHigh
+                          && hfi1.nFileIndexLow == hfi2.nFileIndexLow);
+              }
 
-          CloseHandle (hfile2);
-        }
+            CloseHandle (hfile2);
+          }
 
-      CloseHandle (hfile1);
-    }
+        CloseHandle (hfile1);
+      }
 
-  return retval;
+    return retval;
 
 #else
 
-  // POSIX Code
+    // POSIX Code
 
-  octave::sys::file_stat fs_file1 (file1);
-  octave::sys::file_stat fs_file2 (file2);
+    octave::sys::file_stat fs_file1 (file1);
+    octave::sys::file_stat fs_file2 (file2);
 
-  return (fs_file1 && fs_file2
-          && fs_file1.ino () == fs_file2.ino ()
-          && fs_file1.dev () == fs_file2.dev ());
+    return (fs_file1 && fs_file2
+            && fs_file1.ino () == fs_file2.ino ()
+            && fs_file1.dev () == fs_file2.dev ());
 
 #endif
-}
+  }
 
-void
-sysdep_init (void)
-{
-  // Use a function from libgomp to force loading of OpenMP library.
-  // Otherwise, a dynamically loaded library making use of OpenMP such
-  // as GraphicsMagick will segfault on exit (bug #41699).
+  void sysdep_init (void)
+  {
+    // Use a function from libgomp to force loading of OpenMP library.
+    // Otherwise, a dynamically loaded library making use of OpenMP such
+    // as GraphicsMagick will segfault on exit (bug #41699).
 #if defined (HAVE_OMP_GET_NUM_THREADS)
-  omp_get_num_threads ();
+    omp_get_num_threads ();
 #endif
 
 #if defined (__386BSD__) || defined (__FreeBSD__) || defined (__NetBSD__)
-  BSD_init ();
+    BSD_init ();
 #elif defined (__MINGW32__)
-  MINGW_init ();
+    MINGW_init ();
 #elif defined (_MSC_VER)
-  MSVC_init ();
+    MSVC_init ();
 #endif
-}
+  }
 
-void
-sysdep_cleanup (void)
-{
+  void sysdep_cleanup (void)
+  {
 #if defined (OCTAVE_USE_WINDOWS_API)
-  // Let us fail immediately without displaying any dialog.
-  SetProcessShutdownParameters (0x280, SHUTDOWN_NORETRY);
+    // Let us fail immediately without displaying any dialog.
+    SetProcessShutdownParameters (0x280, SHUTDOWN_NORETRY);
 #endif
-}
+  }
 
-// Set terminal in raw mode.  From less-177.
-//
-// Change terminal to "raw mode", or restore to "normal" mode.
-// "Raw mode" means
-//      1. An outstanding read will complete on receipt of a single keystroke.
-//      2. Input is not echoed.
-//      3. On output, \n is mapped to \r\n.
-//      4. \t is NOT expanded into spaces.
-//      5. Signal-causing characters such as ctrl-C (interrupt),
-//         etc. are NOT disabled.
-// It doesn't matter whether an input \n is mapped to \r, or vice versa.
+  // Set terminal in raw mode.  From less-177.
+  //
+  // Change terminal to "raw mode", or restore to "normal" mode.
+  // "Raw mode" means
+  //      1. An outstanding read will complete on receipt of a single keystroke.
+  //      2. Input is not echoed.
+  //      3. On output, \n is mapped to \r\n.
+  //      4. \t is NOT expanded into spaces.
+  //      5. Signal-causing characters such as ctrl-C (interrupt),
+  //         etc. are NOT disabled.
+  // It doesn't matter whether an input \n is mapped to \r, or vice versa.
 
-void
-raw_mode (bool on, bool wait)
-{
-  static bool curr_on = false;
+  void raw_mode (bool on, bool wait)
+  {
+    static bool curr_on = false;
 
-  int tty_fd = STDIN_FILENO;
-  if (! octave_isatty_wrapper (tty_fd))
-    {
-      if (octave::application::interactive ()
-          && ! octave::application::forced_interactive ())
-        error ("stdin is not a tty!");
-    }
+    int tty_fd = STDIN_FILENO;
+    if (! octave_isatty_wrapper (tty_fd))
+      {
+        if (octave::application::interactive ()
+            && ! octave::application::forced_interactive ())
+          error ("stdin is not a tty!");
+      }
 
-  if (on == curr_on)
-    return;
+    if (on == curr_on)
+      return;
 
 #if defined (HAVE_TERMIOS_H)
-  {
-    struct termios s;
-    static struct termios save_term;
+    {
+      struct termios s;
+      static struct termios save_term;
 
-    if (on)
-      {
-        // Get terminal modes.
+      if (on)
+        {
+          // Get terminal modes.
 
-        tcgetattr (tty_fd, &s);
+          tcgetattr (tty_fd, &s);
 
-        // Save modes and set certain variables dependent on modes.
+          // Save modes and set certain variables dependent on modes.
 
-        save_term = s;
-//      ospeed = s.c_cflag & CBAUD;
-//      erase_char = s.c_cc[VERASE];
-//      kill_char = s.c_cc[VKILL];
+          save_term = s;
+          //      ospeed = s.c_cflag & CBAUD;
+          //      erase_char = s.c_cc[VERASE];
+          //      kill_char = s.c_cc[VKILL];
 
-        // Set the modes to the way we want them.
+          // Set the modes to the way we want them.
 
-        s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
-        s.c_oflag |=  (OPOST | ONLCR);
+          s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+          s.c_oflag |=  (OPOST | ONLCR);
 #if defined (OCRNL)
-        s.c_oflag &= ~(OCRNL);
+          s.c_oflag &= ~(OCRNL);
 #endif
 #if defined (ONOCR)
-        s.c_oflag &= ~(ONOCR);
+          s.c_oflag &= ~(ONOCR);
 #endif
 #if defined (ONLRET)
-        s.c_oflag &= ~(ONLRET);
+          s.c_oflag &= ~(ONLRET);
 #endif
-        s.c_cc[VMIN] = (wait ? 1 : 0);
-        s.c_cc[VTIME] = 0;
-      }
-    else
-      {
-        // Restore saved modes.
+          s.c_cc[VMIN] = (wait ? 1 : 0);
+          s.c_cc[VTIME] = 0;
+        }
+      else
+        {
+          // Restore saved modes.
 
-        s = save_term;
-      }
+          s = save_term;
+        }
 
-    tcsetattr (tty_fd, wait ? TCSAFLUSH : TCSADRAIN, &s);
-  }
+      tcsetattr (tty_fd, wait ? TCSAFLUSH : TCSADRAIN, &s);
+    }
 #elif defined (HAVE_TERMIO_H)
-  {
-    struct termio s;
-    static struct termio save_term;
+    {
+      struct termio s;
+      static struct termio save_term;
 
-    if (on)
-      {
-        // Get terminal modes.
+      if (on)
+        {
+          // Get terminal modes.
 
-        ioctl (tty_fd, TCGETA, &s);
+          ioctl (tty_fd, TCGETA, &s);
 
-        // Save modes and set certain variables dependent on modes.
+          // Save modes and set certain variables dependent on modes.
 
-        save_term = s;
-//      ospeed = s.c_cflag & CBAUD;
-//      erase_char = s.c_cc[VERASE];
-//      kill_char = s.c_cc[VKILL];
+          save_term = s;
+          //      ospeed = s.c_cflag & CBAUD;
+          //      erase_char = s.c_cc[VERASE];
+          //      kill_char = s.c_cc[VKILL];
 
-        // Set the modes to the way we want them.
+          // Set the modes to the way we want them.
 
-        s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
-        s.c_oflag |=  (OPOST | ONLCR);
+          s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+          s.c_oflag |=  (OPOST | ONLCR);
 #if defined (OCRNL)
-        s.c_oflag &= ~(OCRNL);
+          s.c_oflag &= ~(OCRNL);
 #endif
 #if defined (ONOCR)
-        s.c_oflag &= ~(ONOCR);
+          s.c_oflag &= ~(ONOCR);
 #endif
 #if defined (ONLRET)
-        s.c_oflag &= ~(ONLRET);
+          s.c_oflag &= ~(ONLRET);
 #endif
-        s.c_cc[VMIN] = (wait ? 1 : 0);
-      }
-    else
-      {
-        // Restore saved modes.
+          s.c_cc[VMIN] = (wait ? 1 : 0);
+        }
+      else
+        {
+          // Restore saved modes.
+
+          s = save_term;
+        }
+
+      ioctl (tty_fd, TCSETAW, &s);
+    }
+#elif defined (HAVE_SGTTY_H)
+    {
+      octave_unused_parameter (wait);
+
+      struct sgttyb s;
+      static struct sgttyb save_term;
+
+      if (on)
+        {
+          // Get terminal modes.
 
-        s = save_term;
-      }
+          ioctl (tty_fd, TIOCGETP, &s);
+
+          // Save modes and set certain variables dependent on modes.
+
+          save_term = s;
+          //      ospeed = s.sg_ospeed;
+          //      erase_char = s.sg_erase;
+          //      kill_char = s.sg_kill;
+
+          // Set the modes to the way we want them.
 
-    ioctl (tty_fd, TCSETAW, &s);
-  }
-#elif defined (HAVE_SGTTY_H)
-  {
+          s.sg_flags |= CBREAK;
+          s.sg_flags &= ~(ECHO);
+        }
+      else
+        {
+          // Restore saved modes.
+
+          s = save_term;
+        }
+
+      ioctl (tty_fd, TIOCSETN, &s);
+    }
+#else
+
     octave_unused_parameter (wait);
 
-    struct sgttyb s;
-    static struct sgttyb save_term;
-
-    if (on)
-      {
-        // Get terminal modes.
-
-        ioctl (tty_fd, TIOCGETP, &s);
-
-        // Save modes and set certain variables dependent on modes.
-
-        save_term = s;
-//      ospeed = s.sg_ospeed;
-//      erase_char = s.sg_erase;
-//      kill_char = s.sg_kill;
-
-        // Set the modes to the way we want them.
+    warn_disabled_feature ("", "raw mode console I/O");
 
-        s.sg_flags |= CBREAK;
-        s.sg_flags &= ~(ECHO);
-      }
-    else
-      {
-        // Restore saved modes.
-
-        s = save_term;
-      }
-
-    ioctl (tty_fd, TIOCSETN, &s);
-  }
-#else
-
-  octave_unused_parameter (wait);
-
-  warn_disabled_feature ("", "raw mode console I/O");
-
-  // Make sure the current mode doesn't toggle.
-  on = curr_on;
+    // Make sure the current mode doesn't toggle.
+    on = curr_on;
 #endif
 
-  curr_on = on;
-}
+    curr_on = on;
+  }
 
-FILE *
-octave_popen (const char *command, const char *mode)
-{
+  FILE * popen (const char *command, const char *mode)
+  {
 #if defined (__MINGW32__) || defined (_MSC_VER)
-  if (mode && mode[0] && ! mode[1])
-    {
-      // Use binary mode on Windows if unspecified
-      char tmode[3] = {mode[0], 'b', '\0'};
+    wchar_t *wcommand = u8_to_wchar (command);
+    wchar_t *wmode = u8_to_wchar (mode);
 
-      return _popen (command, tmode);
-    }
-  else
-    return _popen (command, mode);
-#else
-  return popen (command, mode);
-#endif
-}
+    octave::unwind_protect frame;
+    frame.add_fcn (::free, static_cast<void *> (wcommand));
+    frame.add_fcn (::free, static_cast<void *> (wmode));
+
+    if (wmode && wmode[0] && ! wmode[1])
+      {
+        // Use binary mode on Windows if unspecified
+        wchar_t tmode[3] = {wmode[0], L'b', L'\0'};
 
-int
-octave_pclose (FILE *f)
-{
-#if defined (__MINGW32__) || defined (_MSC_VER)
-  return _pclose (f);
+        return _wpopen (wcommand, tmode);
+      }
+    else
+      return _wpopen (wcommand, wmode);
 #else
-  return pclose (f);
+    return ::popen (command, mode);
 #endif
-}
-
-// Read one character from the terminal.
+  }
 
-int
-octave_kbhit (bool wait)
-{
+  int pclose (FILE *f)
+  {
+#if defined (__MINGW32__) || defined (_MSC_VER)
+    return ::_pclose (f);
+#else
+    return ::pclose (f);
+#endif
+  }
+
+  // Read one character from the terminal.
+
+  int kbhit (bool wait)
+  {
 #if defined (HAVE__KBHIT) && defined (HAVE__GETCH)
-  // This essentially means we are on a Windows system.
-  int c;
+    // This essentially means we are on a Windows system.
+    int c;
 
-  if (wait)
-    c = _getch ();
-  else
-    c = (! _kbhit ()) ? 0 : _getch ();
+    if (wait)
+      c = _getch ();
+    else
+      c = (! _kbhit ()) ? 0 : _getch ();
 
 #else
-  raw_mode (true, wait);
+    raw_mode (true, wait);
 
-  // Get current handler.
-  octave::interrupt_handler saved_interrupt_handler
-    = octave::ignore_interrupts ();
+    // Get current handler.
+    octave::interrupt_handler saved_interrupt_handler
+      = octave::ignore_interrupts ();
 
-  // Restore it, disabling system call restarts (if possible) so the
-  // read can be interrupted.
+    // Restore it, disabling system call restarts (if possible) so the
+    // read can be interrupted.
 
-  octave::set_interrupt_handler (saved_interrupt_handler, false);
+    octave::set_interrupt_handler (saved_interrupt_handler, false);
 
-  int c = std::cin.get ();
+    int c = std::cin.get ();
 
-  if (std::cin.fail () || std::cin.eof ())
-    std::cin.clear ();
+    if (std::cin.fail () || std::cin.eof ())
+      std::cin.clear ();
 
-  // Restore it, enabling system call restarts (if possible).
-  octave::set_interrupt_handler (saved_interrupt_handler, true);
+    // Restore it, enabling system call restarts (if possible).
+    octave::set_interrupt_handler (saved_interrupt_handler, true);
 
-  raw_mode (false, true);
+    raw_mode (false, true);
 #endif
 
-  return c;
-}
+    return c;
+  }
 
-std::string
-get_P_tmpdir (void)
-{
+  std::string get_P_tmpdir (void)
+  {
 #if defined (OCTAVE_USE_WINDOWS_API)
 
-  std::string retval;
+    std::string retval;
 
 #if defined (P_tmpdir)
-  retval = P_tmpdir;
+    retval = P_tmpdir;
 #endif
 
-  // Apparently some versions of MinGW and MSVC either don't define
-  // P_tmpdir, or they define it to a single backslash, neither of which
-  // is particularly helpful.
+    // Apparently some versions of MinGW and MSVC either don't define
+    // P_tmpdir, or they define it to a single backslash, neither of which
+    // is particularly helpful.
 
-  if (retval.empty () || retval == R"(\)")
-    {
-      retval = octave::sys::env::getenv ("TEMP");
+    if (retval.empty () || retval == R"(\)")
+      {
+        retval = octave::sys::env::getenv ("TEMP");
 
-      if (retval.empty ())
-        retval = octave::sys::env::getenv ("TMP");
+        if (retval.empty ())
+          retval = octave::sys::env::getenv ("TMP");
 
-      if (retval.empty ())
-        retval = R"(c:\temp)";
-    }
+        if (retval.empty ())
+          retval = R"(c:\temp)";
+      }
 
-  return retval;
+    return retval;
 
 #elif defined (P_tmpdir)
 
-  return P_tmpdir;
+    return P_tmpdir;
 
 #else
 
-  return "/tmp";
+    return "/tmp";
 
 #endif
+  }
 }
 
 DEFUN (clc, , ,
@@ -706,7 +713,7 @@
 
   std::string tmp = args(0).string_value ();
 
-  return ovl (octave_unsetenv_wrapper (tmp.c_str ()));
+  return ovl (octave::sys::unsetenv_wrapper (tmp));
 }
 
 /*
@@ -728,7 +735,9 @@
   LONG result;
   HKEY h_subkey;
 
-  result = RegOpenKeyExA (h_rootkey, subkey.c_str (), 0, KEY_READ, &h_subkey);
+  result = RegOpenKeyExW (h_rootkey,
+                          octave::sys::u8_to_wstring (subkey).c_str (), 0,
+                          KEY_READ, &h_subkey);
   if (result != ERROR_SUCCESS)
     return result;
 
@@ -737,27 +746,30 @@
   frame.add_fcn (reg_close_key_wrapper, h_subkey);
 
   DWORD length = 0;
-  result = RegQueryValueExA (h_subkey, name.c_str (), nullptr, nullptr, nullptr,
-                             &length);
+  result = RegQueryValueExW (h_subkey,
+                             octave::sys::u8_to_wstring (name).c_str (),
+                             nullptr, nullptr, nullptr, &length);
   if (result != ERROR_SUCCESS)
     return result;
 
   DWORD type = 0;
   OCTAVE_LOCAL_BUFFER (BYTE, data, length);
-  result = RegQueryValueExA (h_subkey, name.c_str (), nullptr, &type, data,
-                             &length);
+  result = RegQueryValueExW (h_subkey,
+                             octave::sys::u8_to_wstring (name).c_str (),
+                             nullptr, &type, data, &length);
   if (result != ERROR_SUCCESS)
     return result;
 
   if (type == REG_DWORD)
     value = octave_int32 (*data);
   else if (type == REG_SZ || type == REG_EXPAND_SZ)
-    value = string_vector (reinterpret_cast<char *> (data));
+    value = string_vector (octave::sys::u8_from_wstring (
+                                        reinterpret_cast<wchar_t *> (data)));
 
   return result;
 }
 
-LONG
+static LONG
 get_regkey_names (HKEY h_rootkey, const std::string subkey,
                   std::list<std::string> &fields)
 {
@@ -766,22 +778,24 @@
 
   fields.clear ();
 
-  retval = RegOpenKeyEx (h_rootkey, subkey.c_str (), 0, KEY_READ, &h_subkey);
+  retval = RegOpenKeyExW (h_rootkey,
+                          octave::sys::u8_to_wstring (subkey).c_str (), 0,
+                          KEY_READ, &h_subkey);
   if (retval != ERROR_SUCCESS)
     return retval;
 
   DWORD idx = 0;
   const int MAX_VALUE_NAME_SIZE = 32766;
-  char value_name[MAX_VALUE_NAME_SIZE+1];
+  wchar_t value_name[MAX_VALUE_NAME_SIZE+1];
   DWORD value_name_size = MAX_VALUE_NAME_SIZE;
 
   while (true)
     {
-      retval = RegEnumValue (h_subkey, idx, value_name, &value_name_size,
-                             nullptr, nullptr, nullptr, nullptr);
+      retval = RegEnumValueW (h_subkey, idx, value_name, &value_name_size,
+                              nullptr, nullptr, nullptr, nullptr);
       if (retval != ERROR_SUCCESS)
         break;
-      fields.push_back (value_name);
+      fields.push_back (octave::sys::u8_from_wstring (value_name));
       value_name_size = MAX_VALUE_NAME_SIZE;
       idx++;
     }
@@ -919,7 +933,7 @@
 
       LONG retval = get_regkey_names (h_rootkey, subkey_name, fields);
       if (retval != ERROR_SUCCESS)
-        error ("winqueryreg: error %d reading names from registry", retval);
+        error ("winqueryreg: error %ld reading names from registry", retval);
 
       Cell fieldnames (dim_vector (1, fields.size ()));
       size_t i;
@@ -939,7 +953,7 @@
                value_name.c_str (), rootkey_name.c_str (),
                subkey_name.c_str ());
       if (retval != ERROR_SUCCESS)
-        error ("winqueryreg: error %d reading the specified key", retval);
+        error ("winqueryreg: error %ld reading the specified key", retval);
 
       return ovl (key_val);
     }
@@ -1030,7 +1044,7 @@
 
   Fdrawnow ();
 
-  int c = octave_kbhit (args.length () == 0);
+  int c = octave::kbhit (args.length () == 0);
 
   if (c == -1)
     c = 0;
@@ -1040,17 +1054,21 @@
   return octave_value (s);
 }
 
-DEFUN (pause, args, ,
+// State of the pause system
+static bool Vpause_enabled = true;
+
+DEFUN (pause, args, nargout,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} pause ()
 @deftypefnx {} {} pause (@var{n})
-Suspend the execution of the program for @var{n} seconds.
+@deftypefnx {} {@var{old_state} =} pause ("on")
+@deftypefnx {} {@var{old_state} =} pause ("off")
+@deftypefnx {} {@var{old_state} =} pause ("query")
+Suspend the execution of the program or change the state of the pause function.
 
 If invoked without an input arguments then the program is suspended until a
-character is typed.
-
-@var{n} is a positive real value and may be a fraction of a second,
-for example:
+character is typed.  If argument @var{n} is a positive real value, it indicates
+the number of seconds the program shall be suspended, for example:
 
 @example
 @group
@@ -1070,41 +1088,71 @@
 @end group
 @end example
 
+If invoked with a string argument @qcode{"on"}, @qcode{"off"}, or
+@qcode{"query"}, the state of the pause function is changed or queried.  When
+the state is @qcode{"off"}, the pause function returns immediately.  The
+optional return value contains the previous state of the pause function.  In
+the following example pause is disabled locally:
+
+@example
+@group
+old_state = pause ("off");
+tic; pause (0.05); toc
+     @print{} Elapsed time is 3.00407e-05 seconds.
+pause (old_state);
+@end group
+@end example
+
+While the program is suspended Octave still handles figures painting and
+graphics callbacks execution.
+
 @seealso{kbhit}
 @end deftypefn */)
 {
+  octave_value_list retval;
+  
   int nargin = args.length ();
-
+  
   if (nargin > 1)
     print_usage ();
 
-  if (nargin == 1)
+  if (nargin == 1 && args(0).is_string ())
     {
-      double dval = args(0).double_value ();
+      bool saved_state = Vpause_enabled;
+      std::string state = args(0).string_value ();
+      
+      if (state == "on")
+        Vpause_enabled = true;
+      else if (state == "off")
+        Vpause_enabled = false;
+      else if (state == "query")
+        ;// Do nothing
+      else
+        error ("pause: first argument must be \"on\", \"off\" or \"query\"");
+      
+      if (nargout > 0 || state == "query")
+        retval.append (saved_state ? "on" : "off");
+    }
+  else if (Vpause_enabled)
+    {
+      double dval;
+  
+      if (nargin == 0)
+        dval = octave_Inf;
+      else
+        dval = args(0).xdouble_value ("pause: N must be a scalar real value");
 
       if (octave::math::isnan (dval))
         warning ("pause: NaN is an invalid delay");
       else
         {
           Fdrawnow ();
-
-          if (octave::math::isinf (dval))
-            {
-              octave::flush_stdout ();
-              octave_kbhit ();
-            }
-          else
-            octave_sleep (dval);
+      
+          octave::sleep (dval, true);
         }
     }
-  else
-    {
-      Fdrawnow ();
-      octave::flush_stdout ();
-      octave_kbhit ();
-    }
 
-  return ovl ();
+  return retval;
 }
 
 /*
--- a/libinterp/corefcn/sysdep.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/sysdep.h	Thu Dec 20 17:18:56 2018 -0500
@@ -32,24 +32,93 @@
 #include "lo-ieee.h"
 #include "lo-sysdep.h"
 
-extern OCTINTERP_API void sysdep_init (void);
+namespace octave
+{
+  extern OCTINTERP_API void sysdep_init (void);
+
+  extern OCTINTERP_API void set_application_id (void);
+
+  extern OCTINTERP_API void sysdep_cleanup (void);
 
-extern OCTINTERP_API void set_application_id (void);
+  extern OCTINTERP_API void raw_mode (bool, bool wait = true);
+
+  extern OCTINTERP_API FILE * popen (const char *command, const char *mode);
+
+  extern OCTINTERP_API int pclose (FILE *f);
+
+  extern OCTINTERP_API int kbhit (bool wait = true);
+
+  extern OCTINTERP_API std::string get_P_tmpdir (void);
 
-extern OCTINTERP_API void sysdep_cleanup (void);
+  extern OCTINTERP_API bool same_file_internal (const std::string&,
+                                                const std::string&);
+}
+
+#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
 
-extern OCTINTERP_API void raw_mode (bool, bool wait = true);
+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 ();
+}
 
-extern OCTINTERP_API FILE * octave_popen (const char *command,
-                                          const char *mode);
+OCTAVE_DEPRECATED (5, "use 'octave::sysdep_cleanup' instead")
+inline void
+sysdep_cleanup (void)
+{
+  octave::sysdep_cleanup ();
+}
 
-extern OCTINTERP_API int octave_pclose (FILE *f);
+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);
+}
 
-extern OCTINTERP_API int octave_kbhit (bool wait = true);
+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);
+}
 
-extern OCTINTERP_API std::string get_P_tmpdir (void);
+OCTAVE_DEPRECATED (5, "use 'octave::get_P_tmpdir' instead")
+inline std::string
+get_P_tmpdir (void)
+{
+  return octave::get_P_tmpdir ();
+}
 
-extern OCTINTERP_API bool same_file_internal (const std::string&,
-                                              const std::string&);
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/text-engine.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,42 @@
+/*
+
+Copyright (C) 2013-2018 Michael Goffioul
+
+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 "text-engine.h"
+#include "oct-tex-symbols.cc"
+
+namespace octave
+{
+  uint32_t
+  text_element_symbol::get_symbol_code (void) const
+  {
+    uint32_t code = invalid_code;
+
+    if (0 <= symbol && symbol < num_symbol_codes)
+      code = symbol_codes[symbol][0];
+
+    return code;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/text-engine.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,508 @@
+/*
+
+Copyright (C) 2009-2018 Michael Goffioul
+
+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_text_engine_h)
+#define octave_text_engine_h 1
+
+#include "octave-config.h"
+
+#include <memory>
+#include <string>
+
+#include "base-list.h"
+#include "caseless-str.h"
+#include "dMatrix.h"
+
+namespace octave
+{
+  class text_element;
+  class text_element_string;
+  class text_element_symbol;
+  class text_element_list;
+  class text_element_subscript;
+  class text_element_superscript;
+  class text_element_combined;
+  class text_element_fontname;
+  class text_element_fontsize;
+  class text_element_fontstyle;
+  class text_element_color;
+
+  class text_processor;
+
+  class
+  OCTINTERP_API
+  text_element
+  {
+  public:
+    text_element (void) { }
+
+    virtual ~text_element (void) = default;
+
+    virtual void accept (text_processor& p) = 0;
+
+  private:
+    text_element (const text_element&);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_string : public text_element
+  {
+  public:
+    text_element_string (const std::string& s = "")
+      : text_element (), str (s) { }
+
+    ~text_element_string (void) = default;
+
+    std::string string_value (void) const { return str; }
+
+    void accept (text_processor& p);
+
+  private:
+    std::string str;
+
+  private:
+    text_element_string (const text_element_string &);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_symbol : public text_element
+  {
+  public:
+    enum { invalid_code = 0xFFFFFFFFU };
+
+  public:
+    text_element_symbol (int sym)
+      : text_element (), symbol (sym) { }
+
+    ~text_element_symbol (void) = default;
+
+    int get_symbol (void) const { return symbol; }
+
+    uint32_t get_symbol_code (void) const;
+
+    void accept (text_processor& p);
+
+  private:
+    int symbol;
+  };
+
+  class
+  OCTINTERP_API
+  text_element_list
+    : public text_element, public base_list<text_element *>
+  {
+  public:
+    text_element_list (void)
+      : text_element (), base_list<text_element*> () { }
+
+    text_element_list (text_element *e)
+      : text_element (), base_list<text_element*> ()
+    {
+      push_back (e);
+    }
+
+    ~text_element_list (void)
+      {
+        while (! empty ())
+          {
+            auto it = begin ();
+            delete (*it);
+            erase (it);
+          }
+      }
+
+    void accept (text_processor& p);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_subscript : public text_element
+  {
+  public:
+    text_element_subscript (text_element *e)
+      : text_element (), elem (e) { }
+
+    text_element_subscript (char c)
+      : text_element ()
+      { elem = new text_element_string (std::string (1, c)); }
+
+    ~text_element_subscript (void)
+      { delete elem; }
+
+    void accept (text_processor& p);
+
+    text_element * get_element (void) { return elem; }
+
+  private:
+    text_element *elem;
+
+  private:
+    text_element_subscript (void);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_superscript : public text_element
+  {
+  public:
+    text_element_superscript (text_element *e)
+      : text_element (), elem (e) { }
+
+    text_element_superscript (char c)
+      : text_element ()
+      { elem = new text_element_string (std::string (1, c)); }
+
+    ~text_element_superscript (void)
+      { delete elem; }
+
+    void accept (text_processor& p);
+
+    text_element * get_element (void) { return elem; }
+
+  private:
+    text_element *elem;
+
+  private:
+    text_element_superscript (void);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_combined : public text_element_list
+  {
+  public:
+    text_element_combined (text_element *e)
+      : text_element_list (e) { }
+
+    text_element_combined (text_element *e1, text_element *e2)
+      : text_element_list(e1)
+      { push_back (e2); }
+
+    void accept (text_processor& p);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_fontstyle : public text_element
+  {
+  public:
+    enum fontstyle
+    {
+      normal,
+      bold,
+      italic,
+      oblique
+    };
+
+    text_element_fontstyle (fontstyle st)
+      : text_element (), style (st) { }
+
+    ~text_element_fontstyle (void) = default;
+
+    fontstyle get_fontstyle (void) const { return style; }
+
+    void accept (text_processor& p);
+
+  private:
+    fontstyle style;
+
+  private:
+    text_element_fontstyle (void);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_fontname : public text_element
+  {
+  public:
+    text_element_fontname (const std::string& fname)
+      : text_element (), name (fname) { }
+
+    ~text_element_fontname (void) = default;
+
+    const std::string& get_fontname (void) const { return name; }
+
+    void accept (text_processor& p);
+
+  private:
+    std::string name;
+
+  private:
+    text_element_fontname (void);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_fontsize : public text_element
+  {
+  public:
+    text_element_fontsize (double fsize)
+      : text_element (), size (fsize) { }
+
+    ~text_element_fontsize (void) = default;
+
+    double get_fontsize (void) const { return size; }
+
+    void accept (text_processor& p);
+
+  private:
+    double size;
+
+  private:
+    text_element_fontsize (void);
+  };
+
+  class
+  OCTINTERP_API
+  text_element_color : public text_element
+  {
+  public:
+    text_element_color (double r, double g, double b)
+      : text_element (), rgb (1, 3, 0.0)
+      {
+        rgb(0) = r;
+        rgb(1) = g;
+        rgb(2) = b;
+      }
+
+    text_element_color (const std::string& cname)
+      : text_element (), rgb (1, 3, 0.0)
+      {
+#define ASSIGN_COLOR(r,g,b) { rgb(0) = r; rgb(1) = g; rgb(2) = b; }
+        if (cname == "red") ASSIGN_COLOR(1, 0, 0)
+        else if (cname == "green") ASSIGN_COLOR(0, 1, 0)
+        else if (cname == "yellow") ASSIGN_COLOR(1, 1, 0)
+        else if (cname == "magenta") ASSIGN_COLOR(1, 0, 1)
+        else if (cname == "blue") ASSIGN_COLOR(0, 0, 1)
+        else if (cname == "black") ASSIGN_COLOR(0, 0, 0)
+        else if (cname == "white") ASSIGN_COLOR(1, 1, 1)
+        else if (cname == "gray") ASSIGN_COLOR(.5, .5, .5)
+        else if (cname == "darkGreen") ASSIGN_COLOR(0, .5, 0)
+        else if (cname == "orange") ASSIGN_COLOR(1, .65, 0)
+        else if (cname == "lightBlue") ASSIGN_COLOR(0.68, .85, .9)
+#undef ASSIGN_COLOR
+      }
+
+    ~text_element_color (void) = default;
+
+    Matrix get_color (void) { return rgb; }
+
+    void accept (text_processor& p);
+
+  private:
+    Matrix rgb;
+  };
+
+  class
+  OCTINTERP_API
+  text_processor
+  {
+  public:
+    virtual void visit (text_element_string& e) = 0;
+
+    virtual void visit (text_element_symbol&) { }
+
+    virtual void visit (text_element_list& e)
+    {
+      for (auto& el_p : e)
+        {
+          el_p->accept (*this);
+        }
+    }
+
+    virtual void visit (text_element_subscript& e)
+    { e.get_element ()->accept (*this); }
+
+    virtual void visit (text_element_superscript& e)
+    { e.get_element ()->accept (*this); }
+
+    virtual void visit (text_element_combined&) { }
+
+    virtual void visit (text_element_fontstyle&) { }
+
+    virtual void visit (text_element_fontname&) { }
+
+    virtual void visit (text_element_fontsize&) { }
+
+    virtual void visit (text_element_color&) { }
+
+    virtual void reset (void) { }
+
+  protected:
+    text_processor (void) { }
+
+    virtual ~text_processor (void) = default;
+  };
+
+#define TEXT_ELEMENT_ACCEPT(cls)                \
+  inline void                                   \
+  cls::accept (text_processor& p)               \
+  {                                             \
+    p.visit (*this);                            \
+  }
+
+  TEXT_ELEMENT_ACCEPT(text_element_string)
+  TEXT_ELEMENT_ACCEPT(text_element_symbol)
+  TEXT_ELEMENT_ACCEPT(text_element_list)
+  TEXT_ELEMENT_ACCEPT(text_element_subscript)
+  TEXT_ELEMENT_ACCEPT(text_element_superscript)
+  TEXT_ELEMENT_ACCEPT(text_element_combined)
+  TEXT_ELEMENT_ACCEPT(text_element_fontstyle)
+  TEXT_ELEMENT_ACCEPT(text_element_fontname)
+  TEXT_ELEMENT_ACCEPT(text_element_fontsize)
+  TEXT_ELEMENT_ACCEPT(text_element_color)
+
+  class
+  OCTINTERP_API
+  text_parser
+  {
+  public:
+    text_parser (void) { }
+
+    virtual ~text_parser (void) = default;
+
+    virtual text_element * parse (const std::string& s) = 0;
+
+  public:
+    static text_element * parse (const std::string& s,
+                                 const caseless_str& interpreter);
+  };
+
+  class
+  OCTINTERP_API
+  text_parser_none : public text_parser
+  {
+  public:
+    text_parser_none (void) : text_parser () { }
+
+    ~text_parser_none (void) = default;
+
+    // FIXME: is it possible to use reference counting to manage the
+    // memory for the object returned by the text parser?  That would be
+    // preferable to having to know when and where to delete the object it
+    // creates...
+
+    text_element * parse (const std::string& s)
+    {
+      return new text_element_string (s);
+    }
+  };
+
+  class
+  OCTINTERP_API
+  text_parser_tex : public text_parser
+  {
+  public:
+    text_parser_tex (void)
+      : text_parser (), scanner (nullptr), buffer_state (nullptr), result (nullptr)
+      { }
+
+    ~text_parser_tex (void)
+      { destroy_lexer (); }
+
+    text_element * parse (const std::string& s);
+
+    void * get_scanner (void) { return scanner; }
+
+    void set_parse_result (text_element *e) { result = e; }
+
+    text_element * get_parse_result (void) { return result; }
+
+  private:
+    bool init_lexer (const std::string& s);
+
+    void destroy_lexer (void);
+
+  private:
+    void *scanner;
+
+    void *buffer_state;
+
+    text_element *result;
+  };
+
+  inline text_element*
+  text_parser::parse (const std::string& s, const caseless_str& interpreter)
+  {
+    std::unique_ptr<text_parser> parser;
+
+    if (interpreter.compare ("tex"))
+      parser.reset (new text_parser_tex ());
+    else
+      parser.reset (new text_parser_none ());
+
+    return parser->parse (s);
+  }
+}
+
+#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.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/text-renderer.h	Thu Dec 20 17:18:56 2018 -0500
@@ -34,11 +34,10 @@
 #include "dMatrix.h"
 #include "uint8NDArray.h"
 
-#include "txt-eng.h"
-
 namespace octave
 {
   class base_text_renderer;
+  class text_element;
 
   class
   OCTINTERP_API
--- a/libinterp/corefcn/toplev.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/toplev.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,8 +26,8 @@
 
 #include <cerrno>
 #include <cstdlib>
+
 #include <new>
-
 #include <sstream>
 #include <string>
 
@@ -83,8 +83,8 @@
 the Free Software Foundation, either version 3 of the License, or\n\
 (at your option) any later version.\n\
 \n\
-GNU Octave is distributed in the hope that it will be useful,\n\
-but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+GNU Octave is distributed in the hope that it will be useful, but\n\
+WITHOUT ANY WARRANTY; without even the implied warranty of\n\
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
 GNU General Public License for more details.\n\
 \n\
@@ -347,12 +347,6 @@
 @seealso{computer}
 @end deftypefn */)
 {
-#if defined (ENABLE_DYNAMIC_LINKING)
-  bool octave_supports_dynamic_linking = true;
-#else
-  bool octave_supports_dynamic_linking = false;
-#endif
-
   static octave_scalar_map config;
   static octave_scalar_map build_env;
   static octave_scalar_map build_features;
@@ -382,12 +376,6 @@
            { "ENABLE_DOCS", false },
 #endif
 
-#if defined (ENABLE_DYNAMIC_LINKING)
-           { "ENABLE_DYNAMIC_LINKING", true },
-#else
-           { "ENABLE_DYNAMIC_LINKING", false },
-#endif
-
 #if defined (OCTAVE_ENABLE_FLOAT_TRUNCATE)
            { "ENABLE_FLOAT_TRUNCATE", true },
 #else
@@ -559,10 +547,10 @@
            { "QT_CPPFLAGS", octave::build_env::QT_CPPFLAGS },
            { "QT_LDFLAGS", octave::build_env::QT_LDFLAGS },
            { "QT_LIBS", octave::build_env::QT_LIBS },
+           { "QT_OPENGL_LIBS", octave::build_env::QT_OPENGL_LIBS },
            { "RANLIB", octave::build_env::RANLIB },
            { "RDYNAMIC_FLAG", octave::build_env::RDYNAMIC_FLAG },
            { "READLINE_LIBS", octave::build_env::READLINE_LIBS },
-           { "SED", octave::build_env::SED },
            { "SHARED_LIBS", octave::build_env::SHARED_LIBS },
            { "SH_LD", octave::build_env::SH_LD },
            { "SH_LDFLAGS", octave::build_env::SH_LDFLAGS },
@@ -608,8 +596,6 @@
       config.assign ("mac", octave_value (mac_system));
       config.assign ("windows", octave_value (windows_system));
 
-      config.assign ("dld", octave_value (octave_supports_dynamic_linking));
-
       octave::mach_info::float_format ff = octave::mach_info::native_float_format ();
       config.assign ("float_format",
                      octave_value (octave::mach_info::float_format_as_string (ff)));
--- a/libinterp/corefcn/tsearch.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/tsearch.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,7 +50,7 @@
     return (a > c ? c : a);
 }
 
-#define REF(x,k,i) x(static_cast<octave_idx_type>(elem((k), (i))) - 1)
+#define REF(x,k,i) x(static_cast<octave_idx_type> (elem((k), (i))) - 1)
 
 // for large data set the algorithm is very slow
 // one should presort (how?) either the elements of the points of evaluation
--- a/libinterp/corefcn/txt-eng.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
-
-Copyright (C) 2013-2018 Michael Goffioul
-
-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 "txt-eng.h"
-#include "oct-tex-symbols.cc"
-
-uint32_t
-text_element_symbol::get_symbol_code (void) const
-{
-  uint32_t code = invalid_code;
-
-  if (0 <= symbol && symbol < num_symbol_codes)
-    code = symbol_codes[symbol][0];
-
-  return code;
-}
--- a/libinterp/corefcn/txt-eng.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/txt-eng.h	Thu Dec 20 17:18:56 2018 -0500
@@ -1,6 +1,6 @@
 /*
 
-Copyright (C) 2009-2018 Michael Goffioul
+Copyright (C) 2018 John W. Eaton
 
 This file is part of Octave.
 
@@ -25,430 +25,8 @@
 
 #include "octave-config.h"
 
-#include <memory>
-#include <string>
-
-#include "base-list.h"
-#include "caseless-str.h"
-#include "dMatrix.h"
-
-class text_element;
-class text_element_string;
-class text_element_symbol;
-class text_element_list;
-class text_element_subscript;
-class text_element_superscript;
-class text_element_combined;
-class text_element_fontname;
-class text_element_fontsize;
-class text_element_fontstyle;
-class text_element_color;
-
-class text_processor;
-
-class
-OCTINTERP_API
-text_element
-{
-public:
-  text_element (void) { }
-
-  virtual ~text_element (void) = default;
-
-  virtual void accept (text_processor& p) = 0;
-
-private:
-  text_element (const text_element&);
-};
-
-class
-OCTINTERP_API
-text_element_string : public text_element
-{
-public:
-  text_element_string (const std::string& s = "")
-    : text_element (), str (s) { }
-
-  ~text_element_string (void) = default;
-
-  std::string string_value (void) const { return str; }
-
-  void accept (text_processor& p);
-
-private:
-  std::string str;
-
-private:
-  text_element_string (const text_element_string &);
-};
-
-class
-OCTINTERP_API
-text_element_symbol : public text_element
-{
-public:
-  enum { invalid_code = 0xFFFFFFFFU };
-
-public:
-  text_element_symbol (int sym)
-    : text_element (), symbol (sym) { }
-
-  ~text_element_symbol (void) = default;
-
-  int get_symbol (void) const { return symbol; }
-
-  uint32_t get_symbol_code (void) const;
-
-  void accept (text_processor& p);
-
-private:
-  int symbol;
-};
-
-class
-OCTINTERP_API
-text_element_list
-  : public text_element, public octave::base_list<text_element *>
-{
-public:
-  text_element_list (void)
-    : text_element (), octave::base_list<text_element*> () { }
-
-  text_element_list (text_element *e)
-    : text_element (), octave::base_list<text_element*> ()
-  { push_back (e); }
-
-  ~text_element_list (void)
-  {
-    while (! empty ())
-      {
-        iterator it = begin ();
-        delete (*it);
-        erase (it);
-      }
-  }
-
-  void accept (text_processor& p);
-};
-
-class
-OCTINTERP_API
-text_element_subscript : public text_element
-{
-public:
-  text_element_subscript (text_element *e)
-    : text_element (), elem (e) { }
-
-  text_element_subscript (char c)
-    : text_element ()
-  { elem = new text_element_string (std::string (1, c)); }
-
-  ~text_element_subscript (void)
-  { delete elem; }
-
-  void accept (text_processor& p);
-
-  text_element * get_element (void) { return elem; }
-
-private:
-  text_element *elem;
-
-private:
-  text_element_subscript (void);
-};
-
-class
-OCTINTERP_API
-text_element_superscript : public text_element
-{
-public:
-  text_element_superscript (text_element *e)
-    : text_element (), elem (e) { }
-
-  text_element_superscript (char c)
-    : text_element ()
-  { elem = new text_element_string (std::string (1, c)); }
-
-  ~text_element_superscript (void)
-  { delete elem; }
-
-  void accept (text_processor& p);
-
-  text_element * get_element (void) { return elem; }
-
-private:
-  text_element *elem;
-
-private:
-  text_element_superscript (void);
-};
-
-class
-OCTINTERP_API
-text_element_combined : public text_element_list
-{
-public:
-  text_element_combined (text_element *e)
-    : text_element_list (e) { }
-
-  text_element_combined (text_element *e1, text_element *e2)
-    : text_element_list(e1)
-  { push_back (e2); }
-
-  void accept (text_processor& p);
-};
-
-class
-OCTINTERP_API
-text_element_fontstyle : public text_element
-{
-public:
-  enum fontstyle
-  {
-    normal,
-    bold,
-    italic,
-    oblique
-  };
-
-  text_element_fontstyle (fontstyle st)
-    : text_element (), style (st) { }
-
-  ~text_element_fontstyle (void) = default;
-
-  fontstyle get_fontstyle (void) const { return style; }
-
-  void accept (text_processor& p);
-
-private:
-  fontstyle style;
-
-private:
-  text_element_fontstyle (void);
-};
-
-class
-OCTINTERP_API
-text_element_fontname : public text_element
-{
-public:
-  text_element_fontname (const std::string& fname)
-    : text_element (), name (fname) { }
-
-  ~text_element_fontname (void) = default;
+#warning "txt-eng.h has been deprecated; use text-engine instead"
 
-  const std::string& get_fontname (void) const { return name; }
-
-  void accept (text_processor& p);
-
-private:
-  std::string name;
-
-private:
-  text_element_fontname (void);
-};
-
-class
-OCTINTERP_API
-text_element_fontsize : public text_element
-{
-public:
-  text_element_fontsize (double fsize)
-    : text_element (), size (fsize) { }
-
-  ~text_element_fontsize (void) = default;
-
-  double get_fontsize (void) const { return size; }
-
-  void accept (text_processor& p);
-
-private:
-  double size;
-
-private:
-  text_element_fontsize (void);
-};
-
-class
-OCTINTERP_API
-text_element_color : public text_element
-{
-public:
-  text_element_color (double r, double g, double b)
-    : text_element (), rgb (1, 3, 0.0)
-  {
-    rgb(0) = r;
-    rgb(1) = g;
-    rgb(2) = b;
-  }
-
-  text_element_color (const std::string& cname)
-    : text_element (), rgb (1, 3, 0.0)
-  {
-#define ASSIGN_COLOR(r,g,b) { rgb(0) = r; rgb(1) = g; rgb(2) = b; }
-    if (cname == "red") ASSIGN_COLOR(1, 0, 0)
-      else if (cname == "green") ASSIGN_COLOR(0, 1, 0)
-        else if (cname == "yellow") ASSIGN_COLOR(1, 1, 0)
-          else if (cname == "magenta") ASSIGN_COLOR(1, 0, 1)
-            else if (cname == "blue") ASSIGN_COLOR(0, 0, 1)
-              else if (cname == "black") ASSIGN_COLOR(0, 0, 0)
-                else if (cname == "white") ASSIGN_COLOR(1, 1, 1)
-                  else if (cname == "gray") ASSIGN_COLOR(.5, .5, .5)
-                    else if (cname == "darkGreen") ASSIGN_COLOR(0, .5, 0)
-                      else if (cname == "orange") ASSIGN_COLOR(1, .65, 0)
-                        else if (cname == "lightBlue") ASSIGN_COLOR(0.68, .85, .9)
-#undef ASSIGN_COLOR
-  }
-
-  ~text_element_color (void) = default;
-
-  Matrix get_color (void) { return rgb; }
-
-  void accept (text_processor& p);
-
-private:
-  Matrix rgb;
-};
-
-class
-OCTINTERP_API
-text_processor
-{
-public:
-  virtual void visit (text_element_string& e) = 0;
-
-  virtual void visit (text_element_symbol&) { }
-
-  virtual void visit (text_element_list& e)
-  {
-    for (auto& el_p : e)
-      {
-        el_p->accept (*this);
-      }
-  }
-
-  virtual void visit (text_element_subscript& e)
-  { e.get_element ()->accept (*this); }
-
-  virtual void visit (text_element_superscript& e)
-  { e.get_element ()->accept (*this); }
-
-  virtual void visit (text_element_combined&) { }
-
-  virtual void visit (text_element_fontstyle&) { }
-
-  virtual void visit (text_element_fontname&) { }
-
-  virtual void visit (text_element_fontsize&) { }
-
-  virtual void visit (text_element_color&) { }
-
-  virtual void reset (void) { }
-
-protected:
-  text_processor (void) { }
-
-  virtual ~text_processor (void) = default;
-};
-
-#define TEXT_ELEMENT_ACCEPT(cls)                \
-  inline void                                   \
-  cls::accept (text_processor& p)               \
-  {                                             \
-    p.visit (*this);                            \
-  }
-
-TEXT_ELEMENT_ACCEPT(text_element_string)
-TEXT_ELEMENT_ACCEPT(text_element_symbol)
-TEXT_ELEMENT_ACCEPT(text_element_list)
-TEXT_ELEMENT_ACCEPT(text_element_subscript)
-TEXT_ELEMENT_ACCEPT(text_element_superscript)
-TEXT_ELEMENT_ACCEPT(text_element_combined)
-TEXT_ELEMENT_ACCEPT(text_element_fontstyle)
-TEXT_ELEMENT_ACCEPT(text_element_fontname)
-TEXT_ELEMENT_ACCEPT(text_element_fontsize)
-TEXT_ELEMENT_ACCEPT(text_element_color)
-
-class
-OCTINTERP_API
-text_parser
-{
-public:
-  text_parser (void) { }
-
-  virtual ~text_parser (void) = default;
-
-  virtual text_element * parse (const std::string& s) = 0;
-
-public:
-  static text_element * parse (const std::string& s,
-                               const caseless_str& interpreter);
-};
-
-class
-OCTINTERP_API
-text_parser_none : public text_parser
-{
-public:
-  text_parser_none (void) : text_parser () { }
-
-  ~text_parser_none (void) = default;
-
-  // FIXME: is it possible to use reference counting to manage the
-  // memory for the object returned by the text parser?  That would be
-  // preferable to having to know when and where to delete the object it
-  // creates...
-
-  text_element * parse (const std::string& s)
-  {
-    return new text_element_string (s);
-  }
-};
-
-class
-OCTINTERP_API
-text_parser_tex : public text_parser
-{
-public:
-  text_parser_tex (void)
-    : text_parser (), scanner (nullptr), buffer_state (nullptr), result (nullptr)
-  { }
-
-  ~text_parser_tex (void)
-  { destroy_lexer (); }
-
-  text_element * parse (const std::string& s);
-
-  void * get_scanner (void) { return scanner; }
-
-  void set_parse_result (text_element *e) { result = e; }
-
-  text_element * get_parse_result (void) { return result; }
-
-private:
-  bool init_lexer (const std::string& s);
-
-  void destroy_lexer (void);
-
-private:
-  void *scanner;
-
-  void *buffer_state;
-
-  text_element *result;
-};
-
-inline text_element*
-text_parser::parse (const std::string& s, const caseless_str& interpreter)
-{
-  std::unique_ptr<text_parser> parser;
-
-  if (interpreter.compare ("tex"))
-    parser.reset (new text_parser_tex ());
-  else
-    parser.reset (new text_parser_none ());
-
-  return parser->parse (s);
-}
+#include "text-engine.h"
 
 #endif
--- a/libinterp/corefcn/typecast.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/typecast.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,6 +25,7 @@
 #  include "config.h"
 #endif
 
+#include <algorithm>
 #include <limits>
 
 #include "mx-base.h"
@@ -227,6 +228,8 @@
            array.class_name ().c_str ());
 
   std::string numclass = args(1).string_value ();
+  std::transform (numclass.begin (), numclass.end (), numclass.begin (),
+                  tolower);
 
   if (numclass.size () == 0)
     ;
@@ -439,6 +442,13 @@
 %!assert (bitpack (zeros (1, 64,  "logical"), "single complex"), single (0))
 %!assert (bitpack (zeros (1, 128, "logical"), "double complex"), double (0))
 
+%!test <54931>
+%! x = false (1, 32);
+%! x(1) = true;
+%! assert (bitpack (x, "uint32"), uint32 (1));
+%! x([1, 9]) = true;
+%! assert (bitpack (x, "uint32"), uint32 (257));
+
 %!error bitpack ()
 %!error bitpack (1)
 %!error bitpack (1, 2, 3)
--- a/libinterp/corefcn/url-handle-manager.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/url-handle-manager.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -48,7 +48,7 @@
     // part.  To avoid running out of integers, we recycle the integer
     // part but tack on a new random part each time.
 
-    free_list_iterator p = handle_free_list.begin ();
+    auto p = handle_free_list.begin ();
 
     if (p != handle_free_list.end ())
       {
@@ -69,7 +69,7 @@
   {
     if (h.ok ())
       {
-        iterator p = handle_map.find (h);
+        auto p = handle_map.find (h);
 
         if (p == handle_map.end ())
           error ("url_handle_manager::free: invalid object %g", h.value ());
--- a/libinterp/corefcn/urlwrite.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/urlwrite.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,11 +31,11 @@
 #include <string>
 #include <fstream>
 #include <iomanip>
-#include <iostream>
 
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-handle.h"
 #include "glob-match.h"
@@ -637,8 +637,11 @@
         }
       else
         {
+          std::string ascii_fname = octave::sys::get_ASCII_filename (file);
+
           // FIXME: Does ascii mode need to be flagged here?
-          std::ifstream ifile (file.c_str (), std::ios::in | std::ios::binary);
+          std::ifstream ifile (ascii_fname.c_str (),
+                               std::ios::in | std::ios::binary);
 
           if (! ifile.is_open ())
             error ("__ftp_mput__: unable to open file");
--- a/libinterp/corefcn/utils.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/utils.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,8 +29,8 @@
 #include <cstring>
 
 #include <fstream>
-#include <iostream>
 #include <limits>
+#include <ostream>
 #include <string>
 
 #include "dir-ops.h"
@@ -48,11 +48,11 @@
 #include "vasprintf-wrapper.h"
 
 #include "Cell.h"
-#include "defaults.h"
 #include "defun.h"
 #include "dirfns.h"
 #include "error.h"
 #include "errwarn.h"
+#include "graphics.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
 #include "lex.h"
@@ -68,31 +68,35 @@
 #include "utils.h"
 #include "variables.h"
 
-// Return TRUE if S is a valid identifier.
-
-bool
-valid_identifier (const char *s)
+namespace octave
 {
-  if (! s || ! (isalpha (*s) || *s == '_' || *s == '$'))
-    return false;
+  // Return TRUE if S is a valid identifier.
 
-  while (*++s != '\0')
-    if (! (isalnum (*s) || *s == '_' || *s == '$'))
+  bool valid_identifier (const char *s)
+  {
+    if (! s || ! (isalpha (*s) || *s == '_'))
       return false;
 
-  return true;
-}
+    while (*++s != '\0')
+      if (! (isalnum (*s) || *s == '_'))
+        return false;
 
-bool
-valid_identifier (const std::string& s)
-{
-  return valid_identifier (s.c_str ());
+    return true;
+  }
+
+  bool valid_identifier (const std::string& s)
+  {
+    return valid_identifier (s.c_str ());
+  }
 }
 
 DEFUN (isvarname, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} isvarname (@var{name})
 Return true if @var{name} is a valid variable name.
+
+A valid variable name is composed of letters, digits, and underscores ("_"),
+and the first character must not be a digit.
 @seealso{iskeyword, exist, who}
 @end deftypefn */)
 {
@@ -105,7 +109,8 @@
     {
       std::string varname = args(0).string_value ();
 
-      retval = valid_identifier (varname) && ! octave::is_keyword (varname);
+      retval = (octave::valid_identifier (varname)
+                && ! octave::iskeyword (varname));
     }
 
   return retval;
@@ -124,161 +129,154 @@
 %!error isvarname ("foo", "bar")
 */
 
-// Return TRUE if F and G are both names for the same file.
-
-bool
-same_file (const std::string& f, const std::string& g)
+namespace octave
 {
-  return same_file_internal (f, g);
-}
+  // Return TRUE if F and G are both names for the same file.
 
-int
-almost_match (const std::string& std, const std::string& s, int min_match_len,
-              int case_sens)
-{
-  int stdlen = std.length ();
-  int slen = s.length ();
+  bool same_file (const std::string& f, const std::string& g)
+  {
+    return same_file_internal (f, g);
+  }
+
+  int almost_match (const std::string& std, const std::string& s,
+                    int min_match_len, int case_sens)
+  {
+    int stdlen = std.length ();
+    int slen = s.length ();
 
-  return (slen <= stdlen
-          && slen >= min_match_len
-          && (case_sens
-              ? (strncmp (std.c_str (), s.c_str (), slen) == 0)
-              : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0)));
-}
+    return (slen <= stdlen
+            && slen >= min_match_len
+            && (case_sens
+                ? (strncmp (std.c_str (), s.c_str (), slen) == 0)
+                : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0)));
+  }
 
-// Ugh.
+  // Ugh.
 
-int
-keyword_almost_match (const char * const *std, int *min_len,
-                      const std::string& s,
-                      int min_toks_to_match, int max_toks)
-{
-  int status = 0;
-  int tok_count = 0;
-  int toks_matched = 0;
+  int keyword_almost_match (const char * const *std, int *min_len,
+                            const std::string& s,
+                            int min_toks_to_match, int max_toks)
+  {
+    int status = 0;
+    int tok_count = 0;
+    int toks_matched = 0;
 
-  if (s.empty () || max_toks < 1)
-    return status;
-
-  char *kw = strsave (s.c_str ());
+    if (s.empty () || max_toks < 1)
+      return status;
 
-  char *t = kw;
-  while (*t != '\0')
-    {
-      if (*t == '\t')
-        *t = ' ';
-      t++;
-    }
+    char *kw = strsave (s.c_str ());
 
-  char *beg = kw;
-  while (*beg == ' ')
-    beg++;
+    char *t = kw;
+    while (*t != '\0')
+      {
+        if (*t == '\t')
+          *t = ' ';
+        t++;
+      }
 
-  if (*beg == '\0')
-    return status;
+    char *beg = kw;
+    while (*beg == ' ')
+      beg++;
 
-  const char **to_match = new const char * [max_toks + 1];
-  const char * const *s1 = std;
-  const char **s2 = to_match;
+    if (*beg == '\0')
+      return status;
 
-  if (! s1 || ! s2)
-    goto done;
+    const char **to_match = new const char * [max_toks + 1];
+    const char * const *s1 = std;
+    const char **s2 = to_match;
 
-  s2[tok_count] = beg;
-  char *end;
-  while ((end = strchr (beg, ' ')) != nullptr)
-    {
-      *end = '\0';
-      beg = end + 1;
+    if (! s1 || ! s2)
+      goto done;
 
-      while (*beg == ' ')
-        beg++;
+    s2[tok_count] = beg;
+    char *end;
+    while ((end = strchr (beg, ' ')) != nullptr)
+      {
+        *end = '\0';
+        beg = end + 1;
 
-      if (*beg == '\0')
-        break;
+        while (*beg == ' ')
+          beg++;
 
-      tok_count++;
-      if (tok_count >= max_toks)
-        goto done;
+        if (*beg == '\0')
+          break;
 
-      s2[tok_count] = beg;
-    }
-  s2[tok_count+1] = nullptr;
+        tok_count++;
+        if (tok_count >= max_toks)
+          goto done;
 
-  s2 = to_match;
+        s2[tok_count] = beg;
+      }
+    s2[tok_count+1] = nullptr;
 
-  for (;;)
-    {
-      if (! almost_match (*s1, *s2, min_len[toks_matched], 0))
-        goto done;
+    s2 = to_match;
 
-      toks_matched++;
+    for (;;)
+      {
+        if (! almost_match (*s1, *s2, min_len[toks_matched], 0))
+          goto done;
 
-      s1++;
-      s2++;
+        toks_matched++;
 
-      if (! *s2)
-        {
-          status = (toks_matched >= min_toks_to_match);
-          goto done;
-        }
+        s1++;
+        s2++;
+
+        if (! *s2)
+          {
+            status = (toks_matched >= min_toks_to_match);
+            goto done;
+          }
 
-      if (! *s1)
-        goto done;
-    }
+        if (! *s1)
+          goto done;
+      }
 
-done:
+  done:
 
-  delete [] kw;
-  delete [] to_match;
+    delete [] kw;
+    delete [] to_match;
 
-  return status;
-}
+    return status;
+  }
 
-int
-empty_arg (const char * /* name */, octave_idx_type nr, octave_idx_type nc)
-{
-  return (nr == 0 || nc == 0);
-}
+  // See if the given file is in the path.
 
-// See if the given file is in the path.
+  std::string search_path_for_file (const std::string& path,
+                                    const string_vector& names)
+  {
+    directory_path p (path);
 
-std::string
-search_path_for_file (const std::string& path, const string_vector& names)
-{
-  octave::directory_path p (path);
+    return sys::env::make_absolute (p.find_first_of (names.std_list ()));
+  }
+
+  // Find all locations of the given file in the path.
 
-  return octave::sys::env::make_absolute (p.find_first_of (names.std_list ()));
-}
+  string_vector search_path_for_all_files (const std::string& path,
+                                           const string_vector& names)
+  {
+    directory_path p (path);
 
-// Find all locations of the given file in the path.
+    string_vector sv = p.find_all_first_of (names.std_list ());
 
-string_vector
-search_path_for_all_files (const std::string& path, const string_vector& names)
-{
-  octave::directory_path p (path);
+    octave_idx_type len = sv.numel ();
 
-  string_vector sv = p.find_all_first_of (names.std_list ());
+    for (octave_idx_type i = 0; i < len; i++)
+      sv[i] = sys::env::make_absolute (sv[i]);
 
-  octave_idx_type len = sv.numel ();
-
-  for (octave_idx_type i = 0; i < len; i++)
-    sv[i] = octave::sys::env::make_absolute (sv[i]);
+    return sv;
+  }
 
-  return sv;
-}
+  static string_vector make_absolute (const string_vector& sv)
+  {
+    octave_idx_type len = sv.numel ();
+
+    string_vector retval (len);
 
-static string_vector
-make_absolute (const string_vector& sv)
-{
-  octave_idx_type len = sv.numel ();
+    for (octave_idx_type i = 0; i < len; i++)
+      retval[i] = sys::env::make_absolute (sv[i]);
 
-  string_vector retval (len);
-
-  for (octave_idx_type i = 0; i < len; i++)
-    retval[i] = octave::sys::env::make_absolute (sv[i]);
-
-  return retval;
+    return retval;
+  }
 }
 
 DEFMETHOD (file_in_loadpath, interp, args, ,
@@ -325,7 +323,7 @@
       if (opt != "all")
         error (R"(file_in_loadpath: "all" is only valid second argument)");
 
-      return ovl (Cell (make_absolute (lp.find_all_first_of (names))));
+      return ovl (Cell (octave::make_absolute (lp.find_all_first_of (names))));
     }
 }
 
@@ -388,7 +386,7 @@
     error ("file_in_path: FILE argument must not be empty");
 
   if (nargin == 2)
-    return ovl (search_path_for_file (path, names));
+    return ovl (octave::search_path_for_file (path, names));
   else
     {
       std::string opt = args(2).xstring_value ("file_in_path: optional third argument must be a string");
@@ -396,7 +394,7 @@
       if (opt != "all")
         error (R"(file_in_path: "all" is only valid third argument)");
 
-      return ovl (Cell (make_absolute (search_path_for_all_files (path, names))));
+      return ovl (Cell (octave::make_absolute (octave::search_path_for_all_files (path, names))));
     }
 }
 
@@ -422,323 +420,247 @@
 %!error file_in_path (path (), "plot.m", "bar")
 */
 
-std::string
-file_in_path (const std::string& name, const std::string& suffix)
+namespace octave
 {
-  std::string nm = name;
+  std::string file_in_path (const std::string& name, const std::string& suffix)
+  {
+    std::string nm = name;
 
-  if (! suffix.empty ())
-    nm.append (suffix);
-
-  octave::load_path& lp = octave::__get_load_path__ ("file_in_path");
-
-  return octave::sys::env::make_absolute (lp.find_file (nm));
-}
+    if (! suffix.empty ())
+      nm.append (suffix);
 
-std::string
-find_data_file_in_load_path  (const std::string& fcn,
-                              const std::string& file,
-                              bool require_regular_file)
-{
-  std::string fname = file;
+    load_path& lp = __get_load_path__ ("file_in_path");
+
+    return sys::env::make_absolute (lp.find_file (nm));
+  }
 
-  if (! (octave::sys::env::absolute_pathname (fname)
-         || octave::sys::env::rooted_relative_pathname (fname)))
-    {
-      // Load path will also search "." first, but we don't want to
-      // issue a warning if the file is found in the current directory,
-      // so do an explicit check for that.
-      octave::sys::file_stat fs (fname);
-
-      bool local_file_ok
-        = fs.exists () && (fs.is_reg () || ! require_regular_file);
+  std::string find_data_file_in_load_path  (const std::string& fcn,
+                                            const std::string& file,
+                                            bool require_regular_file)
+  {
+    std::string fname = file;
 
-      if (! local_file_ok)
-        {
-          octave::load_path& lp =
-            octave::__get_load_path__ ("find_data_file_in_load_path");
-
-          // Not directly found; search load path.
-          std::string tmp
-            = octave::sys::env::make_absolute (lp.find_file (fname));
+    if (! (sys::env::absolute_pathname (fname)
+           || sys::env::rooted_relative_pathname (fname)))
+      {
+        // Load path will also search "." first, but we don't want to
+        // issue a warning if the file is found in the current directory,
+        // so do an explicit check for that.
+        sys::file_stat fs (fname);
 
-          if (! tmp.empty ())
-            {
-              warn_data_file_in_path (fcn, tmp);
-
-              fname = tmp;
-            }
-        }
-    }
+        bool local_file_ok
+          = fs.exists () && (fs.is_reg () || ! require_regular_file);
 
-  return fname;
-}
-
-// See if there is an function file in the path.
-// If so, return the full path to the file.
+        if (! local_file_ok)
+          {
+            load_path& lp =
+              __get_load_path__ ("find_data_file_in_load_path");
 
-std::string
-fcn_file_in_path (const std::string& name)
-{
-  std::string retval;
+            // Not directly found; search load path.
+            std::string tmp
+              = sys::env::make_absolute (lp.find_file (fname));
 
-  int len = name.length ();
-
-  if (len > 0)
-    {
-      if (octave::sys::env::absolute_pathname (name))
-        {
-          octave::sys::file_stat fs (name);
+            if (! tmp.empty ())
+              {
+                warn_data_file_in_path (fcn, tmp);
 
-          if (fs.exists () && ! fs.is_dir ())
-            retval = name;
-        }
-      else if (len > 2 && name[len - 2] == '.' && name[len - 1] == 'm')
-        {
-          octave::load_path& lp = octave::__get_load_path__ ("fcn_file_in_path");
+                fname = tmp;
+              }
+          }
+      }
 
-          retval = lp.find_fcn_file (name.substr (0, len-2));
-        }
-      else
-        {
-          std::string fname = name;
-          size_t pos = name.find_first_of ('>');
-          if (pos != std::string::npos)
-            fname = name.substr (0, pos);
+    return fname;
+  }
+
+  // See if there is an function file in the path.
+  // If so, return the full path to the file.
 
-          octave::load_path& lp = octave::__get_load_path__ ("fcn_file_in_path");
+  std::string fcn_file_in_path (const std::string& name)
+  {
+    std::string retval;
 
-          retval = lp.find_fcn_file (fname);
-        }
-    }
+    int len = name.length ();
 
-  return retval;
-}
-
-// See if there is a directory called "name" in the path and if it
-// contains a Contents.m file.  If so, return the full path to this file.
-
-std::string
-contents_file_in_path (const std::string& dir)
-{
-  std::string retval;
+    if (len > 0)
+      {
+        if (sys::env::absolute_pathname (name))
+          {
+            sys::file_stat fs (name);
 
-  if (! dir.empty ())
-    {
-      octave::load_path& lp = octave::__get_load_path__ ("contents_in_file_path");
-
-      std::string tcontents
-        = octave::sys::file_ops::concat (lp.find_dir (dir), "Contents.m");
-
-      octave::sys::file_stat fs (tcontents);
-
-      if (fs.exists ())
-        retval = octave::sys::env::make_absolute (tcontents);
-    }
-
-  return retval;
-}
-
-// Deprecated in 4.2, remove in version 5.
-// See if there is a .oct file in the path.
-// If so, return the full path to the file.
+            if (fs.exists () && ! fs.is_dir ())
+              retval = name;
+          }
+        else if (len > 2 && name[len - 2] == '.' && name[len - 1] == 'm')
+          {
+            load_path& lp = __get_load_path__ ("fcn_file_in_path");
 
-std::string
-oct_file_in_path (const std::string& name)
-{
-  std::string retval;
-
-  int len = name.length ();
+            retval = lp.find_fcn_file (name.substr (0, len-2));
+          }
+        else
+          {
+            std::string fname = name;
+            size_t pos = name.find_first_of ('>');
+            if (pos != std::string::npos)
+              fname = name.substr (0, pos);
 
-  if (len > 0)
-    {
-      if (octave::sys::env::absolute_pathname (name))
-        {
-          octave::sys::file_stat fs (name);
+            load_path& lp = __get_load_path__ ("fcn_file_in_path");
+
+            retval = lp.find_fcn_file (fname);
+          }
+      }
 
-          if (fs.exists ())
-            retval = name;
-        }
-      else if (len > 4 && name.find (".oct", len-5))
-        {
-          octave::load_path& lp = octave::__get_load_path__ ("oct_file_in_path");
+    return retval;
+  }
+
+  // See if there is a directory called "name" in the path and if it
+  // contains a Contents.m file.  If so, return the full path to this file.
 
-          retval = lp.find_oct_file (name.substr (0, len-4));
-        }
-      else
-        {
-          octave::load_path& lp = octave::__get_load_path__ ("oct_file_in_path");
+  std::string contents_file_in_path (const std::string& dir)
+  {
+    std::string retval;
 
-          retval = lp.find_oct_file (name);
-        }
-    }
+    if (! dir.empty ())
+      {
+        load_path& lp = __get_load_path__ ("contents_in_file_path");
 
-  return retval;
-}
+        std::string tcontents
+          = sys::file_ops::concat (lp.find_dir (dir), "Contents.m");
 
-// Deprecated in 4.2, remove in version 5.
-// See if there is a .mex file in the path.
-// If so, return the full path to the file.
+        sys::file_stat fs (tcontents);
 
-std::string
-mex_file_in_path (const std::string& name)
-{
-  std::string retval;
+        if (fs.exists ())
+          retval = sys::env::make_absolute (tcontents);
+      }
 
-  int len = name.length ();
+    return retval;
+  }
 
-  if (len > 0)
-    {
-      if (octave::sys::env::absolute_pathname (name))
-        {
-          octave::sys::file_stat fs (name);
+  // Replace backslash escapes in a string with the real values.
 
-          if (fs.exists ())
-            retval = name;
-        }
-      else if (len > 4 && name.find (".mex", len-5))
-        {
-          octave::load_path& lp = octave::__get_load_path__ ("mex_file_in_path");
+  std::string do_string_escapes (const std::string& s)
+  {
+    std::string retval;
 
-          retval = lp.find_mex_file (name.substr (0, len-4));
-        }
-      else
-        {
-          octave::load_path& lp = octave::__get_load_path__ ("mex_file_in_path");
+    size_t i = 0;
+    size_t j = 0;
+    size_t len = s.length ();
 
-          retval = lp.find_mex_file (name);
-        }
-    }
-
-  return retval;
-}
+    retval.resize (len);
 
-// Replace backslash escapes in a string with the real values.
-
-std::string
-do_string_escapes (const std::string& s)
-{
-  std::string retval;
-
-  size_t i = 0;
-  size_t j = 0;
-  size_t len = s.length ();
+    while (j < len)
+      {
+        if (s[j] == '\\' && j+1 < len)
+          {
+            switch (s[++j])
+              {
+              case 'a': // alarm
+                retval[i] = '\a';
+                break;
 
-  retval.resize (len);
+              case 'b': // backspace
+                retval[i] = '\b';
+                break;
 
-  while (j < len)
-    {
-      if (s[j] == '\\' && j+1 < len)
-        {
-          switch (s[++j])
-            {
-            case 'a': // alarm
-              retval[i] = '\a';
-              break;
+              case 'f': // formfeed
+                retval[i] = '\f';
+                break;
 
-            case 'b': // backspace
-              retval[i] = '\b';
-              break;
-
-            case 'f': // formfeed
-              retval[i] = '\f';
-              break;
+              case 'n': // newline
+                retval[i] = '\n';
+                break;
 
-            case 'n': // newline
-              retval[i] = '\n';
-              break;
+              case 'r': // carriage return
+                retval[i] = '\r';
+                break;
 
-            case 'r': // carriage return
-              retval[i] = '\r';
-              break;
+              case 't': // horizontal tab
+                retval[i] = '\t';
+                break;
 
-            case 't': // horizontal tab
-              retval[i] = '\t';
-              break;
-
-            case 'v': // vertical tab
-              retval[i] = '\v';
-              break;
+              case 'v': // vertical tab
+                retval[i] = '\v';
+                break;
 
-            case '\\': // backslash
-              retval[i] = '\\';
-              break;
+              case '\\': // backslash
+                retval[i] = '\\';
+                break;
 
-            case '\'': // quote
-              retval[i] = '\'';
-              break;
-
-            case '"': // double quote
-              retval[i] = '"';
-              break;
+              case '\'': // quote
+                retval[i] = '\'';
+                break;
 
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7': // octal input
-            {
-              size_t k;
-              int tmpi = s[j] - '0';
-              for (k = j+1; k < std::min (j+3, len); k++)
+              case '"': // double quote
+                retval[i] = '"';
+                break;
+
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7': // octal input
                 {
-                  int digit = s[k] - '0';
-                  if (digit < 0 || digit > 7)
-                    break;
-                  tmpi <<= 3;
-                  tmpi += digit;
-                }
-              retval[i] = tmpi;
-              j = k - 1;
-              break;
-            }
-
-            case 'x': // hex input
-            {
-              size_t k;
-              int tmpi = 0;
-              for (k = j+1; k < std::min (j+3, len); k++)
-                {
-                  if (! isxdigit (s[k]))
-                    break;
-
-                  tmpi <<= 4;
-                  int digit = s[k];
-                  if (digit >= 'a')
-                    tmpi += digit - 'a' + 10;
-                  else if (digit >= 'A')
-                    tmpi += digit - 'A' + 10;
-                  else
-                    tmpi += digit - '0';
+                  size_t k;
+                  int tmpi = s[j] - '0';
+                  for (k = j+1; k < std::min (j+3, len); k++)
+                    {
+                      int digit = s[k] - '0';
+                      if (digit < 0 || digit > 7)
+                        break;
+                      tmpi <<= 3;
+                      tmpi += digit;
+                    }
+                  retval[i] = tmpi;
+                  j = k - 1;
+                  break;
                 }
 
-              if (k == j+1)
-                warning (R"(malformed hex escape sequence '\x' -- converting to '\0')");
+              case 'x': // hex input
+                {
+                  size_t k;
+                  int tmpi = 0;
+                  for (k = j+1; k < std::min (j+3, len); k++)
+                    {
+                      if (! isxdigit (s[k]))
+                        break;
 
-              retval[i] = tmpi;
-              j = k - 1;
-              break;
-            }
+                      tmpi <<= 4;
+                      int digit = s[k];
+                      if (digit >= 'a')
+                        tmpi += digit - 'a' + 10;
+                      else if (digit >= 'A')
+                        tmpi += digit - 'A' + 10;
+                      else
+                        tmpi += digit - '0';
+                    }
+
+                  if (k == j+1)
+                    warning (R"(malformed hex escape sequence '\x' -- converting to '\0')");
 
-            default:
-              warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]);
-              retval[i] = s[j];
-              break;
-            }
-        }
-      else
-        retval[i] = s[j];
+                  retval[i] = tmpi;
+                  j = k - 1;
+                  break;
+                }
 
-      i++;
-      j++;
-    }
+              default:
+                warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]);
+                retval[i] = s[j];
+                break;
+              }
+          }
+        else
+          retval[i] = s[j];
 
-  retval.resize (i);
+        i++;
+        j++;
+      }
 
-  return retval;
+    retval.resize (i);
+
+    return retval;
+  }
 }
 
 DEFUN (do_string_escapes, args, ,
@@ -757,7 +679,7 @@
 
   std::string str = args(0).xstring_value ("do_string_escapes: STRING argument must be of type string");
 
-  return ovl (do_string_escapes (str));
+  return ovl (octave::do_string_escapes (str));
 }
 
 /*
@@ -797,63 +719,64 @@
 %!warning <unrecognized escape sequence> do_string_escapes ('\G');
 */
 
-const char *
-undo_string_escape (char c)
+namespace octave
 {
-  if (! c)
-    return "";
+  const char * undo_string_escape (char c)
+  {
+    if (! c)
+      return "";
 
-  switch (c)
-    {
-    case '\0':
-      return R"(\0)";
-
-    case '\a':
-      return R"(\a)";
+    switch (c)
+      {
+      case '\0':
+        return R"(\0)";
 
-    case '\b': // backspace
-      return R"(\b)";
+      case '\a':
+        return R"(\a)";
 
-    case '\f': // formfeed
-      return R"(\f)";
+      case '\b': // backspace
+        return R"(\b)";
 
-    case '\n': // newline
-      return R"(\n)";
+      case '\f': // formfeed
+        return R"(\f)";
 
-    case '\r': // carriage return
-      return R"(\r)";
+      case '\n': // newline
+        return R"(\n)";
 
-    case '\t': // horizontal tab
-      return R"(\t)";
+      case '\r': // carriage return
+        return R"(\r)";
 
-    case '\v': // vertical tab
-      return R"(\v)";
+      case '\t': // horizontal tab
+        return R"(\t)";
 
-    case '\\': // backslash
-      return R"(\\)";
+      case '\v': // vertical tab
+        return R"(\v)";
 
-    case '"': // double quote
-      return R"(\")";
+      case '\\': // backslash
+        return R"(\\)";
 
-    default:
-      {
-        static char retval[2] {'\0', '\0'};
+      case '"': // double quote
+        return R"(\")";
+
+      default:
+        {
+          static char retval[2] {'\0', '\0'};
 
-        retval[0] = c;
-        return retval;
+          retval[0] = c;
+          return retval;
+        }
       }
-    }
-}
+  }
 
-std::string
-undo_string_escapes (const std::string& s)
-{
-  std::string retval;
+  std::string undo_string_escapes (const std::string& s)
+  {
+    std::string retval;
 
-  for (size_t i = 0; i < s.length (); i++)
-    retval.append (undo_string_escape (s[i]));
+    for (size_t i = 0; i < s.length (); i++)
+      retval.append (undo_string_escape (s[i]));
 
-  return retval;
+    return retval;
+  }
 }
 
 DEFUN (undo_string_escapes, args, ,
@@ -892,7 +815,7 @@
 
   std::string str = args(0).xstring_value ("undo_string_escapes: S argument must be a string");
 
-  return ovl (undo_string_escapes (str));
+  return ovl (octave::undo_string_escapes (str));
 }
 
 /*
@@ -921,7 +844,7 @@
        doc: /* -*- texinfo -*-
 @deftypefn {} {} is_absolute_filename (@var{file})
 Return true if @var{file} is an absolute filename.
-@seealso{is_rooted_relative_filename, make_absolute_filename, isdir}
+@seealso{is_rooted_relative_filename, make_absolute_filename, isfolder}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -942,7 +865,7 @@
        doc: /* -*- texinfo -*-
 @deftypefn {} {} is_rooted_relative_filename (@var{file})
 Return true if @var{file} is a rooted-relative filename.
-@seealso{is_absolute_filename, make_absolute_filename, isdir}
+@seealso{is_absolute_filename, make_absolute_filename, isfolder}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -966,7 +889,7 @@
 system.
 
 No check is done for the existence of @var{file}.
-@seealso{canonicalize_file_name, is_absolute_filename, is_rooted_relative_filename, isdir}
+@seealso{canonicalize_file_name, is_absolute_filename, is_rooted_relative_filename, isfolder}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -1123,295 +1046,320 @@
 %!error errno_list ("foo")
 */
 
-static void
-check_dimensions (octave_idx_type& nr, octave_idx_type& nc, const char *warnfor)
+namespace octave
 {
-  if (nr < 0 || nc < 0)
-    {
+  static void check_dimensions (octave_idx_type& nr, octave_idx_type& nc,
+                                const char *warnfor)
+  {
+    if (nr < 0 || nc < 0)
+      {
+        warning_with_id ("Octave:neg-dim-as-zero",
+                         "%s: converting negative dimension to zero", warnfor);
+
+        nr = (nr < 0) ? 0 : nr;
+        nc = (nc < 0) ? 0 : nc;
+      }
+  }
+
+  void check_dimensions (dim_vector& dim, const char *warnfor)
+  {
+    bool neg = false;
+
+    for (int i = 0; i < dim.ndims (); i++)
+      {
+        if (dim(i) < 0)
+          {
+            dim(i) = 0;
+            neg = true;
+          }
+      }
+
+    if (neg)
       warning_with_id ("Octave:neg-dim-as-zero",
                        "%s: converting negative dimension to zero", warnfor);
+  }
 
-      nr = (nr < 0) ? 0 : nr;
-      nc = (nc < 0) ? 0 : nc;
-    }
-}
+  void get_dimensions (const octave_value& a, const char *warn_for,
+                       dim_vector& dim)
+  {
+    // We support dimensions to be specified by any vector, even if it's a
+    // vector of dimensions 0x1, 1x0, 1x1x0, or 1x1x6.  If the vector ends
+    // up being empty, the final dimensions end up being 0x0.
+    if (! a.dims ().isvector ())
+      error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
 
-void
-check_dimensions (dim_vector& dim, const char *warnfor)
-{
-  bool neg = false;
+    const Array<octave_idx_type> v = a.octave_idx_type_vector_value (true);
+    const octave_idx_type n = v.numel ();
 
-  for (int i = 0; i < dim.ndims (); i++)
-    {
-      if (dim(i) < 0)
-        {
-          dim(i) = 0;
-          neg = true;
-        }
-    }
+    dim.resize (n); // even if n < 2, resize sets it back to 2
+    if (n == 0)
+      {
+        dim(0) = 0;
+        dim(1) = 0;
+      }
+    else if (n == 1)
+      {
+        dim(0) = v(0);
+        dim(1) = v(0);
+      }
+    else
+      for (octave_idx_type i = 0; i < n; i++)
+        dim(i) = v(i);
 
-  if (neg)
-    warning_with_id ("Octave:neg-dim-as-zero",
-                     "%s: converting negative dimension to zero", warnfor);
-}
+    octave::check_dimensions (dim, warn_for);
+  }
 
-void
-get_dimensions (const octave_value& a, const char *warn_for,
-                dim_vector& dim)
-{
-  // We support dimensions to be specified by any vector, even if it's a
-  // vector of dimensions 0x1, 1x0, 1x1x0, or 1x1x6.  If the vector ends
-  // up being empty, the final dimensions end up being 0x0.
-  if (! a.dims ().isvector ())
-    error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
+  void get_dimensions (const octave_value& a, const char *warn_for,
+                       octave_idx_type& nr, octave_idx_type& nc)
+  {
+    if (a.is_scalar_type ())
+      {
+        nr = nc = a.idx_type_value (true);
+      }
+    else
+      {
+        nr = a.rows ();
+        nc = a.columns ();
 
-  const Array<octave_idx_type> v = a.octave_idx_type_vector_value ();
-  const octave_idx_type n = v.numel ();
+        if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1))
+          error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
 
-  dim.resize (n); // even if n < 2, resize sets it back to 2
-  if (n == 0)
-    {
-      dim(0) = 0;
-      dim(1) = 0;
-    }
-  else if (n == 1)
-    {
-      dim(0) = v(0);
-      dim(1) = v(0);
-    }
-  else
-    for (octave_idx_type i = 0; i < n; i++)
-      dim(i) = v(i);
+        Array<octave_idx_type> v = a.octave_idx_type_vector_value (true);
+        nr = v(0);
+        nc = v(1);
+      }
+
+    octave::check_dimensions (nr, nc, warn_for);
+  }
 
-  check_dimensions (dim, warn_for);
-}
+  void get_dimensions (const octave_value& a, const octave_value& b,
+                       const char *warn_for, octave_idx_type& nr,
+                       octave_idx_type& nc)
+  {
+    nr = (a.isempty () ? 0 : a.idx_type_value (true));
+    nc = (b.isempty () ? 0 : b.idx_type_value (true));
 
-void
-get_dimensions (const octave_value& a, const char *warn_for,
-                octave_idx_type& nr, octave_idx_type& nc)
-{
-  if (a.is_scalar_type ())
-    {
-      nr = nc = a.idx_type_value ();
-    }
-  else
-    {
-      nr = a.rows ();
-      nc = a.columns ();
+    octave::check_dimensions (nr, nc, warn_for);
+  }
+
+  octave_idx_type dims_to_numel (const dim_vector& dims,
+                                 const octave_value_list& idx_arg)
+  {
+    octave_idx_type retval;
 
-      if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1))
-        error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
-
-      Array<double> v = a.vector_value ();
-      nr = static_cast<octave_idx_type> (octave::math::fix (v(0)));
-      nc = static_cast<octave_idx_type> (octave::math::fix (v(1)));
-    }
-
-  check_dimensions (nr, nc, warn_for);
-}
+    octave_idx_type len = idx_arg.length ();
 
-void
-get_dimensions (const octave_value& a, const octave_value& b,
-                const char *warn_for, octave_idx_type& nr, octave_idx_type& nc)
-{
-  nr = a.isempty ()
-       ? 0 : a.idx_type_value ("%s: row dimension must be a scalar", warn_for);
-  nc = b.isempty ()
-       ? 0 : b.idx_type_value ("%s: column dimension must be a scalar", warn_for);
+    if (len == 0)
+      retval = dims.numel ();
+    else
+      {
+        const dim_vector dv = dims.redim (len);
+        retval = 1;
+        for (octave_idx_type i = 0; i < len; i++)
+          {
+            octave_value idxi = idx_arg(i);
+            if (idxi.is_magic_colon ())
+              retval *= dv(i);
+            else if (idxi.isnumeric ())
+              retval *= idxi.numel ();
+            else
+              {
+                try
+                  {
+                    idx_vector jdx = idxi.index_vector ();
 
-  check_dimensions (nr, nc, warn_for);
-}
+                    retval *= jdx.length (dv(i));
+                  }
+                catch (const index_exception& e)
+                  {
+                    std::string idx = e.idx ();
+                    std::string msg = e.details ();
 
-octave_idx_type
-dims_to_numel (const dim_vector& dims, const octave_value_list& idx_arg)
-{
-  octave_idx_type retval;
-
-  octave_idx_type len = idx_arg.length ();
+                    error ("dims_to_numel: Invalid IDX %s. %s",
+                           idx.c_str (), msg.c_str ());
+                  }
+              }
+          }
+      }
 
-  if (len == 0)
-    retval = dims.numel ();
-  else
-    {
-      const dim_vector dv = dims.redim (len);
-      retval = 1;
-      for (octave_idx_type i = 0; i < len; i++)
-        {
-          octave_value idxi = idx_arg(i);
-          if (idxi.is_magic_colon ())
-            retval *= dv(i);
-          else if (idxi.isnumeric ())
-            retval *= idxi.numel ();
-          else
-            {
-              try
-                {
-                  idx_vector jdx = idxi.index_vector ();
+    return retval;
+  }
+
+  Matrix identity_matrix (octave_idx_type nr, octave_idx_type nc)
+  {
+    Matrix m (nr, nc, 0.0);
+
+    if (nr > 0 && nc > 0)
+      {
+        octave_idx_type n = std::min (nr, nc);
+
+        for (octave_idx_type i = 0; i < n; i++)
+          m (i, i) = 1.0;
+      }
+
+    return m;
+  }
 
-                  retval *= jdx.length (dv(i));
-                }
-              catch (const octave::index_exception& e)
-                {
-                  std::string idx = e.idx ();
-                  std::string msg = e.details ();
+  FloatMatrix float_identity_matrix (octave_idx_type nr, octave_idx_type nc)
+  {
+    FloatMatrix m (nr, nc, 0.0);
+
+    if (nr > 0 && nc > 0)
+      {
+        octave_idx_type n = std::min (nr, nc);
 
-                  error ("dims_to_numel: Invalid IDX %s. %s",
-                         idx.c_str (), msg.c_str ());
-                }
-            }
-        }
-    }
+        for (octave_idx_type i = 0; i < n; i++)
+          m (i, i) = 1.0;
+      }
 
-  return retval;
-}
+    return m;
+  }
 
-Matrix
-identity_matrix (octave_idx_type nr, octave_idx_type nc)
-{
-  Matrix m (nr, nc, 0.0);
+  size_t format (std::ostream& os, const char *fmt, ...)
+  {
+    size_t retval;
 
-  if (nr > 0 && nc > 0)
-    {
-      octave_idx_type n = std::min (nr, nc);
+    va_list args;
+    va_start (args, fmt);
 
-      for (octave_idx_type i = 0; i < n; i++)
-        m (i, i) = 1.0;
-    }
+    retval = vformat (os, fmt, args);
 
-  return m;
-}
+    va_end (args);
 
-FloatMatrix
-float_identity_matrix (octave_idx_type nr, octave_idx_type nc)
-{
-  FloatMatrix m (nr, nc, 0.0);
+    return retval;
+  }
 
-  if (nr > 0 && nc > 0)
-    {
-      octave_idx_type n = std::min (nr, nc);
+  size_t vformat (std::ostream& os, const char *fmt, va_list args)
+  {
+    std::string s = vasprintf (fmt, args);
 
-      for (octave_idx_type i = 0; i < n; i++)
-        m (i, i) = 1.0;
-    }
+    os << s;
 
-  return m;
-}
+    return s.length ();
+  }
 
-size_t
-octave_format (std::ostream& os, const char *fmt, ...)
-{
-  size_t retval;
+  std::string vasprintf (const char *fmt, va_list args)
+  {
+    std::string retval;
 
-  va_list args;
-  va_start (args, fmt);
+    char *result;
+
+    int status = octave_vasprintf_wrapper (&result, fmt, args);
 
-  retval = octave_vformat (os, fmt, args);
-
-  va_end (args);
-
-  return retval;
-}
+    if (status >= 0)
+      {
+        retval = result;
+        ::free (result);
+      }
 
-size_t
-octave_vformat (std::ostream& os, const char *fmt, va_list args)
-{
-  std::string s = octave_vasprintf (fmt, args);
+    return retval;
+  }
 
-  os << s;
+  std::string asprintf (const char *fmt, ...)
+  {
+    std::string retval;
 
-  return s.length ();
-}
+    va_list args;
+    va_start (args, fmt);
 
-std::string
-octave_vasprintf (const char *fmt, va_list args)
-{
-  std::string retval;
+    retval = vasprintf (fmt, args);
 
-  char *result;
+    va_end (args);
 
-  int status = octave_vasprintf_wrapper (&result, fmt, args);
+    return retval;
+  }
 
-  if (status >= 0)
-    {
-      retval = result;
-      ::free (result);
-    }
+  // FIXME: sleep is complicated because we want it to be interruptible.
+  // With the way this program handles signals, the sleep system call
+  // won't respond to SIGINT.  Maybe there is a better way than
+  // breaking this up into multiple shorter intervals?
 
-  return retval;
-}
+  void sleep (double seconds, bool do_graphics_events)
+  {
+    if (seconds <= 0)
+      return;
 
-std::string
-octave_asprintf (const char *fmt, ...)
-{
-  std::string retval;
+    // Allow free access to graphics resources while the interpreter thread
+    // is asleep
+    if (do_graphics_events)
+      gh_manager::unlock ();
+    
+    if (octave::math::isinf (seconds))
+      {
+        // Wait for kbhit
+        int c = -1;
+        octave::flush_stdout ();
+        
+        struct timespec one_tenth = { 0, 100000000 };
+        
+        while (c < 0)
+          {
+            octave_nanosleep_wrapper (&one_tenth, nullptr);
 
-  va_list args;
-  va_start (args, fmt);
-
-  retval = octave_vasprintf (fmt, args);
-
-  va_end (args);
-
-  return retval;
-}
+            octave_quit ();
 
-// FIXME: sleep is complicated because we want it to be interruptible.
-// With the way this program handles signals, the sleep system call
-// won't respond to SIGINT.  Maybe there is a better way than
-// breaking this up into multiple shorter intervals?
+            if (do_graphics_events)
+              gh_manager::process_events ();
+
+            c = octave::kbhit (false);
+          }
+      }
+    else
+      {
+        // Split delay into whole seconds and the remainder as a decimal
+        // fraction.
 
-void
-octave_sleep (double seconds)
-{
-  if (seconds <= 0)
-    return;
+        double fraction = std::modf (seconds, &seconds);
+
+        // Further split the fractional seconds into whole tenths and the
+        // nearest number of nanoseconds remaining.
 
-  // Split delay into whole seconds and the remainder as a decimal
-  // fraction.
+        double tenths = 0;
+        fraction = std::modf (fraction * 10, &tenths) / 10;
+        fraction = std::round (fraction * 1000000000);
 
-  double fraction = std::modf (seconds, &seconds);
-
-  // Further split the fractional seconds into whole tenths and the
-  // nearest number of nanoseconds remaining.
+        // Sleep for the hundredths portion.
 
-  double tenths = 0;
-  fraction = std::modf (fraction * 10, &tenths) / 10;
-  fraction = std::round (fraction * 1000000000);
+        struct timespec hundredths_delay = { 0, static_cast<long> (fraction) };
+
+        octave_nanosleep_wrapper (&hundredths_delay, nullptr);
 
-  // Sleep for the hundredths portion.
+        // Sleep for the whole tenths portion, allowing interrupts every
+        // tenth.
 
-  struct timespec hundredths_delay = { 0, static_cast<long> (fraction) };
+        struct timespec one_tenth = { 0, 100000000 };
 
-  octave_nanosleep_wrapper (&hundredths_delay, nullptr);
-
-  // Sleep for the whole tenths portion, allowing interrupts every
-  // tenth.
+        for (int i = 0; i < static_cast<int> (tenths); i++)
+          {
+            octave_nanosleep_wrapper (&one_tenth, nullptr);
 
-  struct timespec one_tenth = { 0, 100000000 };
+            octave_quit ();
 
-  for (int i = 0; i < static_cast<int> (tenths); i++)
-    {
-      octave_nanosleep_wrapper (&one_tenth, nullptr);
+            if (do_graphics_events)
+              gh_manager::process_events ();
+          }
 
-      octave_quit ();
-    }
+        // Sleep for the whole seconds portion, allowing interrupts every
+        // tenth.
 
-  // Sleep for the whole seconds portion, allowing interrupts every
-  // tenth.
-
-  time_t sec = ((seconds > std::numeric_limits<time_t>::max ())
-                ? std::numeric_limits<time_t>::max ()
-                : static_cast<time_t> (seconds));
+        time_t sec = ((seconds > std::numeric_limits<time_t>::max ())
+                      ? std::numeric_limits<time_t>::max ()
+                      : static_cast<time_t> (seconds));
 
-  for (time_t s = 0; s < sec; s++)
-    {
-      for (int i = 0; i < 10; i++)
-        {
-          octave_nanosleep_wrapper (&one_tenth, nullptr);
+        for (time_t s = 0; s < sec; s++)
+          {
+            for (int i = 0; i < 10; i++)
+              {
+                octave_nanosleep_wrapper (&one_tenth, nullptr);
 
-          octave_quit ();
-        }
-    }
+                octave_quit ();
+
+                if (do_graphics_events)
+                  gh_manager::process_events ();
+              }
+          }
+      }
+  }
 }
 
 DEFUN (isindex, args, ,
@@ -1477,86 +1425,89 @@
 %!error isindex (1:3, 2, 3)
 */
 
-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)
+namespace octave
 {
-  octave_value_list new_args = args;
-  octave_value_list retval;
-  int nargin = args.length ();
-  OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
-  OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
-  OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
+  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_value_list new_args = args;
+    octave_value_list retval;
+    int nargin = args.length ();
+    OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
+    OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
+    OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
 
-  const Cell *ccells = cells;
+    const Cell *ccells = cells;
 
-  octave_idx_type numel = 1;
-  dim_vector dims (1, 1);
+    octave_idx_type numel = 1;
+    dim_vector dims (1, 1);
 
-  for (int i = 0; i < nargin; i++)
-    {
-      octave_value arg = new_args(i);
-      iscell[i] = arg.iscell ();
-      if (iscell[i])
-        {
-          cells[i] = arg.cell_value ();
-          octave_idx_type n = ccells[i].numel ();
-          if (n == 1)
-            {
-              iscell[i] = false;
-              new_args(i) = ccells[i](0);
-            }
-          else if (numel == 1)
-            {
-              numel = n;
-              dims = ccells[i].dims ();
-            }
-          else if (dims != ccells[i].dims ())
-            error ("%s: cell arguments must have matching sizes", fun_name);
-        }
-    }
+    for (int i = 0; i < nargin; i++)
+      {
+        octave_value arg = new_args(i);
+        iscell[i] = arg.iscell ();
+        if (iscell[i])
+          {
+            cells[i] = arg.cell_value ();
+            octave_idx_type n = ccells[i].numel ();
+            if (n == 1)
+              {
+                iscell[i] = false;
+                new_args(i) = ccells[i](0);
+              }
+            else if (numel == 1)
+              {
+                numel = n;
+                dims = ccells[i].dims ();
+              }
+            else if (dims != ccells[i].dims ())
+              error ("%s: cell arguments must have matching sizes", fun_name);
+          }
+      }
 
-  for (int i = 0; i < nargout; i++)
-    rcells[i].clear (dims);
+    for (int i = 0; i < nargout; i++)
+      rcells[i].clear (dims);
 
-  for (octave_idx_type j = 0; j < numel; j++)
-    {
-      for (int i = 0; i < nargin; i++)
-        if (iscell[i])
-          new_args(i) = ccells[i](j);
+    for (octave_idx_type j = 0; j < numel; j++)
+      {
+        for (int i = 0; i < nargin; i++)
+          if (iscell[i])
+            new_args(i) = ccells[i](j);
 
-      octave_quit ();
+        octave_quit ();
 
-      const octave_value_list tmp = fun (new_args, nargout);
+        const octave_value_list tmp = fun (new_args, nargout);
 
-      if (tmp.length () < nargout)
-        error ("%s: do_simple_cellfun: internal error", fun_name);
+        if (tmp.length () < nargout)
+          error ("%s: do_simple_cellfun: internal error", fun_name);
 
-      for (int i = 0; i < nargout; i++)
-        rcells[i](j) = tmp(i);
-    }
+        for (int i = 0; i < nargout; i++)
+          rcells[i](j) = tmp(i);
+      }
 
-  retval.resize (nargout);
+    retval.resize (nargout);
 
-  for (int i = 0; i < nargout; i++)
-    retval(i) = rcells[i];
+    for (int i = 0; i < nargout; i++)
+      retval(i) = rcells[i];
 
-  return retval;
-}
+    return retval;
+  }
 
-octave_value
-do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
-                   const char *fun_name, const octave_value_list& args)
-{
-  octave_value retval;
+  octave_value
+  do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
+                     const char *fun_name, const octave_value_list& args)
+  {
+    octave_value retval;
 
-  const octave_value_list tmp = do_simple_cellfun (fun, fun_name, args, 1);
+    const octave_value_list tmp = octave::do_simple_cellfun (fun, fun_name, args, 1);
 
-  if (tmp.length () > 0)
-    retval = tmp(0);
+    if (tmp.length () > 0)
+      retval = tmp(0);
 
-  return retval;
+    return retval;
+  }
 }
 
 DEFUN (isstudent, args, ,
@@ -1579,3 +1530,183 @@
 
 %!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	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/utils.h	Thu Dec 20 17:18:56 2018 -0500
@@ -38,103 +38,232 @@
 class octave_value_list;
 class string_vector;
 
-extern OCTINTERP_API bool valid_identifier (const char *s);
-extern OCTINTERP_API bool valid_identifier (const std::string& s);
+namespace octave
+{
+  extern OCTINTERP_API bool valid_identifier (const char *s);
+  extern OCTINTERP_API bool valid_identifier (const std::string& s);
+
+  extern OCTINTERP_API bool
+  same_file (const std::string& f, const std::string& g);
+
+  extern OCTINTERP_API int almost_match (const std::string& std,
+                                         const std::string& s,
+                                         int min_match_len = 1,
+                                         int case_sens = 1);
+
+  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);
+
+  extern OCTINTERP_API std::string
+  search_path_for_file (const std::string&, const string_vector&);
+
+  extern OCTINTERP_API string_vector
+  search_path_for_all_files (const std::string&, const string_vector&);
+
+  extern OCTINTERP_API std::string
+  file_in_path (const std::string&, const std::string&);
+
+  extern OCTINTERP_API std::string
+  find_data_file_in_load_path  (const std::string& fcn,
+                                const std::string& file,
+                                bool require_regular_file = false);
+
+  extern OCTINTERP_API std::string contents_file_in_path (const std::string&);
+
+  extern OCTINTERP_API std::string fcn_file_in_path (const std::string&);
+
+  extern OCTINTERP_API std::string do_string_escapes (const std::string& s);
+
+  extern OCTINTERP_API const char * undo_string_escape (char c);
+
+  extern OCTINTERP_API std::string undo_string_escapes (const std::string& s);
+
+  extern OCTINTERP_API void
+  check_dimensions (dim_vector& dim, const char *warnfor);
+
+  extern OCTINTERP_API void
+  get_dimensions (const octave_value& a, const char *warn_for,
+                  dim_vector& dim);
 
+  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);
+
+  extern OCTINTERP_API void
+  get_dimensions (const octave_value& a, const char *warn_for,
+                  octave_idx_type& nr, octave_idx_type& nc);
+
+  extern OCTINTERP_API octave_idx_type
+  dims_to_numel (const dim_vector& dims, const octave_value_list& idx);
+
+  extern OCTINTERP_API Matrix
+  identity_matrix (octave_idx_type nr, octave_idx_type nc);
+
+  extern OCTINTERP_API FloatMatrix
+  float_identity_matrix (octave_idx_type nr, octave_idx_type nc);
+
+  extern OCTINTERP_API size_t
+  format (std::ostream& os, const char *fmt, ...);
+
+  extern OCTINTERP_API size_t
+  vformat (std::ostream& os, const char *fmt, va_list args);
+
+  extern OCTINTERP_API std::string
+  vasprintf (const char *fmt, va_list args);
+
+  extern OCTINTERP_API std::string asprintf (const char *fmt, ...);
+
+  extern OCTINTERP_API void sleep (double seconds,
+                                   bool do_graphics_events = false);
+
+  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);
+
+  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);
+}
+
+#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);
 
-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::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 (4.2, "use 'octave_value::isempty' instead")
-extern OCTINTERP_API int empty_arg (const char *name, octave_idx_type nr,
-                                    octave_idx_type nc);
+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);
 
-extern OCTINTERP_API std::string
-search_path_for_file (const std::string&, const string_vector&);
-
+OCTAVE_DEPRECATED (5, "use 'octave::search_path_for_all_files' instead")
 extern OCTINTERP_API string_vector
-search_path_for_all_files (const std::string&, const 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&, const 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,
+find_data_file_in_load_path  (const std::string& fcn, const std::string& file,
                               bool require_regular_file = false);
 
-extern OCTINTERP_API std::string contents_file_in_path (const std::string&);
+OCTAVE_DEPRECATED (5, "use 'octave::contents_file_in_path' instead")
+extern OCTINTERP_API std::string
+contents_file_in_path (const std::string& s);
 
-extern OCTINTERP_API std::string fcn_file_in_path (const std::string&);
-
-OCTAVE_DEPRECATED (4.2, "use 'load_path::find_oct_file' instead")
-extern OCTINTERP_API std::string oct_file_in_path (const std::string&);
+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 (4.2, "use 'load_path::find_mex_file' instead")
-extern OCTINTERP_API std::string mex_file_in_path (const std::string&);
-
-extern OCTINTERP_API std::string do_string_escapes (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);
 
-extern OCTINTERP_API const char * undo_string_escape (char c);
+OCTAVE_DEPRECATED (5, "use 'octave::undo_string_escape' instead")
+extern OCTINTERP_API const char *
+undo_string_escape (char c);
 
-extern OCTINTERP_API std::string undo_string_escapes (const std::string& s);
+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,
+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);
 
-extern OCTINTERP_API size_t
-octave_format (std::ostream& os, const char *fmt, ...);
+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);
 
-extern OCTINTERP_API std::string octave_asprintf (const char *fmt, ...);
+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) ...);
+}
 
-extern OCTINTERP_API void octave_sleep (double seconds);
+OCTAVE_DEPRECATED (5, "use 'octave::sleep' instead")
+extern OCTINTERP_API void
+octave_sleep (double seconds);
 
-extern OCTINTERP_API
-octave_value_list
+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);
 
-extern OCTINTERP_API
-octave_value
+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	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/variables.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -40,7 +40,6 @@
 #include "str-vec.h"
 
 #include "call-stack.h"
-#include "defaults.h"
 #include "Cell.h"
 #include "defun.h"
 #include "dirfns.h"
@@ -61,15 +60,12 @@
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
+#include "syminfo.h"
 #include "symtab.h"
 #include "unwind-prot.h"
 #include "utils.h"
 #include "variables.h"
 
-// Defines layout for the whos/who -long command
-static std::string Vwhos_line_format
-  = "  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;\n";
-
 // Attributes of variables and functions.
 
 // Is this octave_value a valid function?
@@ -141,7 +137,10 @@
 
       int parse_status;
 
-      octave::eval_string (cmd, true, parse_status, 0);
+      octave::interpreter& interp
+        = octave::__get_interpreter__ ("extract_function");
+
+      interp.eval_string (cmd, true, parse_status, 0);
 
       if (parse_status != 0)
         error ("%s: '%s' is not valid as a function",
@@ -160,165 +159,6 @@
   return retval;
 }
 
-string_vector
-get_struct_elts (const std::string& text)
-{
-  int n = 1;
-
-  size_t pos = 0;
-
-  size_t len = text.length ();
-
-  while ((pos = text.find ('.', pos)) != std::string::npos)
-    {
-      if (++pos == len)
-        break;
-
-      n++;
-    }
-
-  string_vector retval (n);
-
-  pos = 0;
-
-  for (int i = 0; i < n; i++)
-    {
-      len = text.find ('.', pos);
-
-      if (len != std::string::npos)
-        len -= pos;
-
-      retval[i] = text.substr (pos, len);
-
-      if (len != std::string::npos)
-        pos += len + 1;
-    }
-
-  return retval;
-}
-
-static inline bool
-is_variable (octave::symbol_table& symtab, const std::string& name)
-{
-  bool retval = false;
-
-  if (! name.empty ())
-    {
-      octave::symbol_scope scope = symtab.current_scope ();
-
-      octave_value val = scope ? scope.varval (name) : octave_value ();
-
-      retval = val.is_defined ();
-    }
-
-  return retval;
-}
-
-string_vector
-generate_struct_completions (const std::string& text,
-                             std::string& prefix, std::string& hint)
-{
-  string_vector names;
-
-  size_t pos = text.rfind ('.');
-  bool array = false;
-
-  if (pos != std::string::npos)
-    {
-      if (pos == text.length ())
-        hint = "";
-      else
-        hint = text.substr (pos+1);
-
-      prefix = text.substr (0, pos);
-
-      if (prefix == "")
-        {
-          array = true;
-          prefix = find_indexed_expression (text);
-        }
-
-      std::string base_name = prefix;
-
-      pos = base_name.find_first_of ("{(. ");
-
-      if (pos != std::string::npos)
-        base_name = base_name.substr (0, pos);
-
-      octave::symbol_table& symtab
-        = octave::__get_symbol_table__ ("generate_struct_completions");
-
-      if (is_variable (symtab, base_name))
-        {
-          int parse_status;
-
-          octave::unwind_protect frame;
-
-          frame.protect_var (discard_error_messages);
-          frame.protect_var (discard_warning_messages);
-
-          discard_error_messages = true;
-          discard_warning_messages = true;
-
-          try
-            {
-              octave_value tmp = octave::eval_string (prefix, true, parse_status);
-
-              frame.run ();
-
-              if (tmp.is_defined ()
-                  && (tmp.isstruct () || tmp.isjava () || tmp.is_classdef_object ()))
-                names = tmp.map_keys ();
-            }
-          catch (const octave::execution_exception&)
-            {
-              octave::interpreter::recover_from_exception ();
-            }
-        }
-    }
-
-  // Undo look-back that found the array expression,
-  // but insert an extra "." to distinguish from the non-struct case.
-  if (array)
-    prefix = ".";
-
-  return names;
-}
-
-// FIXME: this will have to be much smarter to work "correctly".
-bool
-looks_like_struct (const std::string& text, char prev_char)
-{
-  bool retval = (! text.empty ()
-                 && (text != "." || prev_char == ')' || prev_char == '}')
-                 && text.find_first_of (octave::sys::file_ops::dir_sep_chars ()) == std::string::npos
-                 && text.find ("..") == std::string::npos
-                 && text.rfind ('.') != std::string::npos);
-
-#if 0
-  symbol_record *sr = curr_sym_tab->lookup (text);
-
-  if (sr && ! sr->is_function ())
-    {
-      int parse_status;
-
-      octave::unwind_protect frame;
-
-      frame.protect_var (discard_error_messages);
-
-      discard_error_messages = true;
-
-      octave_value tmp = eval_string (text, true, parse_status);
-
-      frame.run ();
-
-      retval = (tmp.is_defined () && tmp.isstruct ());
-    }
-#endif
-
-  return retval;
-}
-
 static octave_value
 do_isglobal (octave::symbol_table& symtab, const octave_value_list& args)
 {
@@ -361,6 +201,7 @@
 %!test
 %! global x;
 %! assert (isglobal ("x"), true);
+%! clear -global x;  # cleanup after test
 
 %!error isglobal ()
 %!error isglobal ("a", "b")
@@ -371,7 +212,7 @@
 symbol_exist (octave::interpreter& interp, const std::string& name,
               const std::string& type = "any")
 {
-  if (octave::is_keyword (name))
+  if (octave::iskeyword (name))
     return 0;
 
   bool search_any = type == "any";
@@ -440,7 +281,7 @@
             }
         }
 
-      file_name = file_in_path (name, "");
+      file_name = octave::file_in_path (name, "");
 
       if (file_name.empty ())
         file_name = name;
@@ -707,13 +548,7 @@
   octave::call_stack& cs
     = octave::__get_call_stack__ ("curr_fcn_unwind_protect_frame");
 
-  octave_user_code *curr_usr_code = cs.caller_user_code ();
-
-  octave_user_function *curr_usr_fcn
-    = (curr_usr_code && curr_usr_code->is_user_function ()
-       ? dynamic_cast<octave_user_function *> (curr_usr_code) : nullptr);
-
-  return curr_usr_fcn ? curr_usr_fcn->unwind_protect_frame () : nullptr;
+  return cs.curr_fcn_unwind_protect_frame ();
 }
 
 template <typename T>
@@ -866,9 +701,9 @@
       double dval = args(0).xscalar_value ("%s: argument must be a scalar value", nm);
 
       if (dval < minval)
-        error ("%s: argument must be greater than %g", minval);
+        error ("%s: argument must be greater than %g", nm, minval);
       if (dval > maxval)
-        error ("%s: argument must be less than or equal to %g", maxval);
+        error ("%s: argument must be less than or equal to %g", nm, maxval);
 
       var = dval;
     }
@@ -997,971 +832,12 @@
   return retval;
 }
 
-struct
-whos_parameter
-{
-  char command;
-  char modifier;
-  int parameter_length;
-  int first_parameter_length;
-  int balance;
-  std::string text;
-  std::string line;
-};
-
-static void
-print_descriptor (std::ostream& os, std::list<whos_parameter> params)
-{
-  // This method prints a line of information on a given symbol
-  std::list<whos_parameter>::iterator i = params.begin ();
-  std::ostringstream param_buf;
-
-  octave::preserve_stream_state stream_state (os);
-
-  while (i != params.end ())
-    {
-      whos_parameter param = *i;
-
-      if (param.command != '\0')
-        {
-          // Do the actual printing
-          switch (param.modifier)
-            {
-            case 'l':
-              os << std::setiosflags (std::ios::left)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::left)
-                        << std::setw (param.parameter_length);
-              break;
-
-            case 'r':
-              os << std::setiosflags (std::ios::right)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::right)
-                        << std::setw (param.parameter_length);
-              break;
-
-            case 'c':
-              if (param.command != 's')
-                {
-                  os << std::setiosflags (std::ios::left)
-                     << std::setw (param.parameter_length);
-                  param_buf << std::setiosflags (std::ios::left)
-                            << std::setw (param.parameter_length);
-                }
-              break;
-
-            default:
-              os << std::setiosflags (std::ios::left)
-                 << std::setw (param.parameter_length);
-              param_buf << std::setiosflags (std::ios::left)
-                        << std::setw (param.parameter_length);
-            }
-
-          if (param.command == 's' && param.modifier == 'c')
-            {
-              int a, b;
-
-              if (param.modifier == 'c')
-                {
-                  a = param.first_parameter_length - param.balance;
-                  a = (a < 0 ? 0 : a);
-                  b = param.parameter_length - a - param.text.length ();
-                  b = (b < 0 ? 0 : b);
-                  os << std::setiosflags (std::ios::left) << std::setw (a)
-                     << "" << std::resetiosflags (std::ios::left) << param.text
-                     << std::setiosflags (std::ios::left)
-                     << std::setw (b) << ""
-                     << std::resetiosflags (std::ios::left);
-                  param_buf << std::setiosflags (std::ios::left)
-                            << std::setw (a)
-                            << "" << std::resetiosflags (std::ios::left)
-                            << param.line
-                            << std::setiosflags (std::ios::left)
-                            << std::setw (b) << ""
-                            << std::resetiosflags (std::ios::left);
-                }
-            }
-          else
-            {
-              os << param.text;
-              param_buf << param.line;
-            }
-          os << std::resetiosflags (std::ios::left)
-             << std::resetiosflags (std::ios::right);
-          param_buf << std::resetiosflags (std::ios::left)
-                    << std::resetiosflags (std::ios::right);
-          i++;
-        }
-      else
-        {
-          os << param.text;
-          param_buf << param.line;
-          i++;
-        }
-    }
-
-  os << param_buf.str ();
-}
-
-// FIXME: This is a bit of a kluge.  We'd like to just use val.dims()
-// and if val is an object, expect that dims will call size if it is
-// overloaded by a user-defined method.  But there are currently some
-// unresolved const issues that prevent that solution from working.
-// This same kluge is done in symtab.cc (do_workspace_info), fix there too.
-
-std::string
-get_dims_str (const octave_value& val)
-{
-  octave_value tmp = val;
-
-  Matrix sz = tmp.size ();
-
-  dim_vector dv = dim_vector::alloc (sz.numel ());
-
-  for (octave_idx_type i = 0; i < dv.ndims (); i++)
-    dv(i) = sz(i);
-
-  return dv.str ();
-}
-
-class
-symbol_info_list
-{
-private:
-  struct symbol_info
-  {
-    symbol_info (const octave::symbol_record& sr,
-                 octave::symbol_record::context_id context,
-                 const std::string& expr_str = "",
-                 const octave_value& expr_val = octave_value ())
-      : name (expr_str.empty () ? sr.name () : expr_str),
-        varval (),
-        is_automatic (sr.is_automatic ()),
-        is_complex (varval.iscomplex ()),
-        is_formal (sr.is_formal ()),
-        is_global (sr.is_global ()),
-        is_persistent (sr.is_persistent ())
-    {
-      varval = (expr_val.is_undefined ()
-                ? sr.varval (context) : expr_val);
-
-      is_complex = varval.iscomplex ();
-    }
-
-    void display_line (std::ostream& os,
-                       const std::list<whos_parameter>& params) const
-    {
-      std::string dims_str = get_dims_str (varval);
-
-      std::list<whos_parameter>::const_iterator i = params.begin ();
-
-      octave::preserve_stream_state stream_state (os);
-
-      while (i != params.end ())
-        {
-          whos_parameter param = *i;
-
-          if (param.command != '\0')
-            {
-              // Do the actual printing.
-
-              switch (param.modifier)
-                {
-                case 'l':
-                  os << std::setiosflags (std::ios::left)
-                     << std::setw (param.parameter_length);
-                  break;
-
-                case 'r':
-                  os << std::setiosflags (std::ios::right)
-                     << std::setw (param.parameter_length);
-                  break;
-
-                case 'c':
-                  if (param.command == 's')
-                    {
-                      int front = param.first_parameter_length
-                                  - dims_str.find ('x');
-                      int back = param.parameter_length
-                                 - dims_str.length ()
-                                 - front;
-                      front = (front > 0) ? front : 0;
-                      back = (back > 0) ? back : 0;
-
-                      os << std::setiosflags (std::ios::left)
-                         << std::setw (front)
-                         << ""
-                         << std::resetiosflags (std::ios::left)
-                         << dims_str
-                         << std::setiosflags (std::ios::left)
-                         << std::setw (back)
-                         << ""
-                         << std::resetiosflags (std::ios::left);
-                    }
-                  else
-                    {
-                      os << std::setiosflags (std::ios::left)
-                         << std::setw (param.parameter_length);
-                    }
-                  break;
-
-                default:
-                  error ("whos_line_format: modifier '%c' unknown",
-                         param.modifier);
-
-                  os << std::setiosflags (std::ios::right)
-                     << std::setw (param.parameter_length);
-                }
-
-              switch (param.command)
-                {
-                case 'a':
-                  {
-                    char tmp[6];
-
-                    tmp[0] = (is_automatic ? 'a' : ' ');
-                    tmp[1] = (is_complex ? 'c' : ' ');
-                    tmp[2] = (is_formal ? 'f' : ' ');
-                    tmp[3] = (is_global ? 'g' : ' ');
-                    tmp[4] = (is_persistent ? 'p' : ' ');
-                    tmp[5] = 0;
-
-                    os << tmp;
-                  }
-                  break;
-
-                case 'b':
-                  os << varval.byte_size ();
-                  break;
-
-                case 'c':
-                  os << varval.class_name ();
-                  break;
-
-                case 'e':
-                  os << varval.numel ();
-                  break;
-
-                case 'n':
-                  os << name;
-                  break;
-
-                case 's':
-                  if (param.modifier != 'c')
-                    os << dims_str;
-                  break;
-
-                case 't':
-                  os << varval.type_name ();
-                  break;
-
-                default:
-                  error ("whos_line_format: command '%c' unknown",
-                         param.command);
-                }
-
-              os << std::resetiosflags (std::ios::left)
-                 << std::resetiosflags (std::ios::right);
-              i++;
-            }
-          else
-            {
-              os << param.text;
-              i++;
-            }
-        }
-    }
-
-    std::string name;
-    octave_value varval;
-    bool is_automatic;
-    bool is_complex;
-    bool is_formal;
-    bool is_global;
-    bool is_persistent;
-  };
-
-public:
-  symbol_info_list (void) : lst () { }
-
-  symbol_info_list (const symbol_info_list& sil) : lst (sil.lst) { }
-
-  symbol_info_list& operator = (const symbol_info_list& sil)
-  {
-    if (this != &sil)
-      lst = sil.lst;
-
-    return *this;
-  }
-
-  ~symbol_info_list (void) = default;
-
-  void append (const octave::symbol_record& sr,
-               octave::symbol_record::context_id context)
-  {
-    lst.push_back (symbol_info (sr, context));
-  }
-
-  void append (const octave::symbol_record& sr,
-               octave::symbol_record::context_id context,
-               const std::string& expr_str,
-               const octave_value& expr_val)
-  {
-    lst.push_back (symbol_info (sr, context, expr_str, expr_val));
-  }
-
-  size_t size (void) const { return lst.size (); }
-
-  bool empty (void) const { return lst.empty (); }
-
-  octave_map
-  map_value (const std::string& caller_function_name, int nesting_level) const
-  {
-    size_t len = lst.size ();
-
-    Cell name_info (len, 1);
-    Cell size_info (len, 1);
-    Cell bytes_info (len, 1);
-    Cell class_info (len, 1);
-    Cell global_info (len, 1);
-    Cell sparse_info (len, 1);
-    Cell complex_info (len, 1);
-    Cell nesting_info (len, 1);
-    Cell persistent_info (len, 1);
-
-    std::list<symbol_info>::const_iterator p = lst.begin ();
-
-    for (size_t j = 0; j < len; j++)
-      {
-        const symbol_info& si = *p++;
-
-        octave_scalar_map ni;
-
-        ni.assign ("function", caller_function_name);
-        ni.assign ("level", nesting_level);
-
-        name_info(j) = si.name;
-        global_info(j) = si.is_global;
-        persistent_info(j) = si.is_persistent;
-
-        octave_value val = si.varval;
-
-        size_info(j) = val.size ();
-        bytes_info(j) = val.byte_size ();
-        class_info(j) = val.class_name ();
-        sparse_info(j) = val.issparse ();
-        complex_info(j) = val.iscomplex ();
-        nesting_info(j) = ni;
-      }
-
-    octave_map info;
-
-    info.assign ("name", name_info);
-    info.assign ("size", size_info);
-    info.assign ("bytes", bytes_info);
-    info.assign ("class", class_info);
-    info.assign ("global", global_info);
-    info.assign ("sparse", sparse_info);
-    info.assign ("complex", complex_info);
-    info.assign ("nesting", nesting_info);
-    info.assign ("persistent", persistent_info);
-
-    return info;
-  }
-
-  void display (std::ostream& os)
-  {
-    if (! lst.empty ())
-      {
-        size_t bytes = 0;
-        size_t elements = 0;
-
-        std::list<whos_parameter> params = parse_whos_line_format ();
-
-        print_descriptor (os, params);
-
-        octave_stdout << "\n";
-
-        for (const auto& syminfo : lst)
-          {
-            syminfo.display_line (os, params);
-
-            octave_value val = syminfo.varval;
-
-            elements += val.numel ();
-            bytes += val.byte_size ();
-          }
-
-        os << "\nTotal is " << elements
-           << (elements == 1 ? " element" : " elements")
-           << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
-           << "\n";
-      }
-  }
-
-  // Parse the string whos_line_format, and return a parameter list,
-  // containing all information needed to print the given
-  // attributes of the symbols.
-  std::list<whos_parameter> parse_whos_line_format (void)
-  {
-    int idx;
-    size_t format_len = Vwhos_line_format.length ();
-    char garbage;
-    std::list<whos_parameter> params;
-
-    size_t bytes1;
-    int elements1;
-
-    std::string param_string = "abcenst";
-    Array<int> param_length (dim_vector (param_string.length (), 1));
-    Array<std::string> param_names (dim_vector (param_string.length (), 1));
-    size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
-
-    pos_a = param_string.find ('a'); // Attributes
-    pos_b = param_string.find ('b'); // Bytes
-    pos_c = param_string.find ('c'); // Class
-    pos_e = param_string.find ('e'); // Elements
-    pos_n = param_string.find ('n'); // Name
-    pos_s = param_string.find ('s'); // Size
-    pos_t = param_string.find ('t'); // Type
-
-    param_names(pos_a) = "Attr";
-    param_names(pos_b) = "Bytes";
-    param_names(pos_c) = "Class";
-    param_names(pos_e) = "Elements";
-    param_names(pos_n) = "Name";
-    param_names(pos_s) = "Size";
-    param_names(pos_t) = "Type";
-
-    for (size_t i = 0; i < param_string.length (); i++)
-      param_length(i) = param_names(i).length ();
-
-    // The attribute column needs size 5.
-    param_length(pos_a) = 5;
-
-    // Calculating necessary spacing for name column,
-    // bytes column, elements column and class column
-
-    for (const auto& syminfo : lst)
-      {
-        std::stringstream ss1, ss2;
-        std::string str;
-
-        str = syminfo.name;
-        param_length(pos_n) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_n)))
-                               ? str.length () : param_length(pos_n));
-
-        octave_value val = syminfo.varval;
-
-        str = val.type_name ();
-        param_length(pos_t) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_t)))
-                               ? str.length () : param_length(pos_t));
-
-        elements1 = val.numel ();
-        ss1 << elements1;
-        str = ss1.str ();
-        param_length(pos_e) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_e)))
-                               ? str.length () : param_length(pos_e));
-
-        bytes1 = val.byte_size ();
-        ss2 << bytes1;
-        str = ss2.str ();
-        param_length(pos_b) = ((str.length ()
-                                > static_cast<size_t> (param_length(pos_b)))
-                               ? str.length () : param_length (pos_b));
-      }
-
-    idx = 0;
-    while (static_cast<size_t> (idx) < format_len)
-      {
-        whos_parameter param;
-        param.command = '\0';
-
-        if (Vwhos_line_format[idx] == '%')
-          {
-            bool error_encountered = false;
-            param.modifier = 'r';
-            param.parameter_length = 0;
-
-            int a = 0;
-            int b = -1;
-            int balance = 1;
-            unsigned int items;
-            size_t pos;
-            std::string cmd;
-
-            // Parse one command from whos_line_format
-            cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
-            pos = cmd.find (';');
-            if (pos == std::string::npos)
-              error ("parameter without ; in whos_line_format");
-
-            cmd = cmd.substr (0, pos+1);
-
-            idx += cmd.length ();
-
-            // FIXME: use iostream functions instead of sscanf!
-
-            if (cmd.find_first_of ("crl") != 1)
-              items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
-                              &garbage, &param.command, &a, &b, &balance);
-            else
-              items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
-                              &garbage, &param.modifier, &param.command,
-                              &a, &b, &balance) - 1;
-
-            if (items < 2)
-              error ("whos_line_format: parameter structure without command in whos_line_format");
-
-            // Exception case of bare class command 'c' without modifier 'l/r'
-            if (param.modifier == 'c'
-                && param_string.find (param.command) == std::string::npos)
-              {
-                param.modifier = 'r';
-                param.command = 'c';
-              }
-
-            // Insert data into parameter
-            param.first_parameter_length = 0;
-            pos = param_string.find (param.command);
-            if (pos == std::string::npos)
-              error ("whos_line_format: '%c' is not a command", param.command);
-
-            param.parameter_length = param_length(pos);
-            param.text = param_names(pos);
-            param.line.assign (param_names(pos).length (), '=');
-
-            param.parameter_length = (a > param.parameter_length
-                                      ? a : param.parameter_length);
-            if (param.command == 's' && param.modifier == 'c' && b > 0)
-              param.first_parameter_length = b;
-
-            if (param.command == 's')
-              {
-                // Have to calculate space needed for printing
-                // matrix dimensions Space needed for Size column is
-                // hard to determine in prior, because it depends on
-                // dimensions to be shown.  That is why it is
-                // recalculated for each Size-command int first,
-                // rest = 0, total;
-                int rest = 0;
-                int first = param.first_parameter_length;
-                int total = param.parameter_length;
-
-                for (const auto& syminfo : lst)
-                  {
-                    octave_value val = syminfo.varval;
-                    std::string dims_str = get_dims_str (val);
-                    int first1 = dims_str.find ('x');
-                    int total1 = dims_str.length ();
-                    int rest1 = total1 - first1;
-                    rest = (rest1 > rest ? rest1 : rest);
-                    first = (first1 > first ? first1 : first);
-                    total = (total1 > total ? total1 : total);
-                  }
-
-                if (param.modifier == 'c')
-                  {
-                    if (first < balance)
-                      first += balance - first;
-                    if (rest + balance < param.parameter_length)
-                      rest += param.parameter_length - rest - balance;
-
-                    param.parameter_length = first + rest;
-                    param.first_parameter_length = first;
-                    param.balance = balance;
-                  }
-                else
-                  {
-                    param.parameter_length = total;
-                    param.first_parameter_length = 0;
-                  }
-              }
-            else if (param.modifier == 'c')
-              error ("whos_line_format: modifier 'c' not available for command '%c'",
-                     param.command);
-
-            // What happens if whos_line_format contains negative numbers
-            // at param_length positions?
-            param.balance = (b < 0 ? 0 : param.balance);
-            param.first_parameter_length = (b < 0
-                                            ? 0
-                                            : param.first_parameter_length);
-            param.parameter_length = (a < 0
-                                      ? 0
-                                      : (param.parameter_length
-                                         < param_length(pos_s)
-                                         ? param_length(pos_s)
-                                         : param.parameter_length));
-
-            // Parameter will not be pushed into parameter list if ...
-            if (! error_encountered)
-              params.push_back (param);
-          }
-        else
-          {
-            // Text string, to be printed as it is ...
-            std::string text;
-            size_t pos;
-            text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
-            pos = text.find ('%');
-            if (pos != std::string::npos)
-              text = text.substr (0, pos);
-
-            // Push parameter into list ...
-            idx += text.length ();
-            param.text=text;
-            param.line.assign (text.length (), ' ');
-            params.push_back (param);
-          }
-      }
-
-    return params;
-  }
-
-private:
-  std::list<symbol_info> lst;
-
-};
-
-static octave_value
-do_who (octave::interpreter& interp, int argc, const string_vector& argv,
-        bool return_list, bool verbose = false, std::string msg = "")
-{
-  octave_value retval;
-
-  octave::symbol_table& symtab = interp.get_symbol_table ();
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  std::string my_name = argv[0];
-
-  bool global_only = false;
-  bool have_regexp = false;
-
-  int i;
-  for (i = 1; i < argc; i++)
-    {
-      if (argv[i] == "-file")
-        {
-          // FIXME: This is an inefficient manner to implement this as the
-          // variables are loaded in to a temporary context and then treated.
-          // It would be better to refecat symbol_info_list to not store the
-          // symbol records and then use it in load-save.cc (do_load) to
-          // implement this option there so that the variables are never
-          // stored at all.
-          if (i == argc - 1)
-            error ("%s: -file argument must be followed by a filename",
-                   my_name.c_str ());
-
-          std::string nm = argv[i + 1];
-
-          octave::unwind_protect frame;
-
-          // Set up temporary scope.
-
-          octave::symbol_scope tmp_scope ("$dummy_scope$");
-
-          symtab.set_scope (tmp_scope);
-
-          cs.push (tmp_scope, 0);
-          frame.add_method (cs, &octave::call_stack::pop);
-
-          octave::feval ("load", octave_value (nm), 0);
-
-          std::string newmsg = "Variables in the file " + nm + ":\n\n";
-
-          retval = do_who (interp, i, argv, return_list, verbose, newmsg);
-
-          return retval;
-        }
-      else if (argv[i] == "-regexp")
-        have_regexp = true;
-      else if (argv[i] == "global")
-        global_only = true;
-      else if (argv[i][0] == '-')
-        warning ("%s: unrecognized option '%s'", my_name.c_str (),
-                 argv[i].c_str ());
-      else
-        break;
-    }
-
-  int npats = argc - i;
-  string_vector pats;
-  if (npats > 0)
-    {
-      pats.resize (npats);
-      for (int j = 0; j < npats; j++)
-        pats[j] = argv[i+j];
-    }
-  else
-    {
-      pats.resize (++npats);
-      pats[0] = "*";
-    }
-
-  symbol_info_list symbol_stats;
-  std::list<std::string> symbol_names;
-
-  octave::symbol_scope scope = symtab.current_scope ();
-
-  octave::symbol_record::context_id context = scope.current_context ();
-
-  for (int j = 0; j < npats; j++)
-    {
-      std::string pat = pats[j];
-
-      if (have_regexp)
-        {
-          std::list<octave::symbol_record> tmp
-            = (global_only
-               ? symtab.regexp_global_variables (pat)
-               : symtab.regexp_variables (pat));
-
-          for (const auto& symrec : tmp)
-            {
-              if (symrec.is_variable (context))
-                {
-                  if (verbose)
-                    symbol_stats.append (symrec, context);
-                  else
-                    symbol_names.push_back (symrec.name ());
-                }
-            }
-        }
-      else
-        {
-          size_t pos = pat.find_first_of (".({");
-
-          if (pos != std::string::npos && pos > 0)
-            {
-              if (verbose)
-                {
-                  // NOTE: we can only display information for
-                  // expressions based on global values if the variable is
-                  // global in the current scope because we currently have
-                  // no way of looking up the base value in the global
-                  // scope and then evaluating the arguments in the
-                  // current scope.
-
-                  std::string base_name = pat.substr (0, pos);
-
-                  if (scope && scope.is_variable (base_name))
-                    {
-                      octave::symbol_record sr
-                        = symtab.find_symbol (base_name);
-
-                      if (! global_only || sr.is_global ())
-                        {
-                          int parse_status;
-
-                          octave_value expr_val
-                            = octave::eval_string (pat, true, parse_status);
-
-                          symbol_stats.append (sr, context, pat, expr_val);
-                        }
-                    }
-                }
-            }
-          else
-            {
-              std::list<octave::symbol_record> tmp
-                = (global_only
-                   ? symtab.glob_global_variables (pat)
-                   : symtab.glob_variables (pat));
-
-              for (const auto& symrec : tmp)
-                {
-                  if (symrec.is_variable (context))
-                    {
-                      if (verbose)
-                        symbol_stats.append (symrec, context);
-                      else
-                        symbol_names.push_back (symrec.name ());
-                    }
-                }
-            }
-        }
-    }
-
-  if (return_list)
-    {
-      if (verbose)
-        {
-          std::string caller_function_name;
-          octave_function *caller = cs.caller ();
-          if (caller)
-            caller_function_name = caller->name ();
-
-          retval = symbol_stats.map_value (caller_function_name, 1);
-        }
-      else
-        retval = Cell (string_vector (symbol_names));
-    }
-  else if (! (symbol_stats.empty () && symbol_names.empty ()))
-    {
-      if (msg.empty ())
-        if (global_only)
-          octave_stdout << "Global variables:\n\n";
-        else
-          octave_stdout << "Variables in the current scope:\n\n";
-      else
-        octave_stdout << msg;
-
-      if (verbose)
-        symbol_stats.display (octave_stdout);
-      else
-        {
-          string_vector names (symbol_names);
-
-          names.list_in_columns (octave_stdout);
-        }
-
-      octave_stdout << "\n";
-    }
-
-  return retval;
-}
-
-DEFMETHOD (who, interp, args, nargout,
-           doc: /* -*- texinfo -*-
-@deftypefn  {} {} who
-@deftypefnx {} {} who pattern @dots{}
-@deftypefnx {} {} who option pattern @dots{}
-@deftypefnx {} {C =} who ("pattern", @dots{})
-List currently defined variables matching the given patterns.
-
-Valid pattern syntax is the same as described for the @code{clear} command.
-If no patterns are supplied, all variables are listed.
-
-By default, only variables visible in the local scope are displayed.
-
-The following are valid options, but may not be combined.
-
-@table @code
-@item global
-List variables in the global scope rather than the current scope.
-
-@item -regexp
-The patterns are considered to be regular expressions when matching the
-variables to display.  The same pattern syntax accepted by the @code{regexp}
-function is used.
-
-@item -file
-The next argument is treated as a filename.  All variables found within the
-specified file are listed.  No patterns are accepted when reading variables
-from a file.
-@end table
-
-If called as a function, return a cell array of defined variable names
-matching the given patterns.
-@seealso{whos, isglobal, isvarname, exist, regexp}
-@end deftypefn */)
-{
-  int argc = args.length () + 1;
-
-  string_vector argv = args.make_argv ("who");
-
-  return do_who (interp, argc, argv, nargout == 1);
-}
-
-/*
-%!test
-%! avar = magic (4);
-%! ftmp = [tempname() ".mat"];
-%! unwind_protect
-%!   save (ftmp, "avar");
-%!   vars = whos ("-file", ftmp);
-%!   assert (numel (vars), 1);
-%!   assert (isstruct (vars));
-%!   assert (vars.name, "avar");
-%!   assert (vars.size, [4, 4]);
-%!   assert (vars.class, "double");
-%!   assert (vars.bytes, 128);
-%! unwind_protect_cleanup
-%!   unlink (ftmp);
-%! end_unwind_protect
-*/
-
-DEFMETHOD (whos, interp, args, nargout,
-           doc: /* -*- texinfo -*-
-@deftypefn  {} {} whos
-@deftypefnx {} {} whos pattern @dots{}
-@deftypefnx {} {} whos option pattern @dots{}
-@deftypefnx {} {S =} whos ("pattern", @dots{})
-Provide detailed information on currently defined variables matching the
-given patterns.
-
-Options and pattern syntax are the same as for the @code{who} command.
-
-Extended information about each variable is summarized in a table with the
-following default entries.
-
-@table @asis
-@item Attr
-Attributes of the listed variable.  Possible attributes are:
-
-@table @asis
-@item blank
-Variable in local scope
-
-@item @code{a}
-Automatic variable.  An automatic variable is one created by the
-interpreter, for example @code{argn}.
-
-@item @code{c}
-Variable of complex type.
-
-@item @code{f}
-Formal parameter (function argument).
-
-@item @code{g}
-Variable with global scope.
-
-@item @code{p}
-Persistent variable.
-@end table
-
-@item Name
-The name of the variable.
-
-@item Size
-The logical size of the variable.  A scalar is 1x1, a vector is
-@nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.
-
-@item Bytes
-The amount of memory currently used to store the variable.
-
-@item Class
-The class of the variable.  Examples include double, single, char, uint16,
-cell, and struct.
-@end table
-
-The table can be customized to display more or less information through
-the function @code{whos_line_format}.
-
-If @code{whos} is called as a function, return a struct array of defined
-variable names matching the given patterns.  Fields in the structure
-describing each variable are: name, size, bytes, class, global, sparse,
-complex, nesting, persistent.
-@seealso{who, whos_line_format}
-@end deftypefn */)
-{
-  int argc = args.length () + 1;
-
-  string_vector argv = args.make_argv ("whos");
-
-  return do_who (interp, argc, argv, nargout == 1, true);
-}
-
 DEFMETHOD (mlock, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} mlock ()
-Lock the current function into memory so that it can't be cleared.
-@seealso{munlock, mislocked, persistent}
+Lock the current function into memory so that it can't be removed with
+@code{clear}.
+@seealso{munlock, mislocked, persistent, clear}
 @end deftypefn */)
 {
   if (args.length () != 0)
@@ -1983,10 +859,11 @@
            doc: /* -*- texinfo -*-
 @deftypefn  {} {} munlock ()
 @deftypefnx {} {} munlock (@var{fcn})
-Unlock the named function @var{fcn}.
+Unlock the named function @var{fcn} so that it may be removed from memory with
+@code{clear}.
 
 If no function is named then unlock the current function.
-@seealso{mlock, mislocked, persistent}
+@seealso{mlock, mislocked, persistent, clear}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -2019,10 +896,10 @@
            doc: /* -*- texinfo -*-
 @deftypefn  {} {} mislocked ()
 @deftypefnx {} {} mislocked (@var{fcn})
-Return true if the named function @var{fcn} is locked.
+Return true if the named function @var{fcn} is locked in memory.
 
 If no function is named then return true if the current function is locked.
-@seealso{mlock, munlock, persistent}
+@seealso{mlock, munlock, persistent, clear}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -2303,20 +1180,14 @@
     }
 }
 
-#define CLEAR_OPTION_ERROR(cond)                \
-  do                                            \
-    {                                           \
-      if (cond)                                 \
-        print_usage ();                         \
-    }                                           \
-  while (0)
-
 DEFMETHOD (clear, interp, args, ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} clear [options] pattern @dots{}
-Delete the names matching the given patterns from the symbol table.
+@deftypefn  {} {} clear
+@deftypefnx {} {} clear @var{pattern} @dots{}
+@deftypefnx {} {} clear @var{options} @var{pattern} @dots{}
+Delete the names matching the given @var{pattern}s from the symbol table.
 
-The pattern may contain the following special characters:
+The @var{pattern} may contain the following special characters:
 
 @table @code
 @item ?
@@ -2326,10 +1197,10 @@
 Match zero or more characters.
 
 @item [ @var{list} ]
-Match the list of characters specified by @var{list}.  If the first
-character is @code{!} or @code{^}, match all characters except those
-specified by @var{list}.  For example, the pattern @samp{[a-zA-Z]} will
-match all lowercase and uppercase alphabetic characters.
+Match the list of characters specified by @var{list}.  If the first character
+is @code{!} or @code{^}, match all characters except those specified by
+@var{list}.  For example, the pattern @code{[a-zA-Z]} will match all lowercase
+and uppercase alphabetic characters.
 @end table
 
 For example, the command
@@ -2339,50 +1210,58 @@
 @end example
 
 @noindent
-clears the name @code{foo} and all names that begin with the letter
-@code{b} and end with the letter @code{r}.
-
-If @code{clear} is called without any arguments, all user-defined
-variables (local and global) are cleared from the symbol table.
+clears the name @code{foo} and all names that begin with the letter @samp{b}
+and end with the letter @samp{r}.
 
-If @code{clear} is called with at least one argument, only the visible
-names matching the arguments are cleared.  For example, suppose you have
-defined a function @code{foo}, and then hidden it by performing the
-assignment @code{foo = 2}.  Executing the command @kbd{clear foo} once
-will clear the variable definition and restore the definition of
-@code{foo} as a function.  Executing @kbd{clear foo} a second time will
-clear the function definition.
+If @code{clear} is called without any arguments, all user-defined variables
+are cleared from the current workspace (i.e., local variables).  Any global
+variables present will no longer be visible in the current workspace, but they
+will continue to exist in the global workspace.  Functions are unaffected by
+this form of @code{clear}.
 
 The following options are available in both long and short form
 
 @table @code
-@item -all, -a
-Clear all local and global user-defined variables and all functions from the
+@item all, -all, -a
+Clear all local and global user-defined variables, and all functions from the
 symbol table.
 
 @item -exclusive, -x
-Clear the variables that don't match the following pattern.
-
-@item -functions, -f
-Clear the function names and the built-in symbols names.
+Clear variables that do @strong{not} match the following pattern.
 
-@item -global, -g
-Clear global symbol names.
+@item functions, -functions, -f
+Clear function names from the function symbol table.  Persistent variables
+will be re-initialized to their default value unless the function has been
+locked in memory with @code{mlock}.
 
-@item -variables, -v
+@item global, -global, -g
+Clear global variable names.
+
+@item variables, -variables, -v
 Clear local variable names.
 
-@item -classes, -c
-Clears the class structure table and clears all objects.
+@item classes, -classes, -c
+Clear the class structure table and all objects.
 
 @item -regexp, -r
-The arguments are treated as regular expressions as any variables that
-match will be cleared.
+The @var{pattern} arguments are treated as regular expressions and any matches
+will be cleared.
 @end table
 
-With the exception of @code{exclusive}, all long options can be used
-without the dash as well.
-@seealso{who, whos, exist}
+With the exception of @option{-exclusive} and @option{-regexp}, all long
+options can be used without the dash as well.  Note that, aside from
+@option{-exclusive}, only one other option may appear.  All options must
+appear before any patterns.
+
+Programming Note: The command @code{clear @var{name}} only clears the variable
+@var{name} when both a variable and a (shadowed) function named @var{name}
+are currently defined.  For example, suppose you have defined a function
+@code{foo}, and then hidden it by performing the assignment @code{foo = 2}.
+Executing the command @code{clear foo} once will clear the variable
+definition and restore the definition of @code{foo} as a function.
+Executing @code{clear foo} a second time will clear the function definition.
+
+@seealso{who, whos, exist, mlock}
 @end deftypefn */)
 {
   octave::symbol_table& symtab = interp.get_symbol_table ();
@@ -2393,7 +1272,6 @@
 
   if (argc == 1)
     {
-      do_clear_globals (symtab, argv, argc, true);
       do_clear_variables (symtab, argv, argc, true);
 
       octave_link::clear_workspace ();
@@ -2417,47 +1295,52 @@
         {
           if (argv[idx] == "-all" || argv[idx] == "-a")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               clear_all = true;
             }
           else if (argv[idx] == "-exclusive" || argv[idx] == "-x")
             {
-              have_dash_option = true;
               exclusive = true;
             }
           else if (argv[idx] == "-functions" || argv[idx] == "-f")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               clear_functions = true;
             }
           else if (argv[idx] == "-global" || argv[idx] == "-g")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               clear_globals = true;
             }
           else if (argv[idx] == "-variables" || argv[idx] == "-v")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               clear_variables = true;
             }
           else if (argv[idx] == "-classes" || argv[idx] == "-c")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               clear_objects = true;
             }
           else if (argv[idx] == "-regexp" || argv[idx] == "-r")
             {
-              CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+              if (have_dash_option)
+                print_usage ();
 
               have_dash_option = true;
               have_regexp = true;
@@ -2468,7 +1351,7 @@
 
       if (idx <= argc)
         {
-          if (! have_dash_option)
+          if (! have_dash_option && ! exclusive)
             do_matlab_compatible_clear (symtab, argv, argc, idx);
           else
             {
@@ -2509,90 +1392,30 @@
                   do_clear_symbols (symtab, argv, argc, idx, exclusive);
                 }
             }
-
-          octave_link::set_workspace ();
         }
     }
 
   return ovl ();
 }
 
-DEFUN (whos_line_format, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} whos_line_format ()
-@deftypefnx {} {@var{old_val} =} whos_line_format (@var{new_val})
-@deftypefnx {} {} whos_line_format (@var{new_val}, "local")
-Query or set the format string used by the command @code{whos}.
-
-A full format string is:
-@c Set example in small font to prevent overfull line
-
-@smallexample
-%[modifier]<command>[:width[:left-min[:balance]]];
-@end smallexample
-
-The following command sequences are available:
-
-@table @code
-@item %a
-Prints attributes of variables (g=global, p=persistent, f=formal parameter,
-a=automatic variable).
-
-@item %b
-Prints number of bytes occupied by variables.
-
-@item %c
-Prints class names of variables.
-
-@item %e
-Prints elements held by variables.
-
-@item %n
-Prints variable names.
-
-@item %s
-Prints dimensions of variables.
+/*
+## This test must be wrapped in its own function or the 'clear' command will
+## break the %!test environment.
+%!function __test_clear_no_args__ ()
+%!  global x
+%!  x = 3;
+%!  clear
+%!  assert (! exist ("x", "var"));  # x is not in the current workspace anymore
+%!  global x                        # but still lives in the global workspace
+%!  assert (exist ("x", "var"));
+%!endfunction
 
-@item %t
-Prints type names of variables.
-@end table
-
-Every command may also have an alignment modifier:
-
-@table @code
-@item l
-Left alignment.
-
-@item r
-Right alignment (default).
-
-@item c
-Column-aligned (only applicable to command %s).
-@end table
+%!test
+%! __test_clear_no_args__ ();
 
-The @code{width} parameter is a positive integer specifying the minimum
-number of columns used for printing.  No maximum is needed as the field will
-auto-expand as required.
-
-The parameters @code{left-min} and @code{balance} are only available when
-the column-aligned modifier is used with the command @samp{%s}.
-@code{balance} specifies the column number within the field width which
-will be aligned between entries.  Numbering starts from 0 which indicates
-the leftmost column.  @code{left-min} specifies the minimum field width to
-the left of the specified balance column.
-
-The default format is:
-
-@qcode{"  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;@xbackslashchar{}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.
-The original variable value is restored when exiting the function.
-@seealso{whos}
-@end deftypefn */)
-{
-  return SET_INTERNAL_VARIABLE (whos_line_format);
-}
+## Test that multiple options cannot be given
+%!error clear -f -g
+*/
 
 static std::string Vmissing_function_hook = "__unimplemented__";
 
@@ -2814,3 +1637,40 @@
 
   symtab.top_level_assign (nm, val);
 }
+
+string_vector
+get_struct_elts (const std::string& text)
+{
+  int n = 1;
+
+  size_t pos = 0;
+
+  size_t len = text.length ();
+
+  while ((pos = text.find ('.', pos)) != std::string::npos)
+    {
+      if (++pos == len)
+        break;
+
+      n++;
+    }
+
+  string_vector retval (n);
+
+  pos = 0;
+
+  for (int i = 0; i < n; i++)
+    {
+      len = text.find ('.', pos);
+
+      if (len != std::string::npos)
+        len -= pos;
+
+      retval[i] = text.substr (pos, len);
+
+      if (len != std::string::npos)
+        pos += len + 1;
+    }
+
+  return retval;
+}
--- a/libinterp/corefcn/variables.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/variables.h	Thu Dec 20 17:18:56 2018 -0500
@@ -58,16 +58,6 @@
                   const std::string& fname, const std::string& header,
                   const std::string& trailer);
 
-extern OCTINTERP_API string_vector
-get_struct_elts (const std::string& text);
-
-extern OCTINTERP_API string_vector
-generate_struct_completions (const std::string& text, std::string& prefix,
-                             std::string& hint);
-
-extern OCTINTERP_API bool
-looks_like_struct (const std::string& text, char prev_char);
-
 extern OCTINTERP_API int
 symbol_exist (const std::string& name, const std::string& type = "any");
 
@@ -165,4 +155,8 @@
 extern OCTINTERP_API void
 set_top_level_value (const std::string& nm, const octave_value& val);
 
+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/zfstream.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/corefcn/zfstream.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -34,7 +34,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <iomanip>
+#include <istream>
+#include <ostream>
 
 #include "zfstream.h"
 
--- a/libinterp/dldfcn/__eigs__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/__eigs__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -182,6 +182,7 @@
   bool sym_tested = false;
   bool cholB = false;
   bool a_is_sparse = false;
+  bool b_is_sparse = false;
   ColumnVector permB;
   int arg_offset = 0;
   double tol = std::numeric_limits<double>::epsilon ();
@@ -265,6 +266,13 @@
       if (args(1+arg_offset).iscomplex ())
         {
           b_arg = 1+arg_offset;
+          if (args(b_arg).issparse ())
+            {
+              bscm = (args(b_arg).sparse_complex_matrix_value ());
+              b_is_sparse = true;
+            }
+          else
+            bcm = (args(b_arg).complex_matrix_value ());
           have_b = true;
           b_is_complex = true;
           arg_offset++;
@@ -272,6 +280,13 @@
       else
         {
           b_arg = 1+arg_offset;
+          if (args(b_arg).issparse ())
+            {
+              bsmm = (args(b_arg).sparse_matrix_value ());
+              b_is_sparse = true;
+            }
+          else
+            bmm = (args(b_arg).matrix_value ());
           have_b = true;
           arg_offset++;
         }
@@ -374,14 +389,14 @@
     {
       if (a_is_complex || b_is_complex)
         {
-          if (a_is_sparse)
+          if (b_is_sparse)
             bscm = args(b_arg).sparse_complex_matrix_value ();
           else
             bcm = args(b_arg).complex_matrix_value ();
         }
       else
         {
-          if (a_is_sparse)
+          if (b_is_sparse)
             bsmm = args(b_arg).sparse_matrix_value ();
           else
             bmm = args(b_arg).matrix_value ();
@@ -400,10 +415,18 @@
       ComplexColumnVector eig_val;
 
       if (have_a_fun)
-        nconv = EigsComplexNonSymmetricFunc
-                (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec,
-                 eig_val, cresid, octave_stdout, tol, (nargout > 1), cholB,
-                 disp, maxit);
+        {
+          if (b_is_sparse)
+            nconv = EigsComplexNonSymmetricFunc
+              (eigs_complex_func, 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,
+               eig_val, bcm, permB, cresid, octave_stdout, tol,
+               (nargout > 1), cholB, disp, maxit);
+        }
       else if (have_sigma)
         {
           if (a_is_sparse)
@@ -443,10 +466,18 @@
       ComplexColumnVector eig_val;
 
       if (have_a_fun)
-        nconv = EigsComplexNonSymmetricFunc
-                (eigs_complex_func, n, typ,  sigma, k, p, info, eig_vec,
-                 eig_val, cresid, octave_stdout, tol, (nargout > 1), cholB,
-                 disp, maxit);
+        {
+          if (b_is_sparse)
+            nconv = EigsComplexNonSymmetricFunc
+              (eigs_complex_func, 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,
+               eig_val, bcm, permB, cresid, octave_stdout, tol,
+               (nargout > 1), cholB, disp, maxit);
+        }
       else
         {
           if (a_is_sparse)
@@ -474,10 +505,18 @@
           ColumnVector eig_val;
 
           if (have_a_fun)
-            nconv = EigsRealSymmetricFunc
-                    (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
-                     eig_val, resid, octave_stdout, tol, (nargout > 1),
-                     cholB, disp, maxit);
+            {
+              if (b_is_sparse)
+                nconv = EigsRealSymmetricFunc
+                       (eigs_func, 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,
+                        eig_val, bmm, permB, resid, octave_stdout, tol,
+                        (nargout > 1), cholB, disp, maxit);
+            }
           else if (have_sigma)
             {
               if (a_is_sparse)
@@ -516,10 +555,18 @@
           ComplexColumnVector eig_val;
 
           if (have_a_fun)
-            nconv = EigsRealNonSymmetricFunc
-                    (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
-                     eig_val, resid, octave_stdout, tol, (nargout > 1),
-                     cholB, disp, maxit);
+            {
+              if (b_is_sparse)
+                nconv = EigsRealNonSymmetricFunc
+                        (eigs_func, 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,
+                         eig_val, bmm, permB, resid, octave_stdout, tol,
+                         (nargout > 1), cholB, disp, maxit);
+            }
           else if (have_sigma)
             {
               if (a_is_sparse)
@@ -556,10 +603,13 @@
 
   if (nconv <= 0)
     warning_with_id ("Octave:eigs:UnconvergedEigenvalues",
-                     "eigs: None of the %d requested eigenvalues converged", k);
+                     "eigs: None of the %" OCTAVE_IDX_TYPE_FORMAT
+                     " requested eigenvalues converged", k);
   else if (nconv < k)
     warning_with_id ("Octave:eigs:UnconvergedEigenvalues",
-                     "eigs: Only %d of the %d requested eigenvalues converged",
+                     "eigs: Only %" OCTAVE_IDX_TYPE_FORMAT
+                     " of the %" OCTAVE_IDX_TYPE_FORMAT
+                     " requested eigenvalues converged",
                      nconv, k);
 
   if (! fcn_name.empty ())
--- a/libinterp/dldfcn/__init_fltk__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/__init_fltk__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -123,14 +123,18 @@
 public:
 
   OpenGL_fltk (int xx, int yy, int ww, int hh, double num)
-    : Fl_Gl_Window (xx, yy, ww, hh, nullptr), m_number (num), m_renderer (),
-      m_in_zoom (false), m_zoom_box ()
+    : Fl_Gl_Window (xx, yy, ww, hh, nullptr), m_number (num),
+      m_glfcns (), m_renderer (m_glfcns), m_in_zoom (false), m_zoom_box ()
   {
 #if defined (HAVE_OPENGL)
+
     // Ask for double buffering and a depth buffer.
     mode (FL_DEPTH | FL_DOUBLE | FL_MULTISAMPLE);
+
 #else
+
     err_disabled_feature ("OpenGL_fltk", "OpenGL");
+
 #endif
   }
 
@@ -148,9 +152,8 @@
 
   void print (const std::string& cmd, const std::string& term)
   {
-    //std::cout << "OpenGL_fltk::print(cmd=" << cmd << ", term=" << term << ") canvas size = " << w () << 'x' << h () << std::endl;
-
-    octave::gl2ps_print (gh_manager::get_object (m_number), cmd, term);
+    octave::gl2ps_print (m_glfcns, gh_manager::get_object (m_number),
+                         cmd, term);
   }
 
   uint8NDArray get_pixels (void)
@@ -166,10 +169,17 @@
     Fl_Gl_Window::resize (xx, yy, ww, hh);
 
 #else
+
+    octave_unused_parameter (xx);
+    octave_unused_parameter (yy);
+    octave_unused_parameter (ww);
+    octave_unused_parameter (hh);
+
     // This shouldn't happen because construction of Opengl_fltk
     // objects is supposed to be impossible if OpenGL is not available.
 
     panic_impossible ();
+
 #endif
   }
 
@@ -190,6 +200,7 @@
 
   double m_number;
 
+  octave::opengl_functions m_glfcns;
   octave::opengl_renderer m_renderer;
 
   bool m_in_zoom;
@@ -203,9 +214,9 @@
 
     if (! valid ())
       {
-        glMatrixMode (GL_PROJECTION);
-        glLoadIdentity ();
-        glViewport (0, 0, w (), h ());
+        m_glfcns.glMatrixMode (GL_PROJECTION);
+        m_glfcns.glLoadIdentity ();
+        m_glfcns.glViewport (0, 0, w (), h ());
       }
 
     m_renderer.draw (gh_manager::get_object (m_number));
@@ -214,70 +225,31 @@
       overlay ();
 
 #else
+
     // This shouldn't happen because construction of Opengl_fltk
     // objects is supposed to be impossible if OpenGL is not available.
 
     panic_impossible ();
-#endif
-  }
-
-  void zoom_box_vertex (void)
-  {
-#if defined (HAVE_OPENGL)
-
-    glVertex2d (m_zoom_box(0), h () - m_zoom_box(1));
-    glVertex2d (m_zoom_box(0), h () - m_zoom_box(3));
-    glVertex2d (m_zoom_box(2), h () - m_zoom_box(3));
-    glVertex2d (m_zoom_box(2), h () - m_zoom_box(1));
-    glVertex2d (m_zoom_box(0), h () - m_zoom_box(1));
-
-#else
-    // This shouldn't happen because construction of Opengl_fltk
-    // objects is supposed to be impossible if OpenGL is not available.
-
-    panic_impossible ();
+
 #endif
   }
 
   void overlay (void)
   {
-#if defined (HAVE_OPENGL)
-
-    glMatrixMode (GL_MODELVIEW);
-    glPushMatrix ();
-    glLoadIdentity ();
-
-    glMatrixMode (GL_PROJECTION);
-    glPushMatrix ();
-    glLoadIdentity ();
-    gluOrtho2D (0.0, w (), 0.0, h ());
-
-    glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
-    glDisable (GL_DEPTH_TEST);
-
-    glBegin (GL_POLYGON);
-    glColor4f (0.45, 0.62, 0.81, 0.1);
-    zoom_box_vertex ();
-    glEnd ();
-
-    glLineWidth (1.5);
-    glBegin (GL_LINE_STRIP);
-    glColor4f (0.45, 0.62, 0.81, 0.9);
-    zoom_box_vertex ();
-    glEnd ();
-
-    glPopAttrib ();
-    glMatrixMode (GL_MODELVIEW);
-    glPopMatrix ();
-    glMatrixMode (GL_PROJECTION);
-    glPopMatrix ();
-
-#else
-    // This shouldn't happen because construction of Opengl_fltk
-    // objects is supposed to be impossible if OpenGL is not available.
-
-    panic_impossible ();
-#endif
+    Matrix overlaycolor (3, 1);
+    overlaycolor(0) = 0.45;
+    overlaycolor(1) = 0.62;
+    overlaycolor(2) = 0.81;
+    double overlayalpha = 0.1;
+    Matrix bordercolor = overlaycolor;
+    double borderalpha = 0.9;
+    double borderwidth = 1.5;
+
+    m_renderer.draw_zoom_box (w (), h (),
+                              m_zoom_box(0), m_zoom_box(1),
+                              m_zoom_box(2), m_zoom_box(3),
+                              overlaycolor, overlayalpha,
+                              bordercolor, borderalpha, borderwidth);
   }
 
   int handle (int event)
@@ -298,10 +270,14 @@
     return Fl_Gl_Window::handle (event);
 
 #else
+
+    octave_unused_parameter (event);
+
     // This shouldn't happen because construction of Opengl_fltk
     // objects is supposed to be impossible if OpenGL is not available.
 
     panic_impossible ();
+
 #endif
   }
 };
@@ -1489,8 +1465,6 @@
 
     if (! m_fp.is_beingdeleted ())
       {
-        //std::cout << "plot_window::handle event = " <<  fl_eventnames[event] << std::endl;
-
         // FLTK resends keyboard events with flipped case if all
         // widgets rejects the event.
         // See Event Propagation http://www.fltk.org/doc-1.3/events.html
@@ -1847,7 +1821,7 @@
               break;
             }
       }
-    //std::cout << "plot_window::handle wasn't interested in event " <<  fl_eventnames[event] << std::endl;
+
     return Fl_Window::handle (event);
   }
 };
@@ -2441,7 +2415,7 @@
 
         octave_value_list args = input_event_hook_fcn_id;
         args.append (false);
-        Fremove_input_event_hook (args, 0);
+        Fremove_input_event_hook (m_interpreter, args, 0);
         input_event_hook_fcn_id = octave_value_list ();
 
         figure_manager::close_all ();
@@ -2504,7 +2478,7 @@
 
       octave_value fcn (new octave_builtin (F__fltk_check__));
       octave_value fcn_handle (new octave_fcn_handle (fcn, "@__fltk_check__"));
-      octave_value_list id = Fadd_input_event_hook (fcn_handle, 1);
+      octave_value_list id = Fadd_input_event_hook (interp, fcn_handle, 1);
 
       fltk->set_input_event_hook_id (id);
     }
--- a/libinterp/dldfcn/__init_gnuplot__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/__init_gnuplot__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -189,7 +189,7 @@
           std::string gnuplot_binary = tmp(0).string_value ();
 
           string_vector args (gnuplot_binary);
-          std::string gnuplot_path = search_path_for_file (path, args);
+          std::string gnuplot_path = octave::search_path_for_file (path, args);
 
           octave::sys::file_stat fs (gnuplot_path);
 
@@ -197,7 +197,7 @@
             {
               args[0] += exeext;
 
-              gnuplot_path = search_path_for_file (path, args);
+              gnuplot_path = octave::search_path_for_file (path, args);
 
               fs = octave::sys::file_stat (gnuplot_path);
             }
--- a/libinterp/dldfcn/__ode15__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/__ode15__.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -35,6 +35,7 @@
 #include "oct-map.h"
 #include "ov.h"
 #include "ovl.h"
+#include "pager.h"
 #include "parse.h"
 
 #if defined (HAVE_SUNDIALS)
@@ -890,12 +891,12 @@
     if (IDAGetNumResEvals (mem, &nrevals) != 0)
       error ("IDA failed to return the number of residual evaluations");
 
-    std::cout << nsteps << " successful steps\n";
-    std::cout << netfails << " failed attempts\n";
-    std::cout << nrevals << " function evaluations\n";
-    // std::cout << " partial derivatives\n";
-    // std::cout << " LU decompositions\n";
-    // std::cout << " solutions of linear systems\n";
+    octave_stdout << nsteps << " successful steps\n";
+    octave_stdout << netfails << " failed attempts\n";
+    octave_stdout << nrevals << " function evaluations\n";
+    // octave_stdout << " partial derivatives\n";
+    // octave_stdout << " LU decompositions\n";
+    // octave_stdout << " solutions of linear systems\n";
   }
 
   ColumnVector
--- a/libinterp/dldfcn/__osmesa_print__.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,257 +0,0 @@
-/*
-
-Copyright (C) 2016-2018 Andreas Weber <andy.weber.aw@gmail.com>
-
-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/>.
-
-This code is based on Brian Pauls' src/osdemos/osdemo.c
-from git://anongit.freedesktop.org/mesa/demos
-
-*/
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined (HAVE_OSMESA_H)
-#  include <osmesa.h>
-#elif defined (HAVE_GL_OSMESA_H)
-#  include <GL/osmesa.h>
-#endif
-
-#include <string>
-
-#include "Array.h"
-#include "dMatrix.h"
-#include "oct-locbuf.h"
-#include "uint8NDArray.h"
-#include "unwind-prot.h"
-
-#include "defun-dld.h"
-#include "error.h"
-#include "errwarn.h"
-#include "gl-render.h"
-#include "gl2ps-print.h"
-#include "graphics.h"
-#include "oct-opengl.h"
-#include "ov.h"
-#include "ovl.h"
-
-#if defined (HAVE_OSMESA)
-
-static void
-reset_visibility (figure::properties *fp)
-{
-  fp->set_visible ("on");
-}
-
-#endif
-
-DEFUN_DLD(__osmesa_print__, args, ,
-          doc: /* -*- texinfo -*-
-@deftypefn  {} {} __osmesa_print__ (@var{h}, @var{file}, @var{term})
-@deftypefnx {} {@var{img} =} __osmesa_print__ (@var{h})
-Print figure @var{h} using OSMesa and gl2ps for vector formats.
-
-This is a private internal function.
-
-The first method calls gl2ps with the appropriate @var{term} and writes
-the output of gl2ps to @var{file}.  If the first character of @var{file}
-is @code{|}, then a process is started and the output of gl2ps is piped
-to it.
-
-Valid options for @var{term}, which can be concatenated in one string, are:
-
-@table @asis
-@item @qcode{eps}, @qcode{pdf}, @qcode{ps}, @qcode{svg}, @qcode{pgf}, @qcode{tex}
-Select output format.
-
-@item @code{is2D}
-Use GL2PS_SIMPLE_SORT instead of GL2PS_BSP_SORT as Z-depth sorting
-algorithm.
-
-@item @code{notext}
-Don't render text.
-@end table
-
-The second method doesn't use gl2ps and returns a RGB image in @var{img}
-instead.
-
-@end deftypefn */)
-{
-#if defined (HAVE_OSMESA)
-
-  int nargin = args.length ();
-
-  if (nargin != 1 && nargin != 3)
-    print_usage ();
-
-  if (nargin == 3)
-    {
-      if (! (args(1).is_string () && args(2).is_string ()))
-        error ("__osmesa_print__: FILE and TERM must be strings");
-    }
-
-  octave_value_list retval;
-
-  int h = args(0).double_value ();
-  graphics_object fobj = gh_manager::get_object (h);
-  if (! (fobj && fobj.isa ("figure")))
-    error ("__osmesa_print__: H must be a valid figure handle");
-
-  figure::properties& fp =
-    dynamic_cast<figure::properties&> (fobj.get_properties ());
-
-  bool internal = true;
-  Matrix bb = fp.get_boundingbox (internal);
-
-  GLsizei Width = static_cast<GLsizei> (bb(2));
-  GLsizei Height = static_cast<GLsizei> (bb(3));
-
-  // Create an RGBA-mode context, specify Z=16, stencil=0, accum=0 sizes
-  OSMesaContext ctx = OSMesaCreateContextExt (OSMESA_RGBA, 16, 0, 0, nullptr);
-  if (! ctx)
-    error ("__osmesa_print__: OSMesaCreateContext failed!\n");
-
-  // Allocate the image buffer
-  OCTAVE_LOCAL_BUFFER (GLubyte, buffer, 4 * Width * Height);
-
-  // Bind the buffer to the context and make it current
-  if (! OSMesaMakeCurrent (ctx, buffer, GL_UNSIGNED_BYTE, Width, Height))
-    error ("__osmesa_print__: OSMesaMakeCurrent failed!\n");
-
-  // Test for a bug in OSMesa with version < 9.0
-  //
-  // Unfortunately the macros OSMESA_MAJOR_VERSION and OSMESA_MINOR_VERSION
-  // weren't updated between many releases and can't be used for detection.
-  // (Version 8.0 until 9.1.4 all return MAJOR 6, MINOR 5)
-  GLint z, s;
-  glGetIntegerv (GL_DEPTH_BITS, &z);
-  glGetIntegerv (GL_STENCIL_BITS, &s);
-  if (z != 16 || s != 0)
-    error ("__osmesa_print__: Depth and stencil doesn't match,"
-           " are you sure you are using OSMesa >= 9.0?");
-
-  octave::unwind_protect outer_frame;
-
-  bool v = fp.is_visible ();
-
-  if (v)
-    {
-      outer_frame.add_fcn (reset_visibility, &fp);
-
-      fp.set_visible ("off");
-    }
-
-  if (nargin == 3)
-    {
-      std::string file = args(1).string_value ();
-      std::string term = args(2).string_value ();
-
-      octave::gl2ps_print (fobj, file, term);
-    }
-  else
-    {
-      // return RGB image
-      octave::opengl_renderer rend;
-
-      // Draw and finish () or there may primitives missing in the
-      // output.
-      rend.draw (fobj);
-      rend.finish ();
-
-      dim_vector dv (4, Width, Height);
-
-      // FIXME: We expect that GLubyte is 1 Byte long.
-      // Adapt code if this isn't always true
-      assert (sizeof (GLubyte) == 1);
-      uint8NDArray img (dv);
-      unsigned char *p = reinterpret_cast<unsigned char *>(img.fortran_vec ());
-      memcpy (p, buffer, (4 * Width * Height));
-
-      Array<octave_idx_type> perm (dim_vector (3, 1));
-      perm(0) = 2;
-      perm(1) = 1;
-      perm(2) = 0;
-
-      Array<idx_vector> idx (dim_vector (3, 1));
-
-      // Flip Y
-      idx(0) = idx_vector::make_range (Height - 1, -1, Height);
-      idx(1) = idx_vector::colon;
-
-      // Remove alpha channel
-      idx(2) = idx_vector (0, 3);
-      retval(0) = octave_value (img.permute (perm).index(idx));
-    }
-
-  OSMesaDestroyContext (ctx);
-
-  return retval;
-
-#else
-
-  octave_unused_parameter (args);
-
-  err_disabled_feature ("__osmesa_print__", "offscreen rendering with OSMesa");
-
-#endif
-}
-
-/*
-## FIXME: osmesa does not work correctly on Windows platforms.
-##        This is not critical, since this facility will mostly be used in
-##        the future for generating the images in Octave's own documentation.
-##        For the moment, disable these tests on PC's and Macs.
-%!testif HAVE_OPENGL, HAVE_OSMESA, HAVE_GL2PS_H
-%! if (isunix ())
-%!   hf = figure ("visible", "off");
-%!   fn = tempname ();
-%!   unwind_protect
-%!     sombrero ();
-%!     __osmesa_print__ (hf, fn, "svg");
-%!     assert (stat (fn).size > 2e6);
-%!     img = __osmesa_print__ (hf);
-%!     assert (size (img), [get(hf, "position")([4, 3]), 3]);
-%!     ## Use pixel sum per RGB channel as fingerprint
-%!     img_fp = squeeze (sum (sum (img), 2));
-%!     assert (img_fp, [52942515; 54167797; 56158178], -0.05);
-%!   unwind_protect_cleanup
-%!     close (hf);
-%!     unlink (fn);
-%!   end_unwind_protect
-%! endif
-
-%!testif HAVE_OPENGL, HAVE_OSMESA, HAVE_GL2PS_H
-%! if (isunix ())
-%!   hf = figure ("visible", "off");
-%!   fn = tempname ();
-%!   unwind_protect
-%!     plot (sin (0:0.1:2*pi));
-%!     __osmesa_print__ (hf, fn, "svgis2d");
-%!     assert (stat (fn).size, 9022, -0.20);
-%!     img = __osmesa_print__ (hf);
-%!     assert (size (img), [get(hf, "position")([4, 3]), 3]);
-%!     ## Use pixel sum per RGB channel as fingerprint
-%!     img_fp = squeeze (sum (sum (img), 2));
-%!     assert (img_fp, [59281711; 59281711; 59482179], -0.05);
-%!   unwind_protect_cleanup
-%!     close (hf);
-%!     unlink (fn);
-%!   end_unwind_protect
-%! endif
-*/
--- a/libinterp/dldfcn/audiodevinfo.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/audiodevinfo.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -135,8 +135,8 @@
 
       if (! device_info)
         {
-          warning ("Octave:invalid-audio-device",
-                   "invalid audio device ID = %d", i);
+          warning_with_id ("Octave:invalid-audio-device",
+                           "invalid audio device ID = %d", i);
           continue;
         }
 
@@ -161,8 +161,8 @@
 
       if (! device_info)
         {
-          warning ("Octave:invalid-audio-device",
-                   "invalid audio device ID = %d", i);
+          warning_with_id ("Octave:invalid-audio-device",
+                           "invalid audio device ID = %d", i);
           continue;
         }
 
@@ -311,8 +311,8 @@
 
           if (! device_info)
             {
-              warning ("Octave:invalid-audio-device",
-                       "invalid audio device ID = %d", i);
+              warning_with_id ("Octave:invalid-audio-device",
+                               "invalid audio device ID = %d", i);
               continue;
             }
 
@@ -834,8 +834,8 @@
 {
   if (isplaying ())
     {
-      warning ("Octave:audio-interrupt",
-               "interrupting playing audioplayer");
+      warning_with_id ("Octave:audio-interrupt",
+                       "interrupting playing audioplayer");
       stop ();
     }
 }
@@ -874,8 +874,8 @@
   const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device);
 
   if (! device_info)
-    warning ("Octave:invalid-default-audio-device",
-             "invalid default audio device ID = %d", device);
+    warning_with_id ("Octave:invalid-default-audio-device",
+                     "invalid default audio device ID = %d", device);
 
   output_parameters.suggestedLatency
     = (device_info ? device_info->defaultHighOutputLatency : -1);
@@ -918,8 +918,8 @@
   const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device);
 
   if (! device_info)
-    warning ("Octave:invalid-default-audio-device",
-             "invalid default audio device ID = %d", device);
+    warning_with_id ("Octave:invalid-default-audio-device",
+                     "invalid default audio device ID = %d", device);
 
   output_parameters.suggestedLatency
     = (device_info ? device_info->defaultHighOutputLatency : -1);
@@ -1162,7 +1162,7 @@
   PaError err;
   err = Pa_StopStream (stream);
   if (err != paNoError)
-    error ("audiorecorder: failed to stop audio recording stream");
+    error ("audioplayer: failed to stop audio playback stream");
 }
 
 void
@@ -1174,7 +1174,7 @@
   PaError err;
   err = Pa_StartStream (stream);
   if (err != paNoError)
-    error ("audiorecorder: failed to start audio recording stream");
+    error ("audioplayer: failed to start audio playback stream");
 }
 
 PaStream *
@@ -1215,7 +1215,7 @@
   PaError err;
   err = Pa_IsStreamActive (stream);
   if (err != 0 && err != 1)
-    error ("audiorecorder: checking stream activity status failed");
+    error ("audioplayer: checking stream activity status failed");
 
   return (err == 1);
 }
@@ -1346,13 +1346,14 @@
       // FIXME: Is there a better way?
       const uint8_t *input24 = static_cast<const uint8_t *> (input);
 
-      int32_t sample_l32 = 0, sample_r32 = 0;
+      int32_t sample_l32, sample_r32;
 
       uint8_t *sample_l = reinterpret_cast<uint8_t *> (&sample_l32);
       uint8_t *sample_r = reinterpret_cast<uint8_t *> (&sample_r32);
 
       for (unsigned long i = 0; i < frames; i++)
         {
+          sample_l32 = sample_r32 = 0;
           for (int j = 0; j < 3; j++)
             {
               sample_l[j] = input24[i*channels*3 + j];
@@ -1423,13 +1424,14 @@
       // FIXME: Is there a better way?
       const uint8_t *input24 = static_cast<const uint8_t *> (input);
 
-      int32_t sample_l32 = 0, sample_r32 = 0;
+      int32_t sample_l32, sample_r32;
 
       uint8_t *sample_l = reinterpret_cast<uint8_t *> (&sample_l32);
       uint8_t *sample_r = reinterpret_cast<uint8_t *> (&sample_r32);
 
       for (unsigned long i = 0; i < frames; i++)
         {
+          sample_l32 = sample_r32 = 0;
           for (int j = 0; j < 3; j++)
             {
               sample_l[j] = input24[i*channels*3 + j];
@@ -1470,8 +1472,8 @@
 {
   if (isrecording ())
     {
-      warning ("Octave:audio-interrupt",
-               "interrupting recording audiorecorder");
+      warning_with_id ("Octave:audio-interrupt",
+                       "interrupting recording audiorecorder");
       stop ();
     }
 }
@@ -1510,8 +1512,8 @@
   const PaDeviceInfo *device_info = Pa_GetDeviceInfo (device);
 
   if (! device_info)
-    warning ("Octave:invalid-default-audio-device",
-             "invalid default audio device ID = %d", device);
+    warning_with_id ("Octave:invalid-default-audio-device",
+                     "invalid default audio device ID = %d", device);
 
   input_parameters.suggestedLatency
     = (device_info ? device_info->defaultHighInputLatency : -1);
@@ -1637,9 +1639,12 @@
 octave_value
 audiorecorder::getaudiodata (void)
 {
-  Matrix audio (2, left.size ());
-
-  for (unsigned int i = 0; i < left.size (); i++)
+  // Must get size before entering loop as the value of left.size() may change
+  // during loop with simultaneous recording and playback (bug #50674).
+  unsigned int ls = left.size ();
+  Matrix audio (2, ls);
+
+  for (unsigned int i = 0; i < ls; i++)
     {
       audio(0,i) = left[i];
       audio(1,i) = right[i];
@@ -1838,7 +1843,7 @@
                           || args(0).is_inline_function ());
 
       if (is_function)
-        error ("audioplayer: callbacks not yet implemented");
+        error ("audiorecorder: callbacks not yet implemented");
     }
 
   if (nargin >= 3)
--- a/libinterp/dldfcn/audioread.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/audioread.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -167,6 +167,9 @@
             case SF_FORMAT_PCM_32:
               ret_audio = int32NDArray (audio * 2147483648);
               break;
+            case SF_FORMAT_FLOAT:
+              ret_audio = FloatNDArray (audio);
+              break;
             default:
               ret_audio = audio;
               break;
@@ -374,7 +377,12 @@
           else if (bits == 16)
             info.format |= SF_FORMAT_PCM_16;
           else if (bits == 24)
-            info.format |= SF_FORMAT_PCM_32;
+            {
+              if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
+                info.format |= SF_FORMAT_PCM_32;
+              else
+                info.format |= SF_FORMAT_PCM_24;
+            }
           else if (bits == 32)
             {
               if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV
@@ -449,8 +457,8 @@
       sf_count_t items_written = sf_write_float (file, data+offset, chunk_size);
 
       if (items_written != chunk_size)
-        error ("audiowrite: write failed, wrote %ld of %ld items\n",
-               items_written, chunk_size);
+        error ("audiowrite: write failed, wrote %" PRId64 " of %" PRId64
+               " items\n", items_written, chunk_size);
 
       total_items_written += items_written;
       offset += chunk_size;
@@ -584,6 +592,12 @@
     case SF_FORMAT_PCM_32:
       bits = 32;
       break;
+    case SF_FORMAT_FLOAT:
+      bits = 32;
+      break;
+    case SF_FORMAT_DOUBLE:
+      bits = 64;
+      break;
     default:
       bits = -1;
       break;
--- a/libinterp/dldfcn/ccolamd.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/ccolamd.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -509,7 +509,7 @@
       OCTAVE_LOCAL_BUFFER (octave::suitesparse_integer, cmember, cslen);
       for (octave_idx_type i = 0; i < cslen; i++)
         // convert cmember from 1-based to 0-based
-        cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1);
+        cmember[i] = static_cast<octave_idx_type> (in_cmember(i) - 1);
 
       if (cslen != n_col)
         error ("csymamd: CMEMBER must be of length equal to #cols of A");
--- a/libinterp/dldfcn/chol.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/chol.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -796,7 +796,8 @@
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{R1} =} cholinsert (@var{R}, @var{j}, @var{u})
 @deftypefnx {} {[@var{R1}, @var{info}] =} cholinsert (@var{R}, @var{j}, @var{u})
-Update a Cholesky factorization given a row or column to insert in the original factored matrix.
+Update a Cholesky factorization given a row or column to insert in the
+original factored matrix.
 
 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
@@ -1050,7 +1051,8 @@
 DEFUN_DLD (choldelete, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {@var{R1} =} choldelete (@var{R}, @var{j})
-Update a Cholesky factorization given a row or column to delete from the original factored matrix.
+Update a Cholesky factorization given a row or column to delete from the
+original factored matrix.
 
 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
@@ -1174,7 +1176,8 @@
 DEFUN_DLD (cholshift, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {@var{R1} =} cholshift (@var{R}, @var{i}, @var{j})
-Update a Cholesky factorization given a range of columns to shift in the original factored matrix.
+Update a Cholesky factorization given a range of columns to shift in the
+original factored matrix.
 
 Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian
 positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper
--- a/libinterp/dldfcn/colamd.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/colamd.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -62,13 +62,12 @@
       // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k)
       Parent[k] = n ;                // parent of k is not yet known
       Flag[k] = k ;                  // mark node k as visited
-      octave_idx_type kk = (P ? P[k]  // kth original, or permuted, column
-                              : (k));
+      octave_idx_type kk = (P ? P[k] : k); // kth original, or permuted, column
       octave_idx_type p2 = cidx[kk+1];
       for (octave_idx_type p = cidx[kk] ; p < p2 ; p++)
         {
           // A (i,k) is nonzero (original or permuted A)
-          octave_idx_type i = (Pinv) ? (Pinv[ridx[p]]) : (ridx[p]);
+          octave_idx_type i = (P ? Pinv[ridx[p]] : ridx[p]);
           if (i < k)
             {
               // follow path from i to root of etree, stop at flagged node
@@ -675,7 +674,7 @@
   octave_idx_type *ridx = nullptr;
   octave_idx_type *cidx = nullptr;
 
-  if (args(0).issparse ())
+  if (! args(0).issparse ())
     error ("etree: S must be a sparse matrix");
 
   if (args(0).iscomplex ())
@@ -756,3 +755,14 @@
 
   return retval;
 }
+
+/*
+%!assert (etree (speye (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 <TYP must be a string> etree (speye (2), 3)
+%!error <is not square> etree (sprand (2, 4, .25))
+*/
--- a/libinterp/dldfcn/config-module.awk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/config-module.awk	Thu Dec 20 17:18:56 2018 -0500
@@ -49,8 +49,6 @@
   sep = " \\\n";
   print "DLDFCN_LIBS = $(DLDFCN_SRC:.cc=.la)";
   print "";
-  print "if AMCOND_ENABLE_DYNAMIC_LINKING";
-  print "";
   print "octlib_LTLIBRARIES += $(DLDFCN_LIBS)";
   print "";
   print "## Use stamp files to avoid problems with checking timestamps";
@@ -58,12 +56,6 @@
   print "";
   print "%.oct : %.la"
   print "\t$(AM_V_GEN)$(INSTALL_PROGRAM) %reldir%/.libs/$(shell $(SED) -n -e \"s/dlname='\\([^']*\\)'/\\1/p\" < $<) $@"
-  print ""
-  print "else";
-  print "";
-  print "noinst_LTLIBRARIES += $(DLDFCN_LIBS)";
-  print "";
-  print "endif";
 
   for (i = 1; i <= nfiles; i++) {
     basename = files[i];
@@ -76,19 +68,49 @@
         printf ("%%canon_reldir%%_%s_la_CPPFLAGS = $(libinterp_liboctinterp_la_CPPFLAGS) %s\n",
                 basename, cppflags[i]);
       }
-    printf ("%%canon_reldir%%_%s_la_CFLAGS = $(libinterp_liboctinterp_la_CFLAGS) %s\n",
-            basename, cppflags[i]);
-    printf ("%%canon_reldir%%_%s_la_CXXFLAGS = $(libinterp_liboctinterp_la_CXXFLAGS) %s\n",
-            basename, cppflags[i]);
     printf ("%%canon_reldir%%_%s_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED_LDFLAG) %s $(OCT_LINK_OPTS) $(WARN_LDFLAGS)\n",
             basename, ldflags[i]);
-    printf ("%%canon_reldir%%_%s_la_LIBADD = $(DLD_LIBOCTINTERP_LIBADD) liboctave/liboctave.la %s $(OCT_LINK_DEPS)\n",
+    printf ("%%canon_reldir%%_%s_la_LIBADD = $(DLD_LIBOCTINTERP_LIBADD) %s\n",
             basename, libraries[i]);
+    printf ("%%canon_reldir%%_%s_la_DEPENDENCIES = $(OCT_LINK_DEPS)\n",
+            basename);
   }
 
   print "";
   print "$(srcdir)/%reldir%/module.mk: $(srcdir)/%reldir%/config-module.sh $(srcdir)/%reldir%/config-module.awk $(srcdir)/%reldir%/module-files";
   print "\t$(AM_V_GEN)$(SHELL) $(srcdir)/%reldir%/config-module.sh $(srcdir)";
+
   print "";
-  print "libinterp_MAINTAINERCLEANFILES += $(srcdir)/%reldir%/module.mk";
+  print "DLDFCN_OCT_FILES = $(DLDFCN_LIBS:.la=.oct)";
+  print "";
+  print "DLDFCN_DEFUN_FILES = $(DLDFCN_SRC)";
+  print "";
+  print "DLDFCN_PKG_ADD_FILE = %reldir%/PKG_ADD";
+  print "";
+  print "%reldir%/PKG_ADD: $(DLDFCN_DEFUN_FILES) $(srcdir)/build-aux/mk-pkg-add.sh | %reldir%/$(octave_dirstamp)";
+  print "	$(AM_V_GEN)rm -f $@-t && \\"
+  print "	$(SHELL) $(srcdir)/build-aux/mk-pkg-add.sh \"$(srcdir)\" $(DLDFCN_DEFUN_FILES) > $@-t && \\";
+  print "	mv $@-t $@";
+  print "";
+  print "LIBINTERP_DEFUN_FILES += \\";
+  print "  $(DLDFCN_DEFUN_FILES)";
+  print "";
+  print "OCT_FILE_PKG_ADD_FILES += \\";
+  print "  $(DLDFCN_PKG_ADD_FILE)";
+  print "";
+  print "OCTAVE_INTERPRETER_TARGETS += \\";
+  print "  $(DLDFCN_OCT_FILES)";
+  print "";
+  print "OCT_FILE_LIBS += \\";
+  print " $(DLDFCN_LIBS)";
+  print "";
+  print "DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)";
+
+  print "";
+  print "libinterp_CLEANFILES += \\";
+  print "  $(DLDFCN_PKG_ADD_FILE) \\";
+  print "  $(DLDFCN_OCT_FILES)";
+  print "";
+  print "libinterp_MAINTAINERCLEANFILES += \\";
+  print "  $(srcdir)/%reldir%/module.mk";
 }
--- a/libinterp/dldfcn/convhulln.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/convhulln.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -33,7 +33,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <limits>
 #include <string>
 
@@ -254,7 +253,9 @@
             }
         }
       if (j < dim)
-        warning ("convhulln: facet %d only has %d vertices", i, j);
+        warning ("convhulln: facet %" OCTAVE_IDX_TYPE_FORMAT
+                 " only has %" OCTAVE_IDX_TYPE_FORMAT
+                 " vertices", i, j);
 
       i++;
     }
--- a/libinterp/dldfcn/dmperm.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/dmperm.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -91,7 +91,7 @@
           for (octave_idx_type i = 0; i < nc; i++)
             if (jmatch[nr+i] >= 0)
               r++;
-          retval(0) = static_cast<double>(r);
+          retval(0) = static_cast<double> (r);
         }
       else
         retval(0) = put_int (jmatch + nr, nc);
--- a/libinterp/dldfcn/gzip.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/gzip.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -61,6 +61,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "glob-match.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "str-vec.h"
 
@@ -97,7 +98,7 @@
     CFile (void) = delete;
 
     CFile (const std::string& path, const std::string& mode)
-      : m_fp (std::fopen (path.c_str (), mode.c_str ()))
+      : m_fp (octave::sys::fopen (path, mode))
     {
       if (! m_fp)
         throw std::runtime_error ("unable to open file");
@@ -483,13 +484,14 @@
       // is_dir and is_reg will return false if failed to stat.
       if (fs.is_dir ())
         {
-          sys::dir_entry dir (path);
-          if (dir)
+          string_vector dirlist;
+          std::string msg;
+
+          // Collect the whole list of filenames first, before recursion
+          // to avoid issues with infinite loop if the action generates
+          // files in the same directory (highly likely).
+          if (sys::get_dirlist (path, dirlist, msg))
             {
-              // Collect the whole list of filenames first, before recursion
-              // to avoid issues with infinite loop if the action generates
-              // files in the same directory (highly likely).
-              string_vector dirlist = dir.read ();
               for (octave_idx_type i = 0; i < dirlist.numel (); i++)
                 if (dirlist(i) != "." && dirlist(i) != "..")
                   walk (sys::file_ops::concat (path, dirlist(i)));
--- a/libinterp/dldfcn/module-files	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/module-files	Thu Dec 20 17:18:56 2018 -0500
@@ -6,7 +6,6 @@
 __init_fltk__.cc|$(FLTK_CPPFLAGS) $(FT2_CPPFLAGS) $(FONTCONFIG_CPPFLAGS)|$(FLTK_LDFLAGS) $(FT2_LDFLAGS)|$(FLTK_LIBS) $(FT2_LIBS) $(OPENGL_LIBS)
 __init_gnuplot__.cc|$(FT2_CPPFLAGS) $(FONTCONFIG_CPPFLAGS)||
 __ode15__.cc|$(SUNDIALS_XCPPFLAGS)|$(SUNDIALS_XLDFLAGS)|$(SUNDIALS_XLIBS)
-__osmesa_print__.cc|$(OSMESA_CPPFLAGS) $(FT2_CPPFLAGS)|$(OSMESA_LDFLAGS)|$(OSMESA_LIBS)
 __voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS)
 amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS)
 audiodevinfo.cc|$(PORTAUDIO_CPPFLAGS)|$(PORTAUDIO_LDFLAGS)|$(PORTAUDIO_LIBS)
--- a/libinterp/dldfcn/qr.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/qr.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -328,7 +328,9 @@
                             q.R (economy));
               if (arg.rows () < arg.columns ())
                 warning ("qr: non minimum norm solution for under-determined "
-                         "problem %dx%d", arg.rows (), arg.columns ());
+                         "problem %" OCTAVE_IDX_TYPE_FORMAT
+                         "x%" OCTAVE_IDX_TYPE_FORMAT,
+                         arg.rows (), arg.columns ());
             }
           else if (nargout > 1)
             retval = ovl (q.Q (), q.R (economy));
@@ -344,7 +346,9 @@
               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 %dx%d", arg.rows (), arg.columns ());
+                         "problem %" OCTAVE_IDX_TYPE_FORMAT
+                         "x%" OCTAVE_IDX_TYPE_FORMAT,
+                         arg.rows (), arg.columns ());
             }
           else if (nargout > 1)
             retval = ovl (q.Q (), q.R (economy));
@@ -1093,7 +1097,8 @@
 DEFUN_DLD (qrinsert, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {[@var{Q1}, @var{R1}] =} qrinsert (@var{Q}, @var{R}, @var{j}, @var{x}, @var{orient})
-Update a QR factorization given a row or column to insert in the original factored matrix.
+Update a QR factorization given a row or column to insert in the original
+factored matrix.
 
 
 Given a QR@tie{}factorization of a real or complex matrix
@@ -1292,7 +1297,8 @@
 DEFUN_DLD (qrdelete, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {[@var{Q1}, @var{R1}] =} qrdelete (@var{Q}, @var{R}, @var{j}, @var{orient})
-Update a QR factorization given a row or column to delete from the original factored matrix.
+Update a QR factorization given a row or column to delete from the original
+factored matrix.
 
 Given a QR@tie{}factorization of a real or complex matrix
 @w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
@@ -1539,7 +1545,8 @@
 DEFUN_DLD (qrshift, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {[@var{Q1}, @var{R1}] =} qrshift (@var{Q}, @var{R}, @var{i}, @var{j})
-Update a QR factorization given a range of columns to shift in the original factored matrix.
+Update a QR factorization given a range of columns to shift in the original
+factored matrix.
 
 Given a QR@tie{}factorization of a real or complex matrix
 @w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and
--- a/libinterp/dldfcn/symbfact.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/dldfcn/symbfact.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -377,7 +377,7 @@
   CHOLMOD_NAME(finish) (cm);
 
   if (! err_msg.empty ())
-    error (err_msg.c_str ());
+    error ("%s", err_msg.c_str ());
 
   return retval;
 
--- a/libinterp/mk-builtins.pl	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/mk-builtins.pl	Thu Dec 20 17:18:56 2018 -0500
@@ -18,7 +18,6 @@
 # along with Octave; see the file COPYING.  If not, see
 # <https://www.gnu.org/licenses/>.
 
-$defun_dld_are_built_in = 0;
 $make_header = 0;
 $make_source = 0;
 
@@ -40,13 +39,6 @@
 
       $make_source = 1;
     }
-  elsif ($opt eq "--disable-dl")
-    {
-      ## If DLD functions are disabled, then DEFUN_DLD functions are
-      ## built-in instead of being dynamically loaded so they will also
-      ## need to be installed.
-      $defun_dld_are_built_in= 1;
-    }
   else
     {
       $srcdir = "$opt";
@@ -56,7 +48,7 @@
     }
 }
 
-die "usage: mk-builtins.pl --header|--source [--disable-dl] SRCDIR -- f1 f2 ..." if (! @ARGV);
+die "usage: mk-builtins.pl --header|--source SRCDIR -- f1 f2 ..." if (! @ARGV);
 
 die "mk-builtins.pl: one of --header or --source must be specified" if (! $make_header && ! $make_source);
 
@@ -103,19 +95,6 @@
         $name = $2;
         $is_method = ($1 eq "METHOD");
       }
-      elsif ($defun_dld_are_built_in)
-      {
-        if (/^[ \t]*DEF(METHOD|UN)_DLD[ \t]*\( *([^ ,]*).*$/)
-        {
-          $name = "F$2";
-          $is_method = ($1 eq "METHOD");
-        }
-        elsif (/^[ \t]*DEF(METHOD|UN)X_DLD[ \t]*\( *"[^"]*" *, *([^ ,]*).*$/)
-        {
-          $name = "$2";
-          $is_method = ($1 eq "METHOD");
-        }
-      }
 
       if ($name)
       {
@@ -169,7 +148,7 @@
     }
 
     ($fcn = $arg) =~ s,.*/,,;
-    $fcn =~ s/\.(cc|cpp|in\.cc|in\.yy|ll)$//;
+    $fcn =~ s/\.(cc|cpp|in\.cc|yy|ll)$//;
     $fcn =~ s/-/_/g;
     $fcn = "install_${fcn}_fcns";
 
@@ -219,21 +198,6 @@
         $alias = "$1";
         $name = "$2";
       }
-      elsif ($defun_dld_are_built_in)
-      {
-        if ($line =~ /^ *DEF(METHOD|UN)_DLD *\( *([^ ,]*) *,.*$/)
-        {
-          $type = "fun";
-          $fname = "F$2";
-          $name = "$2";
-        }
-        elsif ($line =~ /^ *DEF(METHOD|UN)X_DLD *\( *"([^"]*)" *, *([^ ,]*) *,.*$/)
-        {
-          $type = "fun";
-          $fname = "$3";
-          $name = "$2";
-        }
-      }
 
       if ($type eq "fun")
       {
--- a/libinterp/mk-pkg-add.sh	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-#! /bin/sh
-#
-# Copyright (C) 2005-2018 John W. Eaton
-#
-# 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/>.
-
-## Attempt to get traditional sort behavior based on byte values.
-LC_ALL=C
-export LC_ALL
-
-set -e
-
-SED=${SED:-sed}
-
-srcdir="$1"
-shift
-
-for arg
-do
-  src_file="$srcdir/$arg"
-
-  if [ -f "$src_file" ]; then
-
-    ## Compute and print the autoloads.
-
-    base=`basename "$src_file" | $SED 's/\.cc$//'`
-    fcns=`$SED -n -e 's/^ *DEFMETHOD_DLD *( *\([^, ]*\) *,.*$/\1/p' \
-                  -e 's/^ *DEFMETHODX_DLD *( *"\([^"]*\)".*$/\1/p' \
-                  -e 's/^ *DEFUN_DLD *( *\([^, ]*\) *,.*$/\1/p' \
-                  -e 's/^ *DEFUNX_DLD *( *"\([^"]*\)".*$/\1/p' "$src_file" | \
-          sort -u`
-    if [ -n "$fcns" ]; then
-      for n in $fcns; do
-        if [ "$n" = "$base" ]; then
-          true
-        else
-          echo "autoload (\"$n\", \"$base.oct\");"
-        fi
-      done
-    fi
-
-    ## Process PKG_ADD directives after autoloads so that all
-    ## necessary functions can be found before they are used.
-
-    $SED -n -e 's,^//* *PKG_ADD: *,,p' \
-            -e 's,^/\* *PKG_ADD: *\(.*\) *\*/ *$,\1,p' "$src_file"
-
-  fi
-done
-
-exit $?
--- a/libinterp/mk-version-h.in.sh	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#! /bin/sh
-#
-# Copyright (C) 2016-2018 John W. Eaton
-#
-# 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_API_VERSION="@OCTAVE_API_VERSION@"
-OCTAVE_COPYRIGHT="@OCTAVE_COPYRIGHT@"
-OCTAVE_MAJOR_VERSION="@OCTAVE_MAJOR_VERSION@"
-OCTAVE_MINOR_VERSION="@OCTAVE_MINOR_VERSION@"
-OCTAVE_PATCH_VERSION="@OCTAVE_PATCH_VERSION@"
-OCTAVE_RELEASE_DATE="@OCTAVE_RELEASE_DATE@"
-OCTAVE_VERSION="@OCTAVE_VERSION@"
-
-$SED \
-  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by mk-version-h.|" \
-  -e "s|%OCTAVE_API_VERSION%|\"${OCTAVE_API_VERSION}\"|" \
-  -e "s|%OCTAVE_COPYRIGHT%|\"${OCTAVE_COPYRIGHT}\"|" \
-  -e "s|%OCTAVE_MAJOR_VERSION%|${OCTAVE_MAJOR_VERSION}|" \
-  -e "s|%OCTAVE_MINOR_VERSION%|${OCTAVE_MINOR_VERSION}|" \
-  -e "s|%OCTAVE_PATCH_VERSION%|${OCTAVE_PATCH_VERSION}|" \
-  -e "s|%OCTAVE_RELEASE_DATE%|\"${OCTAVE_RELEASE_DATE}\"|" \
-  -e "s|%OCTAVE_VERSION%|\"${OCTAVE_VERSION}\"|"
--- a/libinterp/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -1,3 +1,5 @@
+LIBINTERP_DEFUN_FILES =
+
 %canon_reldir%_EXTRA_DIST =
 
 %canon_reldir%_CLEANFILES =
@@ -22,11 +24,9 @@
   $(HDF5_CPPFLAGS) \
   $(MAGICK_CPPFLAGS)
 
-%canon_reldir%_liboctinterp_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
+octlib_LTLIBRARIES += %reldir%/liboctinterp.la
 
-%canon_reldir%_liboctinterp_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
-
-octlib_LTLIBRARIES += %reldir%/liboctinterp.la
+%canon_reldir%_pkgconfig_DATA = %reldir%/octinterp.pc
 
 BUILT_SOURCES += \
   %reldir%/builtin-defun-decls.h \
@@ -37,19 +37,15 @@
   %reldir%/corefcn/oct-tex-parser.h \
   %reldir%/corefcn/oct-tex-symbols.cc \
   %reldir%/parse-tree/oct-gperf.h \
-  %reldir%/parse-tree/oct-parse.h \
-  %reldir%/version.h
+  %reldir%/parse-tree/oct-parse.h
 
 ULT_PARSER_SRC := \
-  %reldir%/corefcn/oct-tex-lexer.in.ll \
-  %reldir%/corefcn/oct-tex-parser.in.yy \
-  %reldir%/parse-tree/oct-parse.in.yy
+  %reldir%/corefcn/oct-tex-lexer.in.ll
 
 GENERATED_PARSER_FILES := \
   %reldir%/corefcn/oct-tex-lexer.ll \
   %reldir%/corefcn/oct-tex-parser.h \
-  %reldir%/corefcn/oct-tex-parser.yy \
-  %reldir%/parse-tree/oct-parse.yy
+  %reldir%/parse-tree/oct-parse.h
 
 ## These generated files are included in the source distribution to
 ## avoid needing certain tools to build from a distribution tarball.
@@ -57,10 +53,8 @@
 LIBINTERP_BUILT_DISTFILES = \
   $(GENERATED_PARSER_FILES) \
   $(OPT_HANDLERS) \
-  %reldir%/corefcn/oct-tex-parser.h \
   %reldir%/corefcn/oct-tex-symbols.cc \
-  %reldir%/parse-tree/oct-gperf.h \
-  %reldir%/parse-tree/oct-parse.h
+  %reldir%/parse-tree/oct-gperf.h
 
 ## Files that are created during build process and installed,
 ## BUT not distributed in tarball.
@@ -75,8 +69,7 @@
   %reldir%/corefcn/mxarray.h \
   %reldir%/corefcn/oct-errno.cc \
   %reldir%/liboctinterp-build-info.cc \
-  %reldir%/operators/ops.cc \
-  %reldir%/version.h
+  %reldir%/operators/ops.cc
 
 %canon_reldir%_EXTRA_DIST += \
   %reldir%/DOCSTRINGS \
@@ -85,15 +78,9 @@
   %reldir%/mk-build-env-features.sh \
   %reldir%/mk-builtins.pl \
   %reldir%/mk-doc.pl \
-  %reldir%/mk-pkg-add.sh \
-  %reldir%/mk-version-h.in.sh \
   %reldir%/op-kw-docs \
-  %reldir%/version.in.h \
   $(LIBINTERP_BUILT_DISTFILES)
 
-GEN_CONFIG_SHELL += \
-  %reldir%/mk-version-h.sh
-
 octinclude_HEADERS += \
   %reldir%/build-env.h \
   %reldir%/liboctinterp-build-info.h \
@@ -112,12 +99,10 @@
   %reldir%/builtin-defun-decls.h \
   %reldir%/corefcn/graphics-props.cc \
   %reldir%/corefcn/graphics.h \
-  %reldir%/corefcn/mxarray.h \
-  %reldir%/version.h
+  %reldir%/corefcn/mxarray.h
 
 DIST_SRC += \
   %reldir%/octave.cc \
-  %reldir%/version.cc \
   $(OCTAVE_VALUE_SRC) \
   $(PARSE_TREE_SRC) \
   $(COREFCN_SRC)
@@ -129,19 +114,11 @@
 include %reldir%/corefcn/module.mk
 include %reldir%/dldfcn/module.mk
 
-if AMCOND_ENABLE_DYNAMIC_LINKING
-  OCT_FILES = $(DLDFCN_LIBS:.la=.oct)
-  DLD_LIBOCTINTERP_LIBADD = %reldir%/liboctinterp.la
-  LIBINTERP_DLDFCN_LIBADD =
-else
-  OCT_FILES =
-  DLD_LIBOCTINTERP_LIBADD =
-  LIBINTERP_DLDFCN_LIBADD = $(DLDFCN_LIBS)
-endif
+DLD_LIBOCTINTERP_LIBADD = $(OCT_LINK_DEPS)
+LIBINTERP_DLDFCN_LIBADD =
 
 %canon_reldir%_liboctinterp_la_SOURCES = \
   %reldir%/octave.cc \
-  %reldir%/version.cc \
   $(LIBINTERP_OPERATORS_SRC) \
   $(TEMPLATE_INST_SRC)
 
@@ -155,8 +132,7 @@
   %reldir%/corefcn/mxarray.h \
   %reldir%/corefcn/oct-errno.cc \
   %reldir%/liboctinterp-build-info.cc \
-  %reldir%/operators/ops.cc \
-  %reldir%/version.h
+  %reldir%/operators/ops.cc
 
 %canon_reldir%_liboctinterp_la_LIBADD = \
   %reldir%/octave-value/liboctave-value.la \
@@ -171,7 +147,9 @@
     liboctave/external/blas-xtra/libxerbla.la
 endif
 
-# Increment these as needed and according to the rules in the libtool manual:
+## Increment the following version numbers as needed and according
+## to the rules in the etc/HACKING.md file:
+
 %canon_reldir%_liboctinterp_current = 6
 %canon_reldir%_liboctinterp_revision = 0
 %canon_reldir%_liboctinterp_age = 0
@@ -192,17 +170,10 @@
 LIBINTERP_FOUND_DEFUN_FILES := \
   $(shell $(SHELL) $(srcdir)/build-aux/find-defun-files.sh "$(srcdir)" $(ULT_DIST_SRC))
 
-BUILT_IN_DEFUN_FILES = $(OPT_HANDLERS) $(LIBINTERP_FOUND_DEFUN_FILES)
-
-DLDFCN_DEFUN_FILES = $(DLDFCN_SRC)
+BUILT_IN_DEFUN_FILES := $(OPT_HANDLERS) $(LIBINTERP_FOUND_DEFUN_FILES)
 
-if AMCOND_ENABLE_DYNAMIC_LINKING
-  DEFUN_FILES = $(BUILT_IN_DEFUN_FILES)
-else
-  DEFUN_FILES = $(BUILT_IN_DEFUN_FILES) $(DLDFCN_DEFUN_FILES)
-endif
-
-LIBINTERP_DEFUN_FILES = $(BUILT_IN_DEFUN_FILES) $(DLDFCN_DEFUN_FILES)
+LIBINTERP_DEFUN_FILES += \
+  $(BUILT_IN_DEFUN_FILES)
 
 ## FIXME: The following two variables are deprecated and should be removed
 ##        in Octave version 3.12.
@@ -243,17 +214,10 @@
 	$(SHELL) $(srcdir)/%reldir%/mk-build-env-features.sh $< > $@-t && \
 	mv $@-t $@
 
-%reldir%/version.h: %reldir%/version.in.h %reldir%/mk-version-h.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,%reldir%/mk-version-h.sh)
-
 %reldir%/liboctinterp-build-info.cc: %reldir%/liboctinterp-build-info.in.cc HG-ID | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)$(build-info-commands)
 
-if AMCOND_ENABLE_DYNAMIC_LINKING
-  mkbuiltins_dld_opt =
-else
-  mkbuiltins_dld_opt = --disable-dl
-endif
+mkbuiltins_dld_opt =
 
 %reldir%/builtins.cc: $(LIBINTERP_DEFUN_FILES) %reldir%/mk-builtins.pl | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)rm -f $@-t && \
@@ -265,15 +229,6 @@
 	$(PERL) $(srcdir)/%reldir%/mk-builtins.pl --header $(mkbuiltins_dld_opt) "$(srcdir)" -- $(LIBINTERP_DEFUN_FILES) > $@-t && \
 	$(simple_move_if_change_rule)
 
-if AMCOND_ENABLE_DYNAMIC_LINKING
-DLDFCN_PKG_ADD_FILE = %reldir%/dldfcn/PKG_ADD
-
-%reldir%/dldfcn/PKG_ADD: $(DLDFCN_DEFUN_FILES) %reldir%/mk-pkg-add.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)rm -f $@-t && \
-	$(SHELL) $(srcdir)/%reldir%/mk-pkg-add.sh "$(srcdir)" $(DLDFCN_DEFUN_FILES) > $@-t && \
-	mv $@-t $@
-endif
-
 DOCSTRING_FILES += %reldir%/DOCSTRINGS
 
 %reldir%/DOCSTRINGS: $(LIBINTERP_DEFUN_FILES) %reldir%/op-kw-docs | %reldir%/$(octave_dirstamp)
@@ -282,8 +237,6 @@
 	$(call move_if_change_rule,%reldir%/DOCSTRINGS-t,$@)
 
 OCTAVE_INTERPRETER_TARGETS += \
-  $(OCT_FILES) \
-  $(DLDFCN_PKG_ADD_FILE) \
   $(LIBINTERP_TST_FILES)
 
 DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
@@ -292,36 +245,6 @@
 
 uninstall-local: uninstall-oct uninstall-built-in-docstrings
 
-if AMCOND_ENABLE_DYNAMIC_LINKING
-install-oct:
-	$(MKDIR_P) $(DESTDIR)$(octfiledir)
-	if [ -n "`cat $(DLDFCN_PKG_ADD_FILE)`" ]; then \
-	  $(INSTALL_DATA) $(DLDFCN_PKG_ADD_FILE) $(DESTDIR)$(octfiledir)/PKG_ADD; \
-	fi
-	cd $(DESTDIR)$(octlibdir) && \
-	for ltlib in $(DLDFCN_LIBS); do \
-	  f=`echo $$ltlib | $(SED) 's,.*/,,'`; \
-	  dl=`$(SED) -n -e "s/dlname='\([^']*\)'/\1/p" < $$f`; \
-	  if [ -n "$$dl" ]; then \
-	    $(INSTALL_PROGRAM) $$dl $(DESTDIR)$(octfiledir)/`echo $$f | $(SED) 's,^lib,,; s,\.la$$,.oct,'`; \
-	  else \
-	    echo "error: dlname is empty in $$ltlib!"; \
-	    exit 1; \
-	  fi; \
-	  lnames=`$(SED) -n -e "s/library_names='\([^']*\)'/\1/p" < $$f`; \
-	  if [ -n "$$lnames" ]; then \
-	    rm -f $$f $$lnames $$dl; \
-	  fi \
-	done
-
-uninstall-oct:
-	for f in $(notdir $(OCT_FILES)); do \
-	  rm -f $(DESTDIR)$(octfiledir)/$$f; \
-	done
-	rm -f $(DESTDIR)$(octfiledir)/PKG_ADD
-endif
-.PHONY: install-oct uninstall-oct
-
 install-built-in-docstrings: %reldir%/DOCSTRINGS
 	$(MKDIR_P) $(DESTDIR)$(octetcdir)
 	$(INSTALL_DATA) $< $(DESTDIR)$(octetcdir)/built-in-docstrings
@@ -331,16 +254,19 @@
 	rm -f $(DESTDIR)$(octetcdir)/built-in-docstrings
 .PHONY: uninstall-built-in-docstrings
 
+pkgconfig_DATA += $(%canon_reldir%_pkgconfig_DATA)
+
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
 
 %canon_reldir%_CLEANFILES += \
-  $(DLDFCN_PKG_ADD_FILE) \
   $(LIBINTERP_BUILT_NODISTFILES) \
   $(LIBINTERP_TST_FILES) \
-  $(OCT_FILES) \
   %reldir%/corefcn/oct-tex-parser.output \
   %reldir%/parse-tree/oct-parse.output
 
+%canon_reldir%_DISTCLEANFILES += \
+  $(%canon_reldir%_pkgconfig_DATA)
+
 %canon_reldir%_MAINTAINERCLEANFILES += \
   %reldir%/DOCSTRINGS \
   $(LIBINTERP_BUILT_DISTFILES)
--- a/libinterp/octave-value/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -146,8 +146,4 @@
   $(HDF5_CPPFLAGS) \
   $(JAVA_CPPFLAGS)
 
-%canon_reldir%_liboctave_value_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
-
-%canon_reldir%_liboctave_value_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
-
 %canon_reldir%_liboctave_value_la_LIBADD = $(JAVA_LIBS)
--- a/libinterp/octave-value/ov-base-diag.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-diag.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,9 @@
 // C++ source files that should have included config.h before including
 // this file.
 
-#include <iostream>
+#include <istream>
+#include <ostream>
+#include <sstream>
 
 #include "mach-info.h"
 #include "lo-ieee.h"
--- a/libinterp/octave-value/ov-base-diag.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-diag.h	Thu Dec 20 17:18:56 2018 -0500
@@ -80,7 +80,7 @@
 
   dim_vector dims (void) const { return matrix.dims (); }
 
-  octave_idx_type nnz (void) const { return to_dense ().nnz (); }
+  octave_idx_type nnz (void) const { return diag ().nnz (); }
 
   octave_value reshape (const dim_vector& new_dims) const
   { return to_dense ().reshape (new_dims); }
--- a/libinterp/octave-value/ov-base-int.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-int.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,10 @@
 // C++ source files that should have included config.h before including
 // this file.
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
+#include <sstream>
 #include <vector>
 
 #include "dNDArray.h"
--- a/libinterp/octave-value/ov-base-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 // C++ source files that should have included config.h before including
 // this file.
 
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
 #include "Array-util.h"
 
--- a/libinterp/octave-value/ov-base-scalar.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-scalar.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 // C++ source files that should have included config.h before including
 // this file.
 
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
 #include "oct-inttypes.h"
 
--- a/libinterp/octave-value/ov-base-sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base-sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,9 @@
 // this file.
 
 #include <iomanip>
-#include <iostream>
+#include <istream>
+#include <ostream>
+#include <sstream>
 
 #include "ovl.h"
 #include "ov-base.h"
--- a/libinterp/octave-value/ov-base.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "lo-ieee.h"
 #include "lo-mappers.h"
@@ -192,7 +193,7 @@
 octave_idx_type
 octave_base_value::numel (const octave_value_list& idx)
 {
-  return dims_to_numel (dims (), idx);
+  return octave::dims_to_numel (dims (), idx);
 }
 
 octave_value
@@ -1410,7 +1411,7 @@
   Cell type_field (1, len);
   Cell subs_field (1, len);
 
-  std::list<octave_value_list>::const_iterator p = idx.begin ();
+  auto p = idx.begin ();
 
   for (size_t i = 0; i < len; i++)
     {
@@ -1460,22 +1461,6 @@
   return m;
 }
 
-bool
-called_from_builtin (void)
-{
-  octave::call_stack& cs = octave::__get_call_stack__ ("called_from_builtin");
-
-  octave_function *fcn = cs.caller ();
-
-  // FIXME: we probably need a better check here, or some other
-  // mechanism to avoid overloaded functions when builtin is used.
-  // For example, what if someone overloads the builtin function?
-  // Also, are there other places where using builtin is not properly
-  // avoiding dispatch?
-
-  return (fcn && fcn->name () == "builtin");
-}
-
 void
 install_base_type_conversions (octave::type_info& ti)
 {
--- a/libinterp/octave-value/ov-base.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-base.h	Thu Dec 20 17:18:56 2018 -0500
@@ -888,8 +888,4 @@
                const std::list<octave_value_list>& idx,
                const std::string& who);
 
-// Tells whether some regular octave_value_base methods are being called from
-// within the "builtin" function.
-extern OCTINTERP_API bool called_from_builtin (void);
-
 #endif
--- a/libinterp/octave-value/ov-bool-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-bool-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "dNDArray.h"
--- a/libinterp/octave-value/ov-bool-mat.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-bool-mat.h	Thu Dec 20 17:18:56 2018 -0500
@@ -169,7 +169,7 @@
     octave_idx_type nel = numel ();
 
     for (octave_idx_type i = 0; i < nel; i++)
-      retval(i) = static_cast<char>(matrix(i));
+      retval(i) = static_cast<char> (matrix(i));
 
     return retval;
   }
--- a/libinterp/octave-value/ov-bool-sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-bool-sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "dim-vector.h"
@@ -166,7 +166,7 @@
 
   for (octave_idx_type j = 0; j < nc; j++)
     for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
-      retval(matrix.ridx (i) + nr * j) = static_cast<char>(matrix.data (i));
+      retval(matrix.ridx (i) + nr * j) = static_cast<char> (matrix.data (i));
 
   return retval;
 }
--- a/libinterp/octave-value/ov-bool.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-bool.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "oct-inttypes.h"
 
--- a/libinterp/octave-value/ov-cell.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-cell.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iomanip>
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <sstream>
 #include <vector>
 #include <queue>
@@ -1251,7 +1251,7 @@
       break;
 
     case 1:
-      get_dimensions (args(0), "cell", dims);
+      octave::get_dimensions (args(0), "cell", dims);
       break;
 
     default:
@@ -1267,7 +1267,7 @@
 
   dims.chop_trailing_singletons ();
 
-  check_dimensions (dims, "cell");
+  octave::check_dimensions (dims, "cell");
 
   return ovl (Cell (dims));
 }
--- a/libinterp/octave-value/ov-ch-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-ch-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
 #endif
 
 #include <cctype>
-#include <iostream>
+#include <ostream>
 
 #include "dNDArray.h"
 #include "fNDArray.h"
@@ -41,6 +41,9 @@
 
 #include "lo-ieee.h"
 #include "mx-base.h"
+#include "unicase-wrappers.h"
+#include "unictype-wrappers.h"
+#include "unistr-wrappers.h"
 
 #include "mxarray.h"
 #include "ov-base.h"
@@ -258,20 +261,80 @@
     case umap_ ## UMAP:                                               \
       return octave_value (matrix.map<TYPE, int (&) (int)> (FCN))
 
-    STRING_MAPPER (xisalnum, std::isalnum, bool);
-    STRING_MAPPER (xisalpha, std::isalpha, bool);
     STRING_MAPPER (xisascii, xisascii, bool);
-    STRING_MAPPER (xiscntrl, std::iscntrl, bool);
-    STRING_MAPPER (xisdigit, std::isdigit, bool);
-    STRING_MAPPER (xisgraph, std::isgraph, bool);
-    STRING_MAPPER (xislower, std::islower, bool);
-    STRING_MAPPER (xisprint, std::isprint, bool);
-    STRING_MAPPER (xispunct, std::ispunct, bool);
-    STRING_MAPPER (xisspace, std::isspace, bool);
-    STRING_MAPPER (xisupper, std::isupper, bool);
-    STRING_MAPPER (xisxdigit, std::isxdigit, bool);
-    STRING_MAPPER (xtolower, std::tolower, char);
-    STRING_MAPPER (xtoupper, std::toupper, char);
+
+#define STRING_U8_MAPPER(UMAP,FCN)                                             \
+    case umap_ ## UMAP:                                                        \
+      {                                                                        \
+        charNDArray in_m = matrix;                                             \
+        Array<octave_idx_type> p (dim_vector (matrix.ndims (), 1));            \
+        if (matrix.ndims () > 1)                                               \
+          {                                                                    \
+            for (octave_idx_type i=0; i < matrix.ndims (); i++)                \
+              p(i) = i;                                                        \
+            p(0) = 1;                                                          \
+            p(1) = 0;                                                          \
+            in_m = matrix.permute (p);                                         \
+          }                                                                    \
+        boolNDArray b_array = boolNDArray (in_m.dims ());                      \
+        const uint8_t *in = reinterpret_cast<const uint8_t *> (in_m.data ());  \
+        uint32_t uc;                                                           \
+        for (octave_idx_type i = 0; i < in_m.numel (); )                       \
+        {                                                                      \
+          int mblen = octave_u8_strmbtouc_wrapper (&uc, in + i);               \
+          if (mblen < 1)                                                       \
+            mblen = 1;                                                         \
+          bool is_upper = FCN (uc);                                            \
+          for (int j = 0; j < mblen; j++)                                      \
+            b_array(i+j) = is_upper;                                           \
+          i += mblen;                                                          \
+        }                                                                      \
+        return octave_value ((matrix.ndims () > 1) ? b_array.permute (p, true) \
+                                                   : b_array);                 \
+      }
+
+    STRING_U8_MAPPER (xisalnum, octave_uc_is_alnum_wrapper);
+    STRING_U8_MAPPER (xisalpha, octave_uc_is_alpha_wrapper);
+    STRING_U8_MAPPER (xiscntrl, octave_uc_is_cntrl_wrapper);
+    STRING_U8_MAPPER (xisdigit, octave_uc_is_digit_wrapper);
+    STRING_U8_MAPPER (xisgraph, octave_uc_is_graph_wrapper);
+    STRING_U8_MAPPER (xislower, octave_uc_is_lower_wrapper);
+    STRING_U8_MAPPER (xisprint, octave_uc_is_print_wrapper);
+    STRING_U8_MAPPER (xispunct, octave_uc_is_punct_wrapper);
+    STRING_U8_MAPPER (xisspace, octave_uc_is_space_wrapper);
+    STRING_U8_MAPPER (xisupper, octave_uc_is_upper_wrapper);
+    STRING_U8_MAPPER (xisxdigit, octave_uc_is_xdigit_wrapper);
+
+#define STRING_U8_FCN(UMAP,U8_FCN,STD_FCN)                                     \
+    case umap_ ## UMAP:                                                        \
+      {                                                                        \
+        charNDArray in_m = matrix;                                             \
+        Array<octave_idx_type> p (dim_vector (matrix.ndims (), 1));            \
+        if (matrix.ndims () > 1)                                               \
+          {                                                                    \
+            for (octave_idx_type i=0; i < matrix.ndims (); i++)                \
+              p(i) = i;                                                        \
+            p(0) = 1;                                                          \
+            p(1) = 0;                                                          \
+            in_m = matrix.permute (p);                                         \
+          }                                                                    \
+        size_t output_length = in_m.numel ();                                  \
+        charNDArray ch_array = charNDArray (in_m.dims ());                     \
+        const uint8_t *in = reinterpret_cast<const uint8_t *> (in_m.data ());  \
+        uint8_t *buf = reinterpret_cast<uint8_t *> (ch_array.fortran_vec ());  \
+        U8_FCN (in, matrix.numel (), nullptr, buf, &output_length);            \
+        if (output_length != static_cast<size_t> (matrix.numel ()))            \
+          {                                                                    \
+            warning_with_id ("octave:multi_byte_char_length",                  \
+                             "UMAP: Possible multi-byte error.");              \
+            return octave_value (matrix.map<char, int (&) (int)> (STD_FCN));   \
+          }                                                                    \
+        return octave_value ((matrix.ndims () > 1) ? ch_array.permute (p, true)\
+                                                   : ch_array);                \
+      }
+
+    STRING_U8_FCN (xtolower, octave_u8_tolower_wrapper, std::tolower);
+    STRING_U8_FCN (xtoupper, octave_u8_toupper_wrapper, std::toupper);
 
     // For Matlab compatibility, these should work on ASCII values
     // without error or warning.
--- a/libinterp/octave-value/ov-class.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-class.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "byte-swap.h"
@@ -293,7 +294,7 @@
 Matrix
 octave_class::size (void)
 {
-  if (in_class_method () || called_from_builtin ())
+  if (in_class_method ())
     return octave_base_value::size ();
 
   Matrix retval (1, 2, 1.0);
@@ -333,7 +334,7 @@
 octave_idx_type
 octave_class::numel (const octave_value_list& idx)
 {
-  if (in_class_method () || called_from_builtin ())
+  if (in_class_method ())
     return octave_base_value::numel (idx);
 
   octave_idx_type retval = -1;
@@ -373,7 +374,7 @@
 {
   octave_value_list retval;
 
-  if (in_class_method () || called_from_builtin ())
+  if (in_class_method ())
     {
       // FIXME: this block of code is the same as the body of
       // octave_struct::subsref.  Maybe it could be shared instead of
@@ -387,7 +388,7 @@
           {
             if (type.length () > 1 && type[1] == '.')
               {
-                std::list<octave_value_list>::const_iterator p = idx.begin ();
+                auto p = idx.begin ();
                 octave_value_list key_idx = *++p;
 
                 Cell tmp = dotref (key_idx);
@@ -534,7 +535,7 @@
 {
   octave_value retval;
 
-  if (! (in_class_method () || called_from_builtin ()))
+  if (! in_class_method ())
     {
       octave::symbol_table& symtab
         = octave::__get_symbol_table__ ("octave_class::subsasgn_common");
@@ -635,7 +636,7 @@
           {
             if (type.length () > 1 && type[1] == '.')
               {
-                std::list<octave_value_list>::const_iterator p = idx.begin ();
+                auto p = idx.begin ();
                 octave_value_list t_idx = *p;
 
                 octave_value_list key_idx = *++p;
@@ -689,7 +690,7 @@
             std::string next_type = type.substr (1);
 
             Cell tmpc (1, 1);
-            octave_map::iterator pkey = map.seek (key);
+            auto pkey = map.seek (key);
             if (pkey != map.end ())
               {
                 map.contents (pkey).make_unique ();
@@ -730,7 +731,7 @@
       {
         if (n > 1 && type[1] == '.')
           {
-            std::list<octave_value_list>::const_iterator p = idx.begin ();
+            auto p = idx.begin ();
             octave_value_list key_idx = *++p;
 
             assert (key_idx.length () == 1);
@@ -846,7 +847,7 @@
 
   size_t retval = 0;
 
-  for (octave_map::const_iterator it = map.begin (); it != map.end (); it++)
+  for (auto it = map.cbegin (); it != map.cend (); it++)
     {
       std::string key = map.key (it);
 
@@ -925,7 +926,7 @@
     {
       for (auto& par : parent_list)
         {
-          octave_map::iterator smap = map.seek (par);
+          auto smap = map.seek (par);
 
           Cell& tmp = map.contents (smap);
 
@@ -1124,7 +1125,7 @@
   std::string dbgstr = "dork";
 
   // First, check to see if there might be an issue with inheritance.
-  for (octave_map::const_iterator it = map.begin (); it != map.end (); it++)
+  for (auto it = map.cbegin (); it != map.cend (); it++)
     {
       std::string key = map.key (it);
       Cell        val = map.contents (it);
@@ -1187,7 +1188,7 @@
 
   os << "# length: " << m.nfields () << "\n";
 
-  octave_map::iterator i = m.begin ();
+  auto i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
@@ -1293,7 +1294,7 @@
   int32_t len = m.nfields ();
   os.write (reinterpret_cast<char *> (&len), 4);
 
-  octave_map::iterator i = m.begin ();
+  auto i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
@@ -1705,12 +1706,12 @@
   if (nparents () != obj.nparents ())
     error ("mismatch in number of parent classes");
 
-  std::list<std::string> obj_parents
+  const std::list<std::string> obj_parents
     = obj.parent_class_name_list ();
-  std::list<std::string> pnames = parents ();
+  const std::list<std::string> pnames = parents ();
 
-  std::list<std::string>::const_iterator p = obj_parents.begin ();
-  std::list<std::string>::const_iterator q = pnames.begin ();
+  auto p = obj_parents.begin ();
+  auto q = pnames.begin ();
 
   while (p != obj_parents.end ())
     {
--- a/libinterp/octave-value/ov-classdef.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-classdef.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -364,6 +364,22 @@
             panic_impossible ();
         }
     }
+  else if (acc.isobject ())
+    {
+      cdef_class ctx = get_class_context ();
+
+      // At this point, a class context is always required.
+      if (ctx.ok ())
+        {
+          if (ctx == cls)
+            return true;
+
+          cdef_class acc_cls (to_cdef (acc));
+
+          if (is_superclass (acc_cls, ctx))
+            return true;
+        }
+    }
   else if (acc.iscell ())
     {
       Cell acc_c = acc.cell_value ();
@@ -849,7 +865,7 @@
 
   cdef_class cls = object.get_class ();
 
-  if (! in_class_method (cls) && ! called_from_builtin ())
+  if (! in_class_method (cls))
     {
       cdef_method meth = cls.find_method ("subsref");
 
@@ -908,7 +924,7 @@
 
   cdef_class cls = object.get_class ();
 
-  if (! in_class_method (cls) && ! called_from_builtin ())
+  if (! in_class_method (cls))
     {
       cdef_method meth = cls.find_method ("subsasgn");
 
@@ -963,7 +979,7 @@
 
   cdef_class cls = object.get_class ();
 
-  if (! in_class_method (cls) && ! called_from_builtin ())
+  if (! in_class_method (cls))
     {
       cdef_method meth = cls.find_method ("numel");
 
@@ -1042,6 +1058,10 @@
   octave_classdef_meta (const cdef_meta_object& obj)
     : 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 (); }
 
@@ -1103,9 +1123,15 @@
 class octave_classdef_superclass_ref : public octave_function
 {
 public:
+  octave_classdef_superclass_ref (void) = delete;
+
   octave_classdef_superclass_ref (const octave_value_list& a)
     : octave_function (), args (a) { }
 
+  octave_classdef_superclass_ref (const octave_classdef_superclass_ref&) = delete;
+
+  octave_classdef_superclass_ref& operator = (const octave_classdef_superclass_ref&) = delete;
+
   ~octave_classdef_superclass_ref (void) = default;
 
   bool is_classdef_superclass_ref (void) const { return true; }
@@ -1113,7 +1139,7 @@
   octave_function * function_value (bool = false) { return this; }
 
   octave_value_list
-  call (octave::tree_evaluator&, int nargout, const octave_value_list& idx)
+  call (octave::tree_evaluator& tw, int nargout, const octave_value_list& idx)
   {
     octave_value_list retval;
 
@@ -1137,12 +1163,11 @@
           error ("`%s' is not a direct superclass of `%s'",
                  cname.c_str (), ctx.get_name ().c_str ());
 
-        if (! is_constructed_object (mname))
+        if (! is_constructed_object (tw, mname))
           error ("cannot call superclass constructor with variable `%s'",
                  mname.c_str ());
 
-        octave::symbol_scope scope
-          = octave::__require_current_scope__ ("octave_classdef_superclass_ref::call");
+        octave::symbol_scope scope = tw.get_current_scope ();
 
         octave_value sym = scope.varval (mname);
 
@@ -1185,10 +1210,10 @@
   }
 
 private:
-  bool is_constructed_object (const std::string nm)
+  bool is_constructed_object (octave::tree_evaluator& tw,
+                              const std::string& nm)
   {
-    octave::call_stack& cs
-      = octave::__get_call_stack__ ("octave_classdef_superclass_ref::is_constructed_object");
+    octave::call_stack& cs = tw.get_call_stack ();
 
     octave_function *of = cs.current ();
 
@@ -1370,7 +1395,7 @@
 
             if (type.length () > 1 && type[1] == '(')
               {
-                std::list<octave_value_list>::const_iterator it = idx.begin ();
+                auto it = idx.begin ();
 
                 args = *++it;
 
@@ -1879,7 +1904,7 @@
 cdef_method
 cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local)
 {
-  method_iterator it = method_map.find (nm);
+  auto it = method_map.find (nm);
 
   if (it == method_map.end ())
     {
@@ -1918,9 +1943,17 @@
 class ctor_analyzer : public octave::tree_walker
 {
 public:
+  ctor_analyzer (void) = delete;
+
   ctor_analyzer (const std::string& ctor, const std::string& obj)
     : octave::tree_walker (), who (ctor), obj_name (obj) { }
 
+  ctor_analyzer (const ctor_analyzer&) = delete;
+
+  ctor_analyzer& operator = (const ctor_analyzer&) = delete;
+
+  ~ctor_analyzer (void) = default;
+
   void visit_statement_list (octave::tree_statement_list& t)
   {
     for (const auto& stmt_p : t)
@@ -2145,7 +2178,7 @@
 cdef_property
 cdef_class::cdef_class_rep::find_property (const std::string& nm)
 {
-  property_iterator it = property_map.find (nm);
+  auto it = property_map.find (nm);
 
   if (it != property_map.end ())
     {
@@ -2885,8 +2918,7 @@
                   // detect which ones are invalid and do not correspond to a
                   // defined property.
 
-                  std::map<std::string, octave_value>::iterator git =
-                    get_methods.find (prop_name);
+                  auto git = get_methods.find (prop_name);
 
                   if (git != get_methods.end ())
                     {
@@ -2895,8 +2927,7 @@
                       get_methods.erase (git);
                     }
 
-                  std::map<std::string, octave_value>::iterator sit =
-                    set_methods.find (prop_name);
+                  auto sit = set_methods.find (prop_name);
 
                   if (sit != set_methods.end ())
                     {
@@ -3324,11 +3355,8 @@
   Cell retval (1, m.size ());
   int i = 0;
 
-  for (typename std::map<T1, T2>::const_iterator it = m.begin ();
-       it != m.end (); ++it, ++i)
-    {
-      retval(i) = to_ov (it->second);
-    }
+  for (auto it = m.begin (); it != m.end (); ++it, ++i)
+    retval(i) = to_ov (it->second);
 
   return retval;
 }
@@ -3350,10 +3378,10 @@
 {
   std::string symbol_name = get_name () + '.' + nm;
 
-  octave::symbol_table& symtab
-    = octave::__get_symbol_table__ ("cdef_package::cdef_package_rep::find");
-
-  return symtab.find (symbol_name, octave_value_list (), true, false);
+  octave::symbol_scope curr_scope
+    = octave::__get_current_scope__ ("cdef_package::cdef_package_rep::find");
+
+  return curr_scope.find (symbol_name);
 }
 
 octave_value_list
@@ -3750,7 +3778,7 @@
 cdef_manager::find_class (const std::string& name, bool error_if_not_found,
                           bool load_if_not_found)
 {
-  std::map<std::string, cdef_class>::iterator it = m_all_classes.find (name);
+  auto it = m_all_classes.find (name);
 
   if (it == m_all_classes.end ())
     {
@@ -3762,10 +3790,10 @@
 
           if (pos == std::string::npos)
             {
-              octave::symbol_table& symtab
-                = octave::__get_symbol_table__ ("cdef_manager::find_class");
-
-              ov_cls = symtab.find (name);
+              octave::symbol_scope curr_scope
+                = m_interpreter.get_current_scope ();
+
+              ov_cls = curr_scope.find (name);
             }
           else
             {
@@ -3840,8 +3868,7 @@
     }
   else
     {
-      octave::load_path& lp
-        = octave::__get_load_path__ ("cdef_manager::find_package");
+      octave::load_path& lp = m_interpreter.get_load_path ();
 
       if (load_if_not_found && lp.find_package (name))
         {
--- a/libinterp/octave-value/ov-classdef.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-classdef.h	Thu Dec 20 17:18:56 2018 -0500
@@ -340,6 +340,8 @@
     register_object ();
   }
 
+  cdef_object_base& operator = (const cdef_object_base&) = delete;
+
   ~cdef_object_base (void) { unregister_object (); }
 
   cdef_class get_class (void) const;
@@ -366,9 +368,6 @@
 
   // The class of the object
   cdef_object klass;
-
-  // No assignment!
-  cdef_object_base& operator = (const cdef_object_base&);
 };
 
 class
@@ -380,6 +379,10 @@
   cdef_object_array (const Array<cdef_object>& a)
     : cdef_object_base (), array (a) { }
 
+  cdef_object_array& operator = (const cdef_object_array&) = delete;
+
+  ~cdef_object_array (void) = default;
+
   cdef_object_rep * clone (void) const
   { return new cdef_object_array (*this); }
 
@@ -426,9 +429,6 @@
   // Private copying!
   cdef_object_array (const cdef_object_array& obj)
     : cdef_object_base (obj), array (obj.array) { }
-
-  // No assignment!
-  cdef_object_array& operator = (const cdef_object_array&);
 };
 
 class
@@ -437,6 +437,8 @@
 public:
   cdef_object_scalar (void) : cdef_object_base () { }
 
+  cdef_object_scalar& operator = (const cdef_object_scalar&) = delete;
+
   ~cdef_object_scalar (void) = default;
 
   dim_vector dims (void) const { return dim_vector (1, 1); }
@@ -504,10 +506,6 @@
   // Restricted object copying!
   cdef_object_scalar (const cdef_object_scalar& obj)
     : cdef_object_base (obj), map (obj.map), ctor_list (obj.ctor_list) { }
-
-private:
-  // No assignment!
-  cdef_object_scalar& operator = (const cdef_object_scalar&);
 };
 
 class
@@ -517,6 +515,8 @@
   handle_cdef_object (void)
     : cdef_object_scalar () { }
 
+  handle_cdef_object& operator = (const handle_cdef_object&) = delete;
+
   ~handle_cdef_object (void);
 
   cdef_object_rep * clone (void) const
@@ -537,10 +537,6 @@
   // Restricted copying!
   handle_cdef_object (const handle_cdef_object& obj)
     : cdef_object_scalar (obj) { }
-
-private:
-  // No assignment
-  handle_cdef_object& operator = (const handle_cdef_object&);
 };
 
 class
@@ -550,6 +546,8 @@
   value_cdef_object (void)
     : cdef_object_scalar () { }
 
+  value_cdef_object& operator = (const value_cdef_object&) = delete;
+
   ~value_cdef_object (void);
 
   cdef_object_rep * clone (void) const
@@ -565,9 +563,6 @@
   // Private copying!
   value_cdef_object (const value_cdef_object& obj)
     : cdef_object_scalar (obj) { }
-
-  // No assignment!
-  value_cdef_object& operator = (const value_cdef_object&);
 };
 
 class
@@ -577,6 +572,8 @@
   cdef_meta_object_rep (void)
     : handle_cdef_object () { }
 
+  cdef_meta_object_rep& operator = (const cdef_meta_object_rep&) = delete;
+
   ~cdef_meta_object_rep (void) = default;
 
   cdef_object_rep * copy (void) const
@@ -609,10 +606,6 @@
   // Restricted copying!
   cdef_meta_object_rep (const cdef_meta_object_rep& obj)
     : handle_cdef_object (obj) { }
-
-private:
-  // No assignment!
-  cdef_meta_object_rep& operator = (const cdef_meta_object_rep&);
 };
 
 class
@@ -632,6 +625,8 @@
   cdef_meta_object (const cdef_object& obj)
     : cdef_object (obj) { }
 
+  cdef_meta_object& operator = (const cdef_object&) = delete;
+
   ~cdef_meta_object (void) = default;
 
   bool is_class (void) const { return get_rep ()->is_class (); }
@@ -676,6 +671,10 @@
 
     cdef_class_rep (const std::list<cdef_class>& superclasses);
 
+    cdef_class_rep& operator = (const cdef_class_rep&) = delete;
+
+    ~cdef_class_rep (void) = default;
+
     cdef_object_rep * copy (void) const { return new cdef_class_rep (*this); }
 
     bool is_class (void) const { return true; }
@@ -845,6 +844,8 @@
     return *this;
   }
 
+  ~cdef_class (void) = default;
+
   cdef_method find_method (const std::string& nm, bool local = false);
 
   void install_method (const cdef_method& meth)
@@ -990,6 +991,10 @@
     cdef_property_rep (void)
       : cdef_meta_object_rep () { }
 
+    cdef_property_rep& operator = (const cdef_property_rep& p) = delete;
+
+    ~cdef_property_rep (void) = default;
+
     cdef_object_rep * copy (void) const { return new cdef_property_rep (*this); }
 
     bool is_property (void) const { return true; }
@@ -1054,6 +1059,8 @@
     return *this;
   }
 
+  ~cdef_property (void) = default;
+
   octave_value get_value (const cdef_object& obj, bool do_check_access = true,
                           const std::string& who = "")
   { return get_rep ()->get_value (obj, do_check_access, who); }
@@ -1100,6 +1107,10 @@
       : cdef_meta_object_rep (), function (), dispatch_type ()
     { }
 
+    cdef_method_rep& operator = (const cdef_method_rep& m) = delete;
+
+    ~cdef_method_rep (void) = default;
+
     cdef_object_rep * copy (void) const { return new cdef_method_rep(*this); }
 
     bool is_method (void) const { return true; }
@@ -1186,6 +1197,8 @@
     return *this;
   }
 
+  ~cdef_method (void) = default;
+
   // normal invocation
   octave_value_list execute (const octave_value_list& args, int nargout,
                              bool do_check_access = true,
@@ -1314,6 +1327,8 @@
     cdef_package_rep (void)
       : cdef_meta_object_rep (), member_count (0) { }
 
+    cdef_package_rep& operator = (const cdef_package_rep&) = delete;
+
     ~cdef_package_rep (void) = default;
 
     cdef_object_rep * copy (void) const { return new cdef_package_rep (*this); }
@@ -1420,6 +1435,8 @@
     return *this;
   }
 
+  ~cdef_package (void) = default;
+
   void install_class (const cdef_class& cls, const std::string& nm)
   { get_rep ()->install_class (cls, nm); }
 
@@ -1462,8 +1479,11 @@
   octave_classdef (const cdef_object& obj)
     : octave_base_value (), object (obj) { }
 
-  octave_classdef (const octave_classdef& obj)
-    : octave_base_value (obj), object (obj.object) { }
+  octave_classdef (const octave_classdef&) = delete;
+
+  octave_classdef& operator = (const octave_classdef&) = delete;
+
+  ~octave_classdef (void) = default;
 
   octave_base_value * clone (void) const
   { return new octave_classdef (object.clone ()); }
--- a/libinterp/octave-value/ov-colon.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-colon.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "error.h"
 #include "pr-output.h"
--- a/libinterp/octave-value/ov-complex.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-complex.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <sstream>
 
 #include "lo-ieee.h"
--- a/libinterp/octave-value/ov-cs-list.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-cs-list.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <sstream>
-
 #include "lo-utils.h"
 
 #include "defun.h"
--- a/libinterp/octave-value/ov-cx-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-cx-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "dNDArray.h"
@@ -244,7 +245,7 @@
       octave_idx_type nel = numel ();
 
       for (octave_idx_type i = 0; i < nel; i++)
-        retval.elem (i) = static_cast<char>(std::real (matrix.elem (i)));
+        retval.elem (i) = static_cast<char> (std::real (matrix.elem (i)));
     }
 
   return retval;
--- a/libinterp/octave-value/ov-cx-sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-cx-sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "lo-specfun.h"
@@ -178,7 +178,7 @@
       for (octave_idx_type j = 0; j < nc; j++)
         for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
           retval(matrix.ridx (i) + nr * j) =
-            static_cast<char>(std::real (matrix.data (i)));
+            static_cast<char> (std::real (matrix.data (i)));
     }
 
   return retval;
--- a/libinterp/octave-value/ov-fcn-handle.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,8 +26,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <list>
+#include <ostream>
 #include <sstream>
 #include <vector>
 
@@ -53,6 +54,7 @@
 #include "parse.h"
 #include "pr-output.h"
 #include "pt-arg-list.h"
+#include "pt-anon-scopes.h"
 #include "pt-assign.h"
 #include "pt-cmd.h"
 #include "pt-eval.h"
@@ -160,7 +162,7 @@
         }
       else
         {
-          str_ov_map::iterator it = overloads.find (dispatch_type);
+          auto it = overloads.find (dispatch_type);
 
           if (it == overloads.end ())
             {
@@ -169,10 +171,10 @@
               octave::symbol_table& symtab
                 = octave::__get_symbol_table__ ("octave_fcn_handle::call");
 
-              std::list<std::string> plist
+              const std::list<std::string> plist
                 = symtab.parent_classes (dispatch_type);
 
-              std::list<std::string>::const_iterator pit = plist.begin ();
+              auto pit = plist.begin ();
 
               while (pit != plist.end ())
                 {
@@ -240,9 +242,9 @@
       for (int i = 0; i < btyp_num_types && retval; i++)
         retval = builtin_overloads[i].is_copy_of (h.builtin_overloads[i]);
 
-      str_ov_map::const_iterator iter = overloads.begin ();
-      str_ov_map::const_iterator hiter = h.overloads.begin ();
-      for (; iter != overloads.end () && retval; iter++, hiter++)
+      auto iter = overloads.cbegin ();
+      auto hiter = h.overloads.cbegin ();
+      for (; iter != overloads.cend () && retval; iter++, hiter++)
         retval = (iter->first == hiter->first)
                  && (iter->second.is_copy_of (hiter->second));
     }
@@ -338,40 +340,48 @@
   return true;
 }
 
+octave_value
+octave_fcn_handle::convert_to_str_internal (bool, bool, char type) const
+{
+  std::ostringstream buf;
+  print_raw (buf, true);
+  return octave_value (buf.str (), type);
+}
+
 bool
 octave_fcn_handle::save_ascii (std::ostream& os)
 {
   if (nm == anonymous)
     {
+      if (fcn.is_undefined ())
+        return false;
+
+      octave_user_function *f = fcn.user_function_value ();
+      octave::symbol_scope f_scope = f->scope ();
+
+      if (! f_scope)
+        error ("internal error, invalid scope");
+
+      octave::tree_anon_scopes tas (f);
+
       os << nm << "\n";
 
       print_raw (os, true);
       os << "\n";
 
-      if (fcn.is_undefined ())
-        return false;
-
-      std::list<octave::symbol_record> vars;
-
-      octave_user_function *f = fcn.user_function_value ();
-      octave::symbol_record::context_id context = 0;
-      octave::symbol_scope f_scope = f->scope ();
-      if (f_scope)
-        {
-          vars = f_scope.all_variables ();
-          context = f_scope.current_context ();
-        }
-
-      size_t varlen = vars.size ();
+      size_t varlen = tas.symrec_map_size ();
 
       if (varlen > 0)
         {
+          octave::symbol_record::context_id context
+            = f_scope.current_context ();
+
           os << "# length: " << varlen << "\n";
 
-          for (const auto& symrec : vars)
+          for (const auto& name_symrec : tas)
             {
-              if (! save_text_data (os, symrec.varval (context),
-                                    symrec.name (), false, 0))
+              if (! save_text_data (os, name_symrec.second.varval (context),
+                                    name_symrec.first, false, 0))
                 return ! os.fail ();
             }
         }
@@ -395,10 +405,12 @@
 {
   bool success = true;
 
-  int parse_status;
+  octave::interpreter& interp
+    = octave::__get_interpreter__ ("octave_fcn_handle::parse_anon_fcn_handle");
 
-  octave_value anon_fcn_handle =
-    octave::eval_string (fcn_text, true, parse_status);
+  int parse_status;
+  octave_value anon_fcn_handle
+    = interp.eval_string (fcn_text, true, parse_status);
 
   if (parse_status == 0)
     {
@@ -532,18 +544,15 @@
       if (fcn.is_undefined ())
         return false;
 
-      std::list<octave::symbol_record> vars;
-
       octave_user_function *f = fcn.user_function_value ();
       octave::symbol_scope f_scope = f->scope ();
-      octave::symbol_record::context_id context = 0;
-      if (f_scope)
-        {
-          vars = f_scope.all_variables ();
-          context = f_scope.current_context ();
-        }
+
+      if (! f_scope)
+        error ("internal error, invalid scope");
 
-      size_t varlen = vars.size ();
+      octave::tree_anon_scopes tas (f);
+
+      size_t varlen = tas.symrec_map_size ();
 
       if (varlen > 0)
         nmbuf << nm << ' ' << varlen;
@@ -564,10 +573,13 @@
 
       if (varlen > 0)
         {
-          for (const auto& symrec : vars)
+          octave::symbol_record::context_id context
+            = f_scope.current_context ();
+
+          for (const auto& name_symrec : tas)
             {
-              if (! save_binary_data (os, symrec.varval (context),
-                                      symrec.name (), "", 0, save_as_floats))
+              if (! save_binary_data (os, name_symrec.second.varval (context),
+                                      name_symrec.first, "", 0, save_as_floats))
                 return ! os.fail ();
             }
         }
@@ -792,18 +804,15 @@
 
       H5Dclose (data_hid);
 
-      std::list<octave::symbol_record> vars;
-
       octave_user_function *f = fcn.user_function_value ();
       octave::symbol_scope f_scope = f->scope ();
-      octave::symbol_record::context_id context = 0;
-      if (f_scope)
-        {
-          vars = f_scope.all_variables ();
-          context = f_scope.current_context ();
-        }
+
+      if (! f_scope)
+        error ("internal error, invalid scope");
 
-      size_t varlen = vars.size ();
+      octave::tree_anon_scopes tas (f);
+
+      size_t varlen = tas.symrec_map_size ();
 
       if (varlen > 0)
         {
@@ -848,10 +857,15 @@
               return false;
             }
 
-          for (const auto& symrec : vars)
+          octave::symbol_record::context_id context
+            = f_scope.current_context ();
+
+          for (const auto& name_symrec : tas)
             {
-              if (! add_hdf5_data (data_hid, symrec.varval (context),
-                                   symrec.name (), "", false, save_as_floats))
+              if (! add_hdf5_data (data_hid,
+                                   name_symrec.second.varval (context),
+                                   name_symrec.first, "", false,
+                                   save_as_floats))
                 break;
             }
           H5Gclose (data_hid);
@@ -1171,7 +1185,7 @@
           H5Gget_num_objs (data_hid, &num_obj);
           H5Gclose (data_hid);
 
-          if (num_obj != static_cast<hsize_t>(len))
+          if (num_obj != static_cast<hsize_t> (len))
             error ("load: failed to load anonymous function handle");
 
           hdf5_callback_data dsub;
@@ -1445,7 +1459,7 @@
 }
 
 octave_value
-make_fcn_handle (const std::string& nm, bool local_funcs)
+make_fcn_handle (const std::string& nm)
 {
   octave_value retval;
 
@@ -1579,17 +1593,15 @@
 
   octave::symbol_table& symtab = octave::__get_symbol_table__ ("make_fcn_handle");
 
-  octave_value f = symtab.find_function (tnm, octave_value_list (),
-                                         local_funcs);
+  octave_value f = symtab.find_function (tnm, octave_value_list ());
 
   octave_function *fptr = f.function_value (true);
 
   // Here we are just looking to see if FCN is a method or constructor
   // for any class.
-  if (local_funcs && fptr
-      && (fptr->is_subfunction () || fptr->is_private_function ()
-          || fptr->is_class_constructor ()
-          || fptr->is_classdef_constructor ()))
+  if (fptr && (fptr->is_subfunction () || fptr->is_private_function ()
+               || fptr->is_class_constructor ()
+               || fptr->is_classdef_constructor ()))
     {
       // Locally visible function.
       retval = octave_value (new octave_fcn_handle (f, tnm));
@@ -1836,14 +1848,14 @@
   return retval;
 }
 
-DEFUN (str2func, args, ,
-       doc: /* -*- texinfo -*-
+DEFMETHOD (str2func, interp, args, ,
+           doc: /* -*- texinfo -*-
 @deftypefn  {} {} str2func (@var{fcn_name})
-@deftypefnx {} {} str2func (@var{fcn_name}, "global")
 Return a function handle constructed from the string @var{fcn_name}.
 
-If the optional @qcode{"global"} argument is passed, locally visible
-functions are ignored in the lookup.
+Previous versions of Octave accepted an optional second argument,
+@qcode{"global"}, that caused str2func to ignore locally visible
+functions.  This option is no longer supported.
 @seealso{func2str, inline, functions}
 @end deftypefn */)
 {
@@ -1860,13 +1872,19 @@
     {
       int parse_status;
       octave_value anon_fcn_handle
-        = octave::eval_string (nm, true, parse_status);
+        = interp.eval_string (nm, true, parse_status);
 
       if (parse_status == 0)
         retval = anon_fcn_handle;
     }
   else
-    retval = make_fcn_handle (nm, nargin != 2);
+    {
+      if (nargin == 2)
+        warning_with_id ("Octave:str2func-global-argument",
+                         "str2func: second argument ignored");
+
+      retval = make_fcn_handle (nm);
+    }
 
   return retval;
 }
@@ -1917,10 +1935,12 @@
 }
 
 /*
-%!shared fh
+%!shared fh, finline
 %! fh = @(x) x;
+%! finline = inline ("x");
 
 %!assert (is_function_handle (fh))
+%!assert (is_function_handle (finline))
 %!assert (! is_function_handle ({fh}))
 %!assert (! is_function_handle (1))
 
@@ -1939,7 +1959,7 @@
 
 octave_fcn_handle *
 octave_fcn_binder::maybe_binder (const octave_value& f,
-                                 octave::tree_evaluator *tw)
+                                 octave::tree_evaluator& tw)
 {
   octave_fcn_handle *retval = nullptr;
 
@@ -1998,7 +2018,7 @@
 
           if (arg_list && arg_list->length () > 0)
             {
-              octave::symbol_scope scope = tw->get_current_scope ();
+              octave::symbol_scope scope = tw.get_current_scope ();
 
               octave::symbol_record::context_id context
                 = scope.current_context ();
@@ -2011,13 +2031,13 @@
               // Verify that each argument is either a named param, a constant,
               // or a defined identifier.
               int iarg = 0;
-              for (octave::tree_argument_list::iterator it = arg_list->begin ();
+              for (auto it = arg_list->begin ();
                    it != arg_list->end (); ++it, ++iarg)
                 {
                   octave::tree_expression *elt = *it;
                   if (elt && elt->is_constant ())
                     {
-                      arg_template(iarg) = tw->evaluate (elt);
+                      arg_template(iarg) = tw.evaluate (elt);
                       arg_mask[iarg] = -1;
                     }
                   else if (elt && elt->is_identifier ())
@@ -2030,7 +2050,7 @@
                         }
                       else if (elt_id->is_defined (context))
                         {
-                          arg_template(iarg) = tw->evaluate (elt_id);
+                          arg_template(iarg) = tw.evaluate (elt_id);
                           arg_mask[iarg] = -1;
                         }
                       else
@@ -2052,7 +2072,7 @@
                 {
                   // If the head is a value, use it as root.
                   if (head_id->is_defined (context))
-                    root_val = tw->evaluate (head_id);
+                    root_val = tw.evaluate (head_id);
                   else
                     {
                       // It's a name.
--- a/libinterp/octave-value/ov-fcn-handle.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-fcn-handle.h	Thu Dec 20 17:18:56 2018 -0500
@@ -131,6 +131,8 @@
 
   bool is_equal_to (const octave_fcn_handle&) const;
 
+  octave_value convert_to_str_internal (bool pad, bool force, char type) const;
+
   bool save_ascii (std::ostream& os);
 
   bool load_ascii (std::istream& is);
@@ -181,8 +183,7 @@
   friend octave_value make_fcn_handle (const std::string &, bool);
 };
 
-extern octave_value make_fcn_handle (const std::string& nm,
-                                     bool local_funcs = true);
+extern octave_value make_fcn_handle (const std::string& nm);
 
 class
 OCTINTERP_API
@@ -198,7 +199,7 @@
 
   // Factory method.
   static octave_fcn_handle * maybe_binder (const octave_value& f,
-                                           octave::tree_evaluator *tw);
+                                           octave::tree_evaluator& tw);
 
 protected:
 
--- a/libinterp/octave-value/ov-fcn-inline.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-fcn-inline.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,7 +29,7 @@
 #endif
 
 #include <istream>
-#include <iostream>
+#include <ostream>
 #include <sstream>
 #include <vector>
 
@@ -82,8 +82,12 @@
 
   buf << ") " << iftext;
 
+  octave::interpreter& interp
+    = octave::__get_interpreter__ ("octave_fcn_inline::octave_fcn_inline");
+
   int parse_status;
-  octave_value anon_fcn_handle = octave::eval_string (buf.str (), true, parse_status);
+  octave_value anon_fcn_handle
+    = interp.eval_string (buf.str (), true, parse_status);
 
   if (parse_status == 0)
     {
@@ -97,8 +101,7 @@
 
           if (uf)
             {
-              octave::call_stack& cs
-                = octave::__get_call_stack__ ("octave_fcn_inline");
+              octave::call_stack& cs = interp.get_call_stack ();
 
               octave_function *curr_fcn = cs.current ();
 
--- a/libinterp/octave-value/ov-float.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-float.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "oct-inttypes.h"
 
--- a/libinterp/octave-value/ov-flt-complex.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-flt-complex.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "lo-ieee.h"
 #include "lo-specfun.h"
--- a/libinterp/octave-value/ov-flt-cx-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-flt-cx-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "dNDArray.h"
@@ -218,7 +219,7 @@
       octave_idx_type nel = numel ();
 
       for (octave_idx_type i = 0; i < nel; i++)
-        retval.elem (i) = static_cast<char>(std::real (matrix.elem (i)));
+        retval.elem (i) = static_cast<char> (std::real (matrix.elem (i)));
     }
 
   return retval;
--- a/libinterp/octave-value/ov-flt-re-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-flt-re-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <vector>
 
 #include "dNDArray.h"
@@ -215,7 +216,7 @@
   octave_idx_type nel = numel ();
 
   for (octave_idx_type i = 0; i < nel; i++)
-    retval.elem (i) = static_cast<char>(matrix.elem (i));
+    retval.elem (i) = static_cast<char> (matrix.elem (i));
 
   return retval;
 }
--- a/libinterp/octave-value/ov-int16.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-int16.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-int32.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-int32.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-int64.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-int64.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-int8.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-int8.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-java.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-java.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -34,9 +34,8 @@
 #endif
 
 #include <algorithm>
+#include <fstream>
 #include <map>
-#include <iostream>
-#include <fstream>
 #include <string>
 #include <vector>
 
@@ -52,7 +51,10 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "fpucw-wrappers.h"
+#include "interpreter.h"
+#include "interpreter-private.h"
 #include "load-path.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-shlib.h"
 #include "ov-java.h"
@@ -65,6 +67,14 @@
 
 #if defined (HAVE_JAVA)
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  define LIBJVM_FILE_NAME "jvm.dll"
+#elif defined (__APPLE__)
+#  define LIBJVM_FILE_NAME "libjvm.dylib"
+#else
+#  define LIBJVM_FILE_NAME "libjvm.so"
+#endif
+
 #define TO_JOBJECT(obj) reinterpret_cast<jobject> (obj)
 #define TO_JCLASS(obj) reinterpret_cast<jclass> (obj)
 
@@ -237,7 +247,9 @@
 
     void read_java_opts (const std::string& filename)
     {
-      std::ifstream js (filename.c_str ());
+      std::string ascii_fname = octave::sys::get_ASCII_filename (filename);
+
+      std::ifstream js (ascii_fname.c_str ());
 
       if (! js.bad () && ! js.fail ())
         {
@@ -250,8 +262,7 @@
               if (line.find ('-') == 0)
                 java_opts.push_back (line);
               else if (line.length () > 0 && Vdebug_java)
-                std::cerr << "invalid JVM option, skipping: " << line
-                                                              << std::endl;
+                warning ("invalid JVM option, skipping: %s", line.c_str ());
             }
         }
     }
@@ -286,7 +297,7 @@
           for (const auto& opt : java_opts)
             {
               if (Vdebug_java)
-                std::cout << opt << std::endl;
+                octave_stdout << opt << std::endl;
               vm_args.options[index++].optionString = strsave (opt.c_str ());
             }
 
@@ -358,7 +369,9 @@
 {
   std::string classpath;
 
-  std::ifstream fs (filepath.c_str ());
+  std::string ascii_fname = octave::sys::get_ASCII_filename (filepath);
+
+  std::ifstream fs (ascii_fname.c_str ());
 
   if (! fs.bad () && ! fs.fail ())
     {
@@ -491,11 +504,94 @@
   return retval;
 }
 
+static std::string
+get_jvm_lib_path_in_subdir (std::string java_home_path)
+{
+  // 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"};
+#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"};
+#endif
+
+  for (size_t i = 0; i < sizeof (subdirs) / sizeof (subdirs[0]); i++)
+    {
+      std::string candidate = java_home_path + "/" + subdirs[i]
+                            + "/" LIBJVM_FILE_NAME;
+      if (octave::sys::file_stat (candidate))
+        return candidate;
+    }
+  return "";
+}
+
 #if defined (OCTAVE_USE_WINDOWS_API)
 // Declare function defined in sysdep.cc
 extern LONG
 get_regkey_value (HKEY h_rootkey, const std::string subkey,
                   const std::string name, octave_value& value);
+
+static std::string
+get_jvm_lib_path_from_registry ()
+{
+  // In Windows, find the location of the JRE from the registry
+  // and load the symbol from the dll.
+  std::string key, jversion, value;
+
+  // First search for JRE >= 9
+  key = R"(software\javasoft\jre)";
+
+  jversion = octave::sys::env::getenv ("JAVA_VERSION");
+  octave_value regval;
+  LONG retval;
+  if (jversion.empty ())
+    {
+      value = "CurrentVersion";
+      retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
+
+      if (retval != ERROR_SUCCESS)
+        {
+          // Search for JRE < 9
+          key = R"(software\javasoft\java runtime environment)";
+          retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value,
+                                     regval);
+        }
+
+      if (retval != ERROR_SUCCESS)
+        error ("unable to find Java Runtime Environment: %s::%s",
+               key.c_str (), value.c_str ());
+
+      jversion = regval.xstring_value (
+        "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
+        value.c_str (), key.c_str ());
+    }
+
+  key = key + '\\' + jversion;
+  value = "RuntimeLib";
+  retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
+  if (retval != ERROR_SUCCESS)
+    {
+      // Search for JRE < 9
+      key = R"(software\javasoft\java runtime environment\)" + jversion;
+      retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
+    }
+
+  if (retval != ERROR_SUCCESS)
+    error ("unable to find Java Runtime Environment: %s::%s",
+           key.c_str (), value.c_str ());
+
+  std::string jvm_lib_path = regval.xstring_value (
+        "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
+        value.c_str (), key.c_str ());
+
+  if (jvm_lib_path.empty ())
+    error ("unable to find Java Runtime Environment: %s::%s",
+           key.c_str (), value.c_str ());
+
+  return jvm_lib_path;
+}
 #endif
 
 //! Initialize the java virtual machine (jvm) and field #jvm if necessary.
@@ -546,68 +642,27 @@
 
   if (! create_vm || ! get_vm)
     {
-#if defined (OCTAVE_USE_WINDOWS_API)
-      // In Windows, find the location of the JRE from the registry
-      // and load the symbol from the dll.
-      std::string key, jversion, value;
-
-      // First search for JRE >= 9
-      key = R"(software\javasoft\jre)";
-
-      jversion = octave::sys::env::getenv ("JAVA_VERSION");
-      octave_value regval;
-      LONG retval;
-      if (jversion.empty ())
+      // JAVA_HOME environment variable takes precedence
+      std::string java_home_env = octave::sys::env::getenv ("JAVA_HOME");
+      if (! java_home_env.empty ())
         {
-          value = "CurrentVersion";
-          retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
-
-          if (retval != ERROR_SUCCESS)
-            {
-              // Search for JRE < 9
-              key = R"(software\javasoft\java runtime environment)";
-              retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value,
-                                         regval);
-            }
-
-          if (retval != ERROR_SUCCESS)
-            error ("unable to find Java Runtime Environment: %s::%s",
-                   key.c_str (), value.c_str ());
-
-          jversion = regval.xstring_value (
-            "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
-            value.c_str (), key.c_str ());
+          jvm_lib_path = get_jvm_lib_path_in_subdir (java_home_env);
+
+          // If JAVA_HOME does not look like a Java directory, use it anyway
+          // to fail with a useful error message indicating the directory
+          if (jvm_lib_path.empty ())
+            jvm_lib_path = java_home_env + "/" LIBJVM_FILE_NAME;
         }
-
-      key = key + '\\' + jversion;
-      value = "RuntimeLib";
-      retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
-      if (retval != ERROR_SUCCESS)
+      else
         {
-          // Search for JRE < 9
-          key = R"(software\javasoft\java runtime environment\)" + jversion;
-          retval = get_regkey_value (HKEY_LOCAL_MACHINE, key, value, regval);
+#if defined (OCTAVE_USE_WINDOWS_API)
+          jvm_lib_path = get_jvm_lib_path_from_registry ();
+#else
+          // Fall back to JAVA_LDPATH, determined by the build system
+          jvm_lib_path = std::string (JAVA_LDPATH) + "/" LIBJVM_FILE_NAME;
+#endif
         }
 
-      if (retval != ERROR_SUCCESS)
-        error ("unable to find Java Runtime Environment: %s::%s",
-               key.c_str (), value.c_str ());
-
-      jvm_lib_path = regval.xstring_value (
-            "initialize_jvm: registry value \"%s\" at \"%s\" must be a string",
-            value.c_str (), key.c_str ());
-
-      if (jvm_lib_path.empty ())
-        error ("unable to find Java Runtime Environment: %s::%s",
-               key.c_str (), value.c_str ());
-#else
-      // JAVA_LDPATH determined by configure and set in config.h
-#  if defined (__APPLE__)
-      jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.dylib");
-#  else
-      jvm_lib_path = JAVA_LDPATH + std::string ("/libjvm.so");
-#  endif
-#endif
       lib = octave::dynamic_library (jvm_lib_path);
 
       if (! lib)
@@ -1431,7 +1486,7 @@
         {
           jmethodID mID = jni_env->GetMethodID (cls, "getID", "()I");
           int ID = jni_env->CallIntMethod (jobj, mID);
-          std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
+          auto it = octave_ref_map.find (ID);
 
           if (it != octave_ref_map.end ())
             retval = it->second;
@@ -1883,7 +1938,7 @@
         }
       catch (std::string msg)
         {
-          error (msg.c_str ());
+          error ("%s", msg.c_str ());
         }
 
       octave_set_default_fpucw ();
@@ -1921,7 +1976,7 @@
 Java_org_octave_Octave_doInvoke (JNIEnv *env, jclass, jint ID,
                                  jobjectArray args)
 {
-  std::map<int,octave_value>::iterator it = octave_ref_map.find (ID);
+  auto it = octave_ref_map.find (ID);
 
   if (it != octave_ref_map.end ())
     {
@@ -1964,9 +2019,12 @@
 JNIEXPORT void JNICALL
 Java_org_octave_Octave_doEvalString (JNIEnv *env, jclass, jstring cmd)
 {
+  octave::interpreter& interp
+    = octave::__get_interpreter__ ("Java_org_octave_Octave_doEvalString");
+
   std::string s = jstring_to_string (env, cmd);
   int pstatus;
-  octave::eval_string (s, false, pstatus, 0);
+  interp.eval_string (s, false, pstatus, 0);
 }
 
 JNIEXPORT jboolean JNICALL
@@ -2067,7 +2125,7 @@
           count++;
           ovl(1) = octave_value (this);
           ovl(0) = (idx.front ())(0);
-          std::list<octave_value_list>::const_iterator it = idx.begin ();
+          auto it = idx.begin ();
           ovl.append (*++it);
           retval = FjavaMethod (ovl, 1);
           skip++;
@@ -2142,7 +2200,7 @@
       else if (type.length () > 2 && type[1] == '(')
         {
           std::list<octave_value_list> new_idx;
-          std::list<octave_value_list>::const_iterator it = idx.begin ();
+          auto it = idx.begin ();
           new_idx.push_back (*it++);
           new_idx.push_back (*it++);
           octave_value_list u = subsref (type.substr (0, 2), new_idx, 1);
--- a/libinterp/octave-value/ov-range.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-range.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
+#include <sstream>
 
 #include "dNDArray.h"
 #include "fNDArray.h"
@@ -220,7 +222,7 @@
   octave_idx_type nel = numel ();
 
   for (octave_idx_type i = 0; i < nel; i++)
-    retval.elem (i) = static_cast<char>(matrix.elem (i));
+    retval.elem (i) = static_cast<char> (matrix.elem (i));
 
   return retval;
 }
--- a/libinterp/octave-value/ov-re-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-re-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <vector>
 
 #include "dNDArray.h"
@@ -225,7 +226,7 @@
   octave_idx_type nel = numel ();
 
   for (octave_idx_type i = 0; i < nel; i++)
-    retval.elem (i) = static_cast<char>(matrix.elem (i));
+    retval.elem (i) = static_cast<char> (matrix.elem (i));
 
   return retval;
 }
--- a/libinterp/octave-value/ov-re-sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-re-sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <vector>
 
 #include "lo-specfun.h"
@@ -147,7 +148,7 @@
 
   for (octave_idx_type j = 0; j < nc; j++)
     for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
-      retval(matrix.ridx (i) + nr * j) = static_cast<char>(matrix.data (i));
+      retval(matrix.ridx (i) + nr * j) = static_cast<char> (matrix.data (i));
 
   return retval;
 }
--- a/libinterp/octave-value/ov-scalar.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-scalar.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "oct-inttypes.h"
 
--- a/libinterp/octave-value/ov-str-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-str-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,8 @@
 
 #include <cctype>
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "data-conv.h"
@@ -51,7 +52,6 @@
 #include "ov-re-mat.h"
 #include "ov-str-mat.h"
 #include "pr-output.h"
-#include "pt-mat.h"
 #include "utils.h"
 
 
@@ -289,7 +289,7 @@
           std::string retval = string_value ();
 
           if (! is_sq_string ())
-            retval = undo_string_escapes (retval);
+            retval = octave::undo_string_escapes (retval);
 
           return retval;
         }
--- a/libinterp/octave-value/ov-struct.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-struct.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Cell.h"
 #include "builtin-defun-decls.h"
@@ -107,7 +108,7 @@
 static void
 maybe_warn_invalid_field_name (const std::string& key, const char *who)
 {
-  if (! valid_identifier (key))
+  if (! octave::valid_identifier (key))
     {
       if (who)
         warning_with_id ("Octave:language-extension",
@@ -135,7 +136,7 @@
       {
         if (type.length () > 1 && type[1] == '.')
           {
-            std::list<octave_value_list>::const_iterator p = idx.begin ();
+            auto p = idx.begin ();
             octave_value_list key_idx = *++p;
 
             const Cell tmp = dotref (key_idx);
@@ -198,7 +199,7 @@
       {
         if (type.length () > 1 && type[1] == '.')
           {
-            std::list<octave_value_list>::const_iterator p = idx.begin ();
+            auto p = idx.begin ();
             octave_value_list key_idx = *++p;
 
             const Cell tmp = dotref (key_idx, auto_add);
@@ -291,7 +292,7 @@
           {
             if (type.length () > 1 && type[1] == '.')
               {
-                std::list<octave_value_list>::const_iterator p = idx.begin ();
+                auto p = idx.begin ();
                 octave_value_list t_idx = *p;
 
                 octave_value_list key_idx = *++p;
@@ -313,7 +314,7 @@
                 std::string next_type = type.substr (2);
 
                 Cell tmpc (1, 1);
-                octave_map::iterator pkey = map.seek (key);
+                auto pkey = map.seek (key);
                 if (pkey != map.end ())
                   {
                     map.contents (pkey).make_unique ();
@@ -365,7 +366,7 @@
             std::string next_type = type.substr (1);
 
             Cell tmpc (1, 1);
-            octave_map::iterator pkey = map.seek (key);
+            auto pkey = map.seek (key);
             if (pkey != map.end ())
               {
                 map.contents (pkey).make_unique ();
@@ -414,7 +415,7 @@
       {
         if (n > 1 && type[1] == '.')
           {
-            std::list<octave_value_list>::const_iterator p = idx.begin ();
+            auto p = idx.begin ();
             octave_value_list key_idx = *++p;
             octave_value_list idxf = idx.front ();
 
@@ -550,7 +551,7 @@
 
   size_t retval = 0;
 
-  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+  for (auto p = map.cbegin (); p != map.cend (); p++)
     {
       std::string key = map.key (p);
 
@@ -1212,7 +1213,7 @@
           std::string next_type = type.substr (1);
 
           octave_value tmp;
-          octave_map::iterator pkey = map.seek (key);
+          auto pkey = map.seek (key);
           if (pkey != map.end ())
             {
               map.contents (pkey).make_unique ();
@@ -1264,7 +1265,7 @@
 
   size_t retval = 0;
 
-  for (octave_map::const_iterator p = map.begin (); p != map.end (); p++)
+  for (auto p = map.cbegin (); p != map.cend (); p++)
     {
       std::string key = map.key (p);
 
--- a/libinterp/octave-value/ov-typeinfo.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-typeinfo.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,8 @@
 #  include "config.h"
 #endif
 
+#include <iostream>
+
 #include "Array.h"
 
 #include "defun.h"
--- a/libinterp/octave-value/ov-uint16.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-uint16.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-uint32.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-uint32.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-uint64.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-uint64.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-uint8.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-uint8.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,9 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-#include <limits>
-
 #include "lo-ieee.h"
 #include "lo-utils.h"
 #include "mx-base.h"
--- a/libinterp/octave-value/ov-usr-fcn.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -64,14 +64,17 @@
 
 octave_user_code::~octave_user_code (void)
 {
+  // FIXME: shouldn't this happen automatically when deleting cmd_list?
+  if (cmd_list)
+    cmd_list->remove_all_breakpoints (file_name);
+
+  delete cmd_list;
   delete m_file_info;
 }
 
 void
 octave_user_code::get_file_info (void)
 {
-  std::string file_name = fcn_file_name ();
-
   m_file_info = new octave::file_info (file_name);
 
   octave::sys::file_stat fs (file_name);
@@ -118,6 +121,20 @@
   return std::map<std::string, octave_value> ();
 }
 
+octave_value
+octave_user_code::dump (void) const
+{
+  std::map<std::string, octave_value> m
+    = {{ "scope_info", m_scope ? m_scope.dump () : "0x0" },
+       { "file_name", file_name },
+       { "time_parsed", t_parsed },
+       { "time_checked", t_checked },
+       { "call_depth", m_call_depth }};
+
+  return octave_value (m);
+}
+
+
 // User defined scripts.
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_script,
@@ -125,20 +142,14 @@
                                      "user-defined script");
 
 octave_user_script::octave_user_script (void)
-  : octave_user_code (), cmd_list (nullptr), file_name (),
-    t_parsed (static_cast<time_t> (0)),
-    t_checked (static_cast<time_t> (0)),
-    call_depth (-1)
+  : octave_user_code ()
 { }
 
 octave_user_script::octave_user_script
   (const std::string& fnm, const std::string& nm,
    const octave::symbol_scope& scope, octave::tree_statement_list *cmds,
    const std::string& ds)
-  : octave_user_code (nm, scope, ds), cmd_list (cmds), file_name (fnm),
-    t_parsed (static_cast<time_t> (0)),
-    t_checked (static_cast<time_t> (0)),
-    call_depth (-1)
+  : octave_user_code (fnm, nm, scope, cmds, ds)
 {
   if (cmd_list)
     cmd_list->mark_as_script_body ();
@@ -147,81 +158,14 @@
 octave_user_script::octave_user_script
   (const std::string& fnm, const std::string& nm,
    const octave::symbol_scope& scope, const std::string& ds)
-  : octave_user_code (nm, scope, ds), cmd_list (nullptr), file_name (fnm),
-    t_parsed (static_cast<time_t> (0)),
-    t_checked (static_cast<time_t> (0)),
-    call_depth (-1)
+    : octave_user_code (fnm, nm, scope, nullptr, ds)
 { }
 
-octave_user_script::~octave_user_script (void)
-{
-  if (cmd_list)
-    cmd_list->remove_all_breakpoints (file_name);
-
-  delete cmd_list;
-}
-
 octave_value_list
 octave_user_script::call (octave::tree_evaluator& tw, int nargout,
                           const octave_value_list& args)
 {
-  octave_value_list retval;
-
-  octave::unwind_protect frame;
-
-  if (args.length () != 0 || nargout != 0)
-    error ("invalid call to script %s", file_name.c_str ());
-
-  if (cmd_list)
-    {
-      frame.protect_var (call_depth);
-      call_depth++;
-
-      if (call_depth >= tw.max_recursion_depth ())
-        error ("max_recursion_depth exceeded");
-
-      octave::call_stack& cs
-        = octave::__get_call_stack__ ("octave_user_script::call");
-
-      cs.push (this);
-
-      // Set pointer to the current unwind_protect frame to allow
-      // certain builtins register simple cleanup in a very optimized manner.
-      // This is *not* intended as a general-purpose on-cleanup mechanism,
-      frame.protect_var (curr_unwind_protect_frame);
-      curr_unwind_protect_frame = &frame;
-
-      frame.add_method (cs, &octave::call_stack::pop);
-
-      // Update line number even if debugging.
-      frame.protect_var (Vtrack_line_num);
-      Vtrack_line_num = true;
-
-      frame.protect_var (octave::tree_evaluator::statement_context);
-      octave::tree_evaluator::statement_context = octave::tree_evaluator::script;
-
-      octave::profiler& profiler = tw.get_profiler ();
-
-      octave::profiler::enter<octave_user_script> block (profiler, *this);
-
-      frame.add_method (m_scope,
-                        &octave::symbol_scope::unbind_script_symbols);
-      m_scope.bind_script_symbols (tw.get_current_scope ());
-
-      if (tw.echo ())
-        tw.push_echo_state (frame, octave::tree_evaluator::ECHO_SCRIPTS,
-                            file_name);
-
-      cmd_list->accept (tw);
-
-      if (octave::tree_return_command::returning)
-        octave::tree_return_command::returning = 0;
-
-      if (octave::tree_break_command::breaking)
-        octave::tree_break_command::breaking--;
-    }
-
-  return retval;
+  return tw.execute_user_script (*this, nargout, args);
 }
 
 void
@@ -242,13 +186,11 @@
 octave_user_function::octave_user_function
   (const octave::symbol_scope& scope, octave::tree_parameter_list *pl,
    octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
-  : octave_user_code ("", scope, ""),
-    param_list (pl), ret_list (rl), cmd_list (cl),
-    lead_comm (), trail_comm (), file_name (),
+  : octave_user_code ("", "", scope, cl, ""),
+    param_list (pl), ret_list (rl),
+    lead_comm (), trail_comm (),
     location_line (0), location_column (0),
-    parent_name (), t_parsed (static_cast<time_t> (0)),
-    t_checked (static_cast<time_t> (0)),
-    system_fcn_file (false), call_depth (-1),
+    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),
@@ -266,13 +208,8 @@
 
 octave_user_function::~octave_user_function (void)
 {
-  // FIXME: shouldn't this happen automatically when deleting cmd_list?
-  if (cmd_list)
-    cmd_list->remove_all_breakpoints (file_name);
-
   delete param_list;
   delete ret_list;
-  delete cmd_list;
   delete lead_comm;
   delete trail_comm;
 
@@ -289,12 +226,6 @@
   return this;
 }
 
-void
-octave_user_function::stash_fcn_file_name (const std::string& nm)
-{
-  file_name = nm;
-}
-
 // If there is no explicit end statement at the end of the function,
 // relocate the no_op that was generated for the end of file condition
 // to appear on the next line after the last statement in the file, or
@@ -401,7 +332,7 @@
       // function file is parsed, it probably doesn't matter that
       // much.
 
-      std::string ff_name = fcn_file_in_path (file_name);
+      std::string ff_name = octave::fcn_file_in_path (file_name);
 
       std::string fcn_file_dir = octave::config::fcn_file_dir ();
       if (fcn_file_dir == ff_name.substr (0, fcn_file_dir.length ()))
@@ -455,6 +386,37 @@
   return m_scope.subfunctions ();
 }
 
+// Find definition of final subfunction in list of subfuns:
+//
+//  sub1>sub2>...>subN
+
+octave_value
+octave_user_function::find_subfunction (const std::string& subfuns_arg) const
+{
+  std::string subfuns = subfuns_arg;
+
+  std::string first_fun = subfuns;
+
+  size_t pos = subfuns.find ('>');
+
+  if (pos == std::string::npos)
+    subfuns = "";
+  else
+    {
+      first_fun = subfuns.substr (0, pos-1);
+      subfuns = subfuns.substr (pos+1);
+    }
+
+  octave_value ov_fcn = m_scope.find_subfunction (first_fun);
+
+  if (subfuns.empty ())
+    return ov_fcn;
+
+  octave_user_function *fcn = ov_fcn.user_function_value ();
+
+  return fcn->find_subfunction (subfuns);
+}
+
 bool
 octave_user_function::has_subfunctions (void) const
 {
@@ -488,194 +450,9 @@
 
 octave_value_list
 octave_user_function::call (octave::tree_evaluator& tw, int nargout,
-                            const octave_value_list& _args)
+                            const octave_value_list& args)
 {
-  octave_value_list retval;
-
-  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 (_args);
-  octave_value_list ret_args;
-
-  if (is_classdef_constructor ())
-    {
-      if (args.length () > 0)
-        {
-          ret_args = args.slice (0, 1, true);
-          args = args.slice (1, args.length () - 1, true);
-        }
-      else
-        panic_impossible ();
-    }
-
-#if defined (HAVE_LLVM)
-  if (is_special_expr ()
-      && octave::tree_jit::execute (*this, args, retval))
-    return retval;
-#endif
-
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
-  call_depth++;
-
-  if (call_depth >= tw.max_recursion_depth ())
-    error ("max_recursion_depth exceeded");
-
-  // Save old and set current symbol table context, for
-  // eval_undefined_error().
-
-  octave::call_stack& cs
-    = octave::__get_call_stack__ ("octave_user_function::call");
-
-  octave::symbol_record::context_id context
-    = anonymous_function ? 0 : call_depth;
-
-  cs.push (this, m_scope, context);
-
-  // Set pointer to the current unwind_protect frame to allow
-  // certain builtins register simple cleanup in a very optimized manner.
-  // This is *not* intended as a general-purpose on-cleanup mechanism,
-  frame.protect_var (curr_unwind_protect_frame);
-  curr_unwind_protect_frame = &frame;
-
-  frame.protect_var (Vtrack_line_num);
-  Vtrack_line_num = true;    // update source line numbers, even if debugging
-  frame.add_method (cs, &octave::call_stack::pop);
-
-  if (call_depth > 0 && ! is_anonymous_function ())
-    {
-      m_scope.push_context ();
-
-#if 0
-      std::cerr << name () << " scope: " << m_scope
-                << " call depth: " << call_depth
-                << " context: " << m_scope.current_context () << std::endl;
-#endif
-
-      frame.add_method (m_scope, &octave::symbol_scope::pop_context);
-    }
-
-  string_vector arg_names = _args.name_tags ();
-
-  if (param_list && ! param_list->varargs_only ())
-    {
-#if 0
-      std::cerr << "defining param list, scope: " << m_scope
-                << ", context: " << m_scope.current_context () << std::endl;
-#endif
-      tw.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.
-
-  if (is_classdef_constructor ())
-    {
-      if (! ret_list)
-        error ("%s: invalid classdef constructor, no output argument defined",
-               dispatch_class ().c_str ());
-
-      tw.define_parameter_list_from_arg_vector (ret_list, ret_args);
-    }
-
-  // Force parameter list to be undefined when this function exits.
-  // Doing so decrements the reference counts on the values of local
-  // variables that are also named function parameters.
-
-  if (param_list)
-    frame.add_method (&tw, &octave::tree_evaluator::undefine_parameter_list,
-                      param_list);
-
-  // Force return list to be undefined when this function exits.
-  // Doing so decrements the reference counts on the values of local
-  // variables that are also named values returned by this function.
-
-  if (ret_list)
-    frame.add_method (&tw, &octave::tree_evaluator::undefine_parameter_list,
-                      ret_list);
-
-  if (call_depth == 0)
-    {
-      // Force symbols to be undefined again when this function
-      // exits.
-      //
-      // This cleanup function is added to the unwind_protect stack
-      // after the calls to clear the parameter lists so that local
-      // variables will be cleared before the parameter lists are
-      // cleared.  That way, any function parameters that have been
-      // declared global will be unmarked as global before they are
-      // undefined by the clear_param_list cleanup function.
-
-      frame.add_method (m_scope, &octave::symbol_scope::refresh);
-    }
-
-  bind_automatic_vars (tw, arg_names, args.length (), nargout,
-                       all_va_args (args));
-
-  frame.add_method (this, &octave_user_function::restore_warning_states);
-
-  // Evaluate the commands that make up the function.
-
-  frame.protect_var (octave::tree_evaluator::statement_context);
-  octave::tree_evaluator::statement_context = octave::tree_evaluator::function;
-
-  {
-    octave::profiler& profiler = tw.get_profiler ();
-
-    octave::profiler::enter<octave_user_function> block (profiler, *this);
-
-    if (tw.echo ())
-      tw.push_echo_state (frame, octave::tree_evaluator::ECHO_FUNCTIONS,
-                          file_name);
-
-    if (is_special_expr ())
-      {
-        assert (cmd_list->length () == 1);
-
-        octave::tree_statement *stmt = cmd_list->front ();
-
-        octave::tree_expression *expr = stmt->expression ();
-
-        if (expr)
-          {
-            cs.set_location (stmt->line (), stmt->column ());
-
-            retval = tw.evaluate_n (expr, nargout);
-          }
-      }
-    else
-      cmd_list->accept (tw);
-  }
-
-  if (octave::tree_return_command::returning)
-    octave::tree_return_command::returning = 0;
-
-  if (octave::tree_break_command::breaking)
-    octave::tree_break_command::breaking--;
-
-  // Copy return values out.
-
-  if (ret_list && ! is_special_expr ())
-    {
-      Cell varargout;
-
-      if (ret_list->takes_varargs ())
-        {
-          octave_value varargout_varval = m_scope.varval ("varargout");
-
-          if (varargout_varval.is_defined ())
-            varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
-        }
-
-      retval = tw.convert_return_list_to_const_vector (ret_list, nargout, varargout);
-    }
-
-  return retval;
+  return tw.execute_user_function (*this, nargout, args);
 }
 
 void
@@ -742,24 +519,20 @@
 octave_user_function::dump (void) const
 {
   std::map<std::string, octave_value> m
-    = {{ "file_name", file_name },
+    = {{ "user_code", octave_user_code::dump () },
        { "line", location_line },
        { "col", location_column },
        { "end_line", end_location_line },
        { "end_col", end_location_column },
-       { "time_parsed", t_parsed },
-       { "time_checked", t_checked },
        { "parent_name", parent_name },
        { "system_fcn_file", system_fcn_file },
-       { "call_depth", call_depth },
        { "num_named_args", num_named_args },
        { "subfunction", subfunction },
        { "inline_function", inline_function },
        { "anonymous_function", anonymous_function },
        { "nested_function", nested_function },
        { "ctor_type", ctor_type_str () },
-       { "class_method", class_method },
-       { "scope_info", m_scope ? m_scope.dump () : "0x0" }};
+       { "class_method", class_method }};
 
   return octave_value (m);
 }
@@ -781,53 +554,6 @@
 }
 
 void
-octave_user_function::bind_automatic_vars
-  (octave::tree_evaluator& tw, const string_vector& arg_names,
-   int nargin, int nargout, const octave_value_list& va_args)
-{
-  if (! arg_names.empty ())
-    {
-      // It is better to save this in the hidden variable .argn. and
-      // then use that in the inputname function instead of using argn,
-      // which might be redefined in a function.  Keep the old argn name
-      // for backward compatibility of functions that use it directly.
-
-      charMatrix chm (arg_names, tw.string_fill_char ());
-      m_scope.force_assign ("argn", chm);
-      m_scope.force_assign (".argn.", Cell (arg_names));
-
-      m_scope.mark_hidden (".argn.");
-
-      m_scope.mark_automatic ("argn");
-      m_scope.mark_automatic (".argn.");
-    }
-
-  m_scope.force_assign (".nargin.", nargin);
-  m_scope.force_assign (".nargout.", nargout);
-
-  m_scope.mark_hidden (".nargin.");
-  m_scope.mark_hidden (".nargout.");
-
-  m_scope.mark_automatic (".nargin.");
-  m_scope.mark_automatic (".nargout.");
-
-  m_scope.force_assign (".saved_warning_states.", octave_value ());
-
-  m_scope.mark_automatic (".saved_warning_states.");
-  m_scope.mark_automatic (".saved_warning_states.");
-
-  if (takes_varargs ())
-    m_scope.assign ("varargin", va_args.cell_value ());
-
-  Matrix ignored_fcn_outputs = tw.ignored_fcn_outputs ();
-
-  m_scope.force_assign (".ignored.", ignored_fcn_outputs);
-
-  m_scope.mark_hidden (".ignored.");
-  m_scope.mark_automatic (".ignored.");
-}
-
-void
 octave_user_function::restore_warning_states (void)
 {
   octave_value val = m_scope.varval (".saved_warning_states.");
--- a/libinterp/octave-value/ov-usr-fcn.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov-usr-fcn.h	Thu Dec 20 17:18:56 2018 -0500
@@ -60,20 +60,19 @@
 {
 protected:
 
-  octave_user_code (const std::string& nm,
+  octave_user_code (const std::string& fnm = "", const std::string& nm = "",
                     const octave::symbol_scope& scope = octave::symbol_scope (),
+                    octave::tree_statement_list *cmds = nullptr,
                     const std::string& ds = "")
-    : octave_function (nm, ds), m_scope (scope), m_file_info (nullptr),
-      curr_unwind_protect_frame (nullptr)
+    : octave_function (nm, ds), m_scope (scope), file_name (fnm),
+      t_parsed (static_cast<time_t> (0)),
+      t_checked (static_cast<time_t> (0)),
+      m_call_depth (-1), m_file_info (nullptr),
+      cmd_list (cmds)
   { }
 
 public:
 
-  octave_user_code (void)
-    : octave_function (), m_scope (), m_file_info (nullptr),
-      curr_unwind_protect_frame (nullptr)
-  { }
-
   // No copying!
 
   octave_user_code (const octave_user_code& f) = delete;
@@ -84,12 +83,6 @@
 
   bool is_user_code (void) const { return true; }
 
-  octave::unwind_protect *
-  unwind_protect_frame (void)
-  {
-    return curr_unwind_protect_frame;
-  }
-
   std::string get_code_line (size_t line);
 
   std::deque<std::string> get_code_lines (size_t line, size_t num_lines);
@@ -99,9 +92,39 @@
 
   octave::symbol_scope scope (void) { return m_scope; }
 
+  void stash_fcn_file_name (const std::string& nm) { file_name = nm; }
+
+  void mark_fcn_file_up_to_date (const octave::sys::time& t) { t_checked = t; }
+
+  void stash_fcn_file_time (const octave::sys::time& t)
+  {
+    t_parsed = t;
+    mark_fcn_file_up_to_date (t);
+  }
+
+  std::string fcn_file_name (void) const { return file_name; }
+
+  octave::sys::time time_parsed (void) const { return t_parsed; }
+
+  octave::sys::time time_checked (void) const { return t_checked; }
+
+  virtual octave_value find_subfunction (const std::string&) const
+  {
+    return octave_value ();
+  }
+
+  // XXX FIXME
+  int call_depth (void) const { return m_call_depth; }
+
+  void set_call_depth (int val) { m_call_depth = val; }
+
+  void increment_call_depth (void) { ++m_call_depth; }
+
   virtual std::map<std::string, octave_value> subfunctions (void) const;
 
-  virtual octave::tree_statement_list * body (void) = 0;
+  octave::tree_statement_list * body (void) { return cmd_list; }
+
+  octave_value dump (void) const;
 
 protected:
 
@@ -110,12 +133,25 @@
   // Our symbol table scope.
   octave::symbol_scope m_scope;
 
+  // The name of the file we parsed.
+  std::string file_name;
+
+  // The time the file was parsed.
+  octave::sys::time t_parsed;
+
+  // The time the file was last checked to see if it needs to be
+  // parsed again.
+  octave::sys::time t_checked;
+
+  // Used to keep track of recursion depth.
+  int m_call_depth;
+
   // Cached text of function or script code with line offsets
   // calculated.
   octave::file_info *m_file_info;
 
-  // pointer to the current unwind_protect frame of this function.
-  octave::unwind_protect *curr_unwind_protect_frame;
+  // The list of commands that make up the body of this function.
+  octave::tree_statement_list *cmd_list;
 };
 
 // Scripts.
@@ -142,7 +178,7 @@
 
   octave_user_script& operator = (const octave_user_script& f) = delete;
 
-  ~octave_user_script (void);
+  ~octave_user_script (void) = default;
 
   octave_function * function_value (bool = false) { return this; }
 
@@ -155,48 +191,17 @@
 
   bool is_user_script (void) const { return true; }
 
-  void stash_fcn_file_name (const std::string& nm) { file_name = nm; }
-
-  void mark_fcn_file_up_to_date (const octave::sys::time& t) { t_checked = t; }
-
-  void stash_fcn_file_time (const octave::sys::time& t)
-  {
-    t_parsed = t;
-    mark_fcn_file_up_to_date (t);
-  }
-
-  std::string fcn_file_name (void) const { return file_name; }
-
-  octave::sys::time time_parsed (void) const { return t_parsed; }
-
-  octave::sys::time time_checked (void) const { return t_checked; }
-
   octave_value_list
   call (octave::tree_evaluator& tw, int nargout = 0,
         const octave_value_list& args = octave_value_list ());
 
-  octave::tree_statement_list * body (void) { return cmd_list; }
+  void accept (octave::tree_walker& tw);
 
-  void accept (octave::tree_walker& tw);
+  // XXX FIXME
+  void set_call_depth (int val) { octave_user_code::set_call_depth (val); }
 
 private:
 
-  // The list of commands that make up the body of this function.
-  octave::tree_statement_list *cmd_list;
-
-  // The name of the file we parsed.
-  std::string file_name;
-
-  // The time the file was parsed.
-  octave::sys::time t_parsed;
-
-  // The time the file was last checked to see if it needs to be
-  // parsed again.
-  octave::sys::time t_checked;
-
-  // Used to keep track of recursion depth.
-  int call_depth;
-
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
@@ -223,7 +228,7 @@
   octave::symbol_record::context_id active_context () const
   {
     return is_anonymous_function ()
-      ? 0 : static_cast<octave::symbol_record::context_id>(call_depth);
+      ? 0 : static_cast<octave::symbol_record::context_id>(m_call_depth);
   }
 
   octave_function * function_value (bool = false) { return this; }
@@ -236,8 +241,6 @@
 
   octave_user_function * define_ret_list (octave::tree_parameter_list *t);
 
-  void stash_fcn_file_name (const std::string& nm);
-
   void stash_fcn_location (int line, int col)
   {
     location_line = line;
@@ -266,16 +269,6 @@
 
   void stash_trailing_comment (octave::comment_list *tc) { trail_comm = tc; }
 
-  void mark_fcn_file_up_to_date (const octave::sys::time& t) { t_checked = t; }
-
-  void stash_fcn_file_time (const octave::sys::time& t)
-  {
-    t_parsed = t;
-    mark_fcn_file_up_to_date (t);
-  }
-
-  std::string fcn_file_name (void) const { return file_name; }
-
   std::string profiler_name (void) const;
 
   std::string parent_fcn_name (void) const { return parent_name; }
@@ -285,10 +278,6 @@
     return m_scope.parent_scope ();
   }
 
-  octave::sys::time time_parsed (void) const { return t_parsed; }
-
-  octave::sys::time time_checked (void) const { return t_checked; }
-
   void mark_as_system_fcn_file (void);
 
   bool is_system_fcn_file (void) const { return system_fcn_file; }
@@ -309,6 +298,8 @@
 
   std::map<std::string, octave_value> subfunctions (void) const;
 
+  octave_value find_subfunction (const std::string& subfuns) const;
+
   bool has_subfunctions (void) const;
 
   void stash_subfunction_names (const std::list<std::string>& names);
@@ -385,8 +376,6 @@
 
   octave::tree_parameter_list * return_list (void) { return ret_list; }
 
-  octave::tree_statement_list * body (void) { return cmd_list; }
-
   octave::comment_list * leading_comment (void) { return lead_comm; }
 
   octave::comment_list * trailing_comment (void) { return trail_comm; }
@@ -407,6 +396,9 @@
 
   octave_value dump (void) const;
 
+  // XXX FIXME
+  void set_call_depth (int val) { octave_user_code::set_call_depth (val); }
+
 private:
 
   enum class_ctor_type
@@ -425,18 +417,12 @@
   // this function.
   octave::tree_parameter_list *ret_list;
 
-  // The list of commands that make up the body of this function.
-  octave::tree_statement_list *cmd_list;
-
   // The comments preceding the FUNCTION token.
   octave::comment_list *lead_comm;
 
   // The comments preceding the ENDFUNCTION token.
   octave::comment_list *trail_comm;
 
-  // The name of the file we parsed.
-  std::string file_name;
-
   // Location where this function was defined.
   int location_line;
   int location_column;
@@ -446,21 +432,11 @@
   // The name of the parent function, if any.
   std::string parent_name;
 
-  // The time the file was parsed.
-  octave::sys::time t_parsed;
-
-  // The time the file was last checked to see if it needs to be
-  // parsed again.
-  octave::sys::time t_checked;
-
   // 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;
 
-  // Used to keep track of recursion depth.
-  int call_depth;
-
   // The number of arguments that have names.
   int num_named_args;
 
@@ -492,10 +468,8 @@
 
   void print_code_function_trailer (const std::string& prefix);
 
-  void bind_automatic_vars (octave::tree_evaluator& tw,
-                            const string_vector& arg_names,
-                            int nargin, int nargout,
-                            const octave_value_list& va_args);
+  // XXX FIXME (public)
+public:
 
   void restore_warning_states (void);
 
--- a/libinterp/octave-value/ov.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -1558,6 +1558,26 @@
   return *this;
 }
 
+// FIXME: This is a bit of a kluge.  We'd like to just use val.dims()
+// and if val is an object, expect that dims will call size if it is
+// overloaded by a user-defined method.  But there are currently some
+// unresolved const issues that prevent that solution from working.
+
+std::string
+octave_value::get_dims_str (void) const
+{
+  octave_value tmp = *this;
+
+  Matrix sz = tmp.size ();
+
+  dim_vector dv = dim_vector::alloc (sz.numel ());
+
+  for (octave_idx_type i = 0; i < dv.ndims (); i++)
+    dv(i) = sz(i);
+
+  return dv.str ();
+}
+
 octave_idx_type
 octave_value::length (void) const
 {
@@ -1805,7 +1825,7 @@
                 retval.xelem (i) = v;
               else
                 {
-                  error_with_cfn ("conversion to integer value failed");
+                  error_with_cfn ("conversion of %g to int value failed", ai);
                   break;
                 }
             }
@@ -1875,7 +1895,7 @@
                 retval.xelem (i) = v;
               else
                 {
-                  error_with_cfn ("conversion to integer value failed");
+                  error_with_cfn ("conversion of %g to octave_idx_type value failed", ai);
                   break;
                 }
             }
--- a/libinterp/octave-value/ov.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave-value/ov.h	Thu Dec 20 17:18:56 2018 -0500
@@ -466,8 +466,9 @@
 
   // Size.
 
-  dim_vector dims (void) const
-  { return rep->dims (); }
+  dim_vector dims (void) const { return rep->dims (); }
+
+  std::string get_dims_str (void) const;
 
   octave_idx_type rows (void) const { return rep->rows (); }
 
--- a/libinterp/octave.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
 #  include "config.h"
 #endif
 
+#include <iostream>
 #include <string>
 
 #include "file-ops.h"
@@ -35,7 +36,6 @@
 #include "str-vec.h"
 
 #include "Cell.h"
-#include "defaults.h"
 #include "defun.h"
 #include "display.h"
 #include "error.h"
--- a/libinterp/octave.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/octave.h	Thu Dec 20 17:18:56 2018 -0500
@@ -48,6 +48,9 @@
 
     cmdline_options& operator = (const cmdline_options&) = default;
 
+    int sys_argc (void) const { return m_all_args.numel (); }
+    char **sys_argv (void) const { return m_all_args.c_str_vec (); }
+
     bool debug_jit (void) const { return m_debug_jit; }
     bool echo_commands (void) const { return m_echo_commands; }
 
@@ -255,6 +258,9 @@
 
     virtual ~application (void);
 
+    int sys_argc (void) const { return m_options.sys_argc (); }
+    char **sys_argv (void) const { return m_options.sys_argv (); }
+
     void set_program_names (const std::string& pname);
 
     void intern_argv (const string_vector& args);
@@ -352,9 +358,6 @@
     // from eval without persist.
     bool m_is_octave_program = false;
 
-    // If TRUE, the GUI should be started.
-    bool m_gui_running = false;
-
     interpreter *m_interpreter = nullptr;
   };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octinterp.in.pc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,9 @@
+Name: @PACKAGE_NAME@
+Description: C++ interface to GNU Octave interpreter.
+URL: https://www.octave.org
+Version: @PACKAGE_VERSION@
+Requires: octave = @PACKAGE_VERSION@
+Requires.private:
+Libs: -L@octlibdir@ @LIBOCTINTERP@
+Libs.private:
+Cflags: -I@octincludedir@/..
--- a/libinterp/op-kw-docs	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/op-kw-docs	Thu Dec 20 17:18:56 2018 -0500
@@ -17,14 +17,14 @@
 ## <https://www.gnu.org/licenses/>.
 
 !
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} !
 Logical 'not' operator.
 @seealso{~, not}
 @end deftypefn
 ~
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ~
 Logical 'not' operator.
@@ -38,21 +38,21 @@
 @seealso{!, not}
 @end deftypefn
 !=
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} !=
 Logical 'not equals' operator.
 @seealso{~=, ne}
 @end deftypefn
 ~=
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ~=
 Logical 'not equals' operator.
 @seealso{!=, ne}
 @end deftypefn
 "
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} "
 String delimiter.
@@ -63,21 +63,21 @@
 @seealso{'}
 @end deftypefn
 #
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} #
 Begin comment character.
 @seealso{%, #@\{}
 @end deftypefn
 %
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} %
 Begin comment character.
 @seealso{#, %@\{}
 @end deftypefn
 #{
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} #@{
 Begin block comment.
@@ -87,7 +87,7 @@
 @seealso{%@\{, #@\}, #}
 @end deftypefn
 %{
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} %@{
 Begin block comment.
@@ -97,7 +97,7 @@
 @seealso{#@\{, %@\}, %}
 @end deftypefn
 #}
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} #@}
 Close block comment.
@@ -107,7 +107,7 @@
 @seealso{%@\}, #@\{, #}
 @end deftypefn
 %}
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} %@}
 Close block comment.
@@ -117,7 +117,7 @@
 @seealso{#@\}, %@\{, %}
 @end deftypefn
 ...
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ...
 Continuation marker.
@@ -125,21 +125,21 @@
 Joins current line with following line before parsing.
 @end deftypefn
 &
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} &
 Element by element logical 'and' operator.
 @seealso{&&, and}
 @end deftypefn
 &&
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} &&
 Logical 'and' operator (with short-circuit evaluation).
 @seealso{&, and}
 @end deftypefn
 '
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} '
 Matrix transpose operator or string delimiter.
@@ -153,26 +153,26 @@
 @seealso{.', transpose, "}
 @end deftypefn
 (
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} (
 Array index or function argument delimiter.
 @end deftypefn
 )
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {})
 Array index or function argument delimiter.
 @end deftypefn
 *
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} *
 Multiplication operator.
 @seealso{.*, times}
 @end deftypefn
 **
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} **
 Power operator.
@@ -183,7 +183,7 @@
 @seealso{power, ^, .**, .^, realpow, realsqrt, cbrt, nthroot}
 @end deftypefn
 ^
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ^
 Power operator.
@@ -194,14 +194,14 @@
 @seealso{power, **, .^, .**, realpow, realsqrt, cbrt, nthroot}
 @end deftypefn
 +
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} +
 Addition operator.
 @seealso{plus}
 @end deftypefn
 ++
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ++
 Increment operator.
@@ -210,20 +210,20 @@
 @seealso{--}
 @end deftypefn
 ,
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ,
 Array index, function argument, or command separator.
 @end deftypefn
 -
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} -
 Subtraction or unary negation operator.
 @seealso{minus}
 @end deftypefn
 --
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} --
 Decrement operator.
@@ -232,7 +232,7 @@
 @seealso{++}
 @end deftypefn
 .'
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} .'
 Matrix transpose operator.
@@ -242,14 +242,14 @@
 @seealso{', transpose}
 @end deftypefn
 .*
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} .*
 Element by element multiplication operator.
 @seealso{*, times}
 @end deftypefn
 .**
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} .**
 Element by element power operator.
@@ -260,7 +260,7 @@
 @seealso{**, ^, .^, power, realpow, realsqrt, cbrt, nthroot}
 @end deftypefn
 .^
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} .^
 Element by element power operator.
@@ -271,28 +271,28 @@
 @seealso{.**, ^, **, power, realpow, realsqrt, cbrt, nthroot}
 @end deftypefn
 ./
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ./
 Element by element right division operator.
 @seealso{/, .\\, rdivide, mrdivide}
 @end deftypefn
 /
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} /
 Right division operator.
 @seealso{./, \\, rdivide, mrdivide}
 @end deftypefn
 .\
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} .\
 Element by element left division operator.
 @seealso{\\, ./, rdivide, mrdivide}
 @end deftypefn
 \
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} \
 Left division operator.
@@ -302,89 +302,89 @@
 @seealso{.\\, /, ldivide, mldivide}
 @end deftypefn
 :
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} :
 Select entire rows or columns of matrices.
 @end deftypefn
 ;
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ;
 Array row or command separator.
 @seealso{,}
 @end deftypefn
 <
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} <
 'Less than' operator.
 @seealso{lt}
 @end deftypefn
 <=
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} <=
 'Less than' or 'equals' operator.
 @seealso{le}
 @end deftypefn
 =
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} =
 Assignment operator.
 @end deftypefn
 ==
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ==
 Equality test operator.
 @seealso{eq}
 @end deftypefn
 >
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} >
 'Greater than' operator.
 @seealso{gt}
 @end deftypefn
 >=
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} >=
 'Greater than' or 'equals' operator.
 @seealso{ge}
 @end deftypefn
 [
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} [
 Return list delimiter.
 @seealso{]}
 @end deftypefn
 ]
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ]
 Return list delimiter.
 @seealso{[}
 @end deftypefn
 |
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} |
 Element by element logical 'or' operator.
 @seealso{||, or}
 @end deftypefn
 ||
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} ||
 Logical 'or' (with short-circuit evaluation) operator.
 @seealso{|, or}
 @end deftypefn
 @
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} @@
 Return handle to a function.
@@ -404,14 +404,14 @@
 @seealso{function, functions, func2str, str2func}
 @end deftypefn
 break
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} break
 Exit the innermost enclosing do, while, or for loop.
 @seealso{do, while, for, parfor, continue}
 @end deftypefn
 case
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn  {} {} case @var{value}
 @deftypefnx {} {} case @{@var{value}, @dots{}@}
@@ -423,7 +423,7 @@
 @seealso{switch}
 @end deftypefn
 catch
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn  {} {} catch
 @deftypefnx {} {} catch @var{value}
@@ -431,21 +431,21 @@
 @seealso{try}
 @end deftypefn
 classdef
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} classdef
 Begin a classdef block.
 @seealso{properties, methods, events, enumeration}
 @end deftypefn
 continue
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} continue
 Jump to the end of the innermost enclosing do, while, or for loop.
 @seealso{break, do, while, for, parfor}
 @end deftypefn
 do
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} do
 Begin a do-until loop.
@@ -464,124 +464,124 @@
 @seealso{for, until, while}
 @end deftypefn
 else
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} else
 Alternate action for an if block.  See @code{if} for  an example.
 @seealso{if}
 @end deftypefn
 elseif
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} elseif (@var{condition})
 Alternate conditional test for an if block.  See @code{if} for an example.
 @seealso{if}
 @end deftypefn
 end_try_catch
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} end_try_catch
 Mark the end of a @code{try-catch} block.
 @seealso{try, catch}
 @end deftypefn
 end_unwind_protect
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} end_unwind_protect
 Mark the end of an unwind_protect block.
 @seealso{unwind_protect}
 @end deftypefn
 endclassdef
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endclassdef
 Mark the end of a classdef definition.
 @seealso{classdef}
 @end deftypefn
 endenumeration
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endenumeration
 Mark the end of an enumeration block in a classdef definition.
 @seealso{enumeration}
 @end deftypefn
 endevents
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endevents
 Mark the end of an events block in a classdef definition.
 @seealso{events}
 @end deftypefn
 endfor
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endfor
 Mark the end of a for loop.  See @code{for} for an example.
 @seealso{for}
 @end deftypefn
 endfunction
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endfunction
 Mark the end of a function.
 @seealso{function}
 @end deftypefn
 endif
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endif
 Mark the end of an if block.  See @code{if} for an example.
 @seealso{if}
 @end deftypefn
 endmethods
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endmethods
 Mark the end of a methods block in a classdef definition.
 @seealso{methods}
 @end deftypefn
 endparfor
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endparfor
 Mark the end of a parfor loop.  See @code{parfor} for an example.
 @seealso{parfor}
 @end deftypefn
 endproperties
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endproperties
 Mark the end of a properties block in a classdef definition.
 @seealso{properties}
 @end deftypefn
 endswitch
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endswitch
 Mark the end of a switch block.  See @code{switch} for an example.
 @seealso{switch}
 @end deftypefn
 endwhile
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} endwhile
 Mark the end of a while loop.  See @code{while} for an example.
 @seealso{do, while}
 @end deftypefn
 enumeration
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} enumeration
 Begin an enumeration block in a classdef definition.
 @end deftypefn
 events
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} events
 Begin an events block in a classdef definition.
 @end deftypefn
 for
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} for @var{i} = @var{range}
 Begin a for loop.
@@ -596,7 +596,7 @@
 @seealso{parfor, do, while}
 @end deftypefn
 function
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn  {} {} function @var{outputs} = function_name (@var{input}, @dots{})
 @deftypefnx {} {} function {} function_name (@var{input}, @dots{})
@@ -612,7 +612,7 @@
 @seealso{return}
 @end deftypefn
 global
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} global @var{var}
 Declare variables to have global scope.
@@ -628,7 +628,7 @@
 @seealso{persistent}
 @end deftypefn
 if
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn  {} {} if (@var{cond}) @dots{} endif
 @deftypefnx {} {} if (@var{cond}) @dots{} else @dots{} endif
@@ -653,13 +653,13 @@
 @c ## FIXME: Can't have duplicate DOCSTRING entries.  The function methods
 @c ##        already has a docstring which overrides this keyword definition.
 @c #methods
-@c #@c libinterp/parse-tree/oct-parse.in.yy
+@c #@c libinterp/parse-tree/oct-parse.yy
 @c #-*- texinfo -*-
 @c #@deftypefn {} {} methods
 @c #Begin a methods block in a classdef definition.
 @c #@end deftypefn
 otherwise
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} otherwise
 The default statement in a switch block which is executed when no other
@@ -667,7 +667,7 @@
 @seealso{switch, case}
 @end deftypefn
 parfor
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn  {} {} parfor @var{i} = @var{range}
 @deftypefnx {} {} parfor (@var{i} = @var{range}, @var{maxproc})
@@ -683,7 +683,7 @@
 @seealso{for, do, while}
 @end deftypefn
 persistent
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} persistent @var{var}
 Declare variables as persistent.
@@ -696,27 +696,27 @@
 @seealso{global}
 @end deftypefn
 properties
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} properties
 Begin a properties block in a classdef definition.
 @end deftypefn
 return
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} return
 Return from a function.
 @seealso{function}
 @end deftypefn
 static
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} static
 This statement has been deprecated in favor of @code{persistent}.
 @seealso{persistent}
 @end deftypefn
 switch
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} switch @var{statement}
 Begin a switch block.
@@ -738,7 +738,7 @@
 @seealso{if, case, otherwise}
 @end deftypefn
 try
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} try
 Begin a try-catch block.
@@ -749,14 +749,14 @@
 @seealso{catch, unwind_protect}
 @end deftypefn
 until
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} until (@var{cond})
 End a do-until loop.  See @code{do} for an example.
 @seealso{do}
 @end deftypefn
 unwind_protect
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} unwind_protect
 Begin an unwind_protect block.
@@ -769,28 +769,28 @@
 @seealso{unwind_protect_cleanup, try}
 @end deftypefn
 unwind_protect_cleanup
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} unwind_protect_cleanup
 Begin the cleanup section of an unwind_protect block.
 @seealso{unwind_protect}
 @end deftypefn
 varargin
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} varargin
 Pass an arbitrary number of arguments into a function.
 @seealso{varargout, nargin, isargout, nargout, nthargout}
 @end deftypefn
 varargout
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} varargout
 Pass an arbitrary number of arguments out of a function.
 @seealso{varargin, nargin, isargout, nargout, nthargout}
 @end deftypefn
 while
-@c libinterp/parse-tree/oct-parse.in.yy
+@c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
 @deftypefn {} {} while
 Begin a while loop.
--- a/libinterp/operators/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/operators/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -142,3 +142,4 @@
 	$(AM_V_GEN)rm -f $@-t $@ && \
 	$(SHELL) $(srcdir)/%reldir%/mk-ops.sh $(LIBINTERP_OPERATORS_SRC) > $@-t && \
 	mv $@-t $@
+
--- a/libinterp/parse-tree/bp-table.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/bp-table.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,14 +26,11 @@
 #endif
 
 #include <algorithm>
-#include <fstream>
 #include <limits>
 #include <list>
 #include <map>
 #include <set>
 #include <string>
-#include <sstream>
-#include <iostream>
 
 #include "file-ops.h"
 
@@ -41,6 +38,7 @@
 #include "defun-int.h"
 #include "call-stack.h"
 #include "error.h"
+#include "interpreter.h"
 #include "interpreter-private.h"
 #include "oct-map.h"
 #include "octave-link.h"
@@ -53,7 +51,6 @@
 #include "pt-exp.h"
 #include "pt-stmt.h"
 #include "sighandlers.h"
-#include "symtab.h"
 
 namespace octave
 {
@@ -70,7 +67,7 @@
     Vdebug_on_warning = false;
     bp_table::m_warnings_that_stop.clear ();
 
-    octave::Vdebug_on_interrupt = false;
+    Vdebug_on_interrupt = false;
   }
 
   // Process the "warn", "errs", "caught" and "intr" fields for a call of
@@ -101,6 +98,7 @@
               }
           }
       }
+
     if (fail)
       error ("dbstop: invalid 'errs' field");
 
@@ -127,6 +125,7 @@
               }
           }
       }
+
     if (fail)
       error ("dbstop: invalid 'caught' field");
 
@@ -153,12 +152,13 @@
               }
           }
       }
+
     if (fail)
       error ("dbstop: invalid 'warn' field");
 
     // process interrupt
     if (mv.isfield ("intr"))
-      octave::Vdebug_on_interrupt = 1;
+      Vdebug_on_interrupt = 1;
   }
 
   // Insert a breakpoint in function fcn at line within file fname,
@@ -173,7 +173,7 @@
   {
     bool found = false;
 
-    octave::tree_statement_list *cmds = fcn->body ();
+    tree_statement_list *cmds = fcn->body ();
 
     std::string file = fcn->fcn_file_name ();
 
@@ -212,14 +212,15 @@
   {
     if (cond.length () > 0)
       {
-        octave::parser parser (cond + " ;"); // ; to reject partial expr like "y=="
+        // ; to reject partial expr like "y=="
+        parser parser (cond + " ;", m_evaluator.get_interpreter ());
         parser.reset ();
         int parse_status = parser.run ();
         if (parse_status)
           error ("dbstop: Cannot parse condition '%s'", cond.c_str ());
         else
           {
-            octave::tree_statement *stmt = nullptr;
+            tree_statement *stmt = nullptr;
             if (! parser.m_stmt_list)
               error ("dbstop: "
                      "condition is not empty, but has nothing to evaluate");
@@ -229,7 +230,7 @@
                     && (stmt = parser.m_stmt_list->front ())
                     && stmt->is_expression ())
                   {
-                    octave::tree_expression *expr = stmt->expression ();
+                    tree_expression *expr = stmt->expression ();
                     if (expr->is_assignment_expression ())
                       error ("dbstop: condition cannot be an assignment.  "
                              "Did you mean '=='?");
@@ -239,6 +240,7 @@
               }
           }
       }
+
     return true;
   }
 
@@ -329,21 +331,21 @@
               error ("%s: Only one 'at' clause is allowed -- %s",
                      who, args(pos).string_value ().c_str ());
             else if (seen_if)
-              error ("%s: line number must come before 'if' clause\n");
+              error ("%s: line number must come before 'if' clause\n", who);
             seen_at = true;
 
             if (! seen_in)
               {
                 // It was a line number.  Get function name from debugger.
                 if (Vdebugging)
-                  symbol_name = get_user_code ()->profiler_name ();
+                  symbol_name = m_evaluator.get_user_code ()->profiler_name ();
                 else
                   error ("%s: function name must come before line number "
                          "and 'if'", who);
                 seen_in = true;
               }
             else if (seen_if)
-              error ("%s: line number must come before 'if' clause\n");
+              error ("%s: line number must come before 'if' clause\n", who);
 
             // Read a list of line numbers (or arrays thereof)
             for ( ; pos < nargin; pos++)
@@ -366,7 +368,7 @@
                   }
                 else
                   error ("%s: Invalid argument type %s",
-                         args(pos).type_name ().c_str ());
+                         who, args(pos).type_name ().c_str ());
               }
             break;
 
@@ -412,7 +414,7 @@
                   }
                 else if (condition == "interrupt")
                   {
-                    octave::Vdebug_on_interrupt = on_off;
+                    Vdebug_on_interrupt = on_off;
                   }
                 else if (condition == "naninf")
                   {
@@ -455,7 +457,7 @@
                         if (stop_flag == &Vdebug_on_error)
                           {
                             // Matlab stops on both.
-                            octave::Vdebug_on_interrupt = on_off;
+                            Vdebug_on_interrupt = on_off;
                           }
                       }
                   }
@@ -555,7 +557,7 @@
                                              const bp_table::intmap& line,
                                              const std::string& condition)
   {
-    octave_user_code *main_fcn = get_user_code (fname);
+    octave_user_code *main_fcn = m_evaluator.get_user_code (fname);
 
     if (! main_fcn)
       error ("add_breakpoint: unable to find function '%s'\n", fname.c_str ());
@@ -586,8 +588,7 @@
           }
       }
 
-    octave::tree_evaluator::debug_mode = bp_table::have_breakpoints ()
-                                         || Vdebugging;
+    m_evaluator.debug_mode (bp_table::have_breakpoints () || Vdebugging);
 
     return retval;
   }
@@ -600,7 +601,7 @@
 
     std::string file = fcn->fcn_file_name ();
 
-    octave::tree_statement_list *cmds = fcn->body ();
+    tree_statement_list *cmds = fcn->body ();
 
     // FIXME: move the operation on cmds to the tree_statement_list class?
 
@@ -629,7 +630,7 @@
 
             results = cmds->list_breakpoints ();
 
-            bp_set_iterator it = m_bp_set.find (fname);
+            auto it = m_bp_set.find (fname);
             if (results.empty () && it != m_bp_set.end ())
               m_bp_set.erase (it);
           }
@@ -654,7 +655,7 @@
       }
     else
       {
-        octave_user_code *dbg_fcn = get_user_code (fname);
+        octave_user_code *dbg_fcn = m_evaluator.get_user_code (fname);
 
         if (! dbg_fcn)
           error ("remove_breakpoint: unable to find function %s\n",
@@ -683,8 +684,7 @@
           }
       }
 
-    octave::tree_evaluator::debug_mode = bp_table::have_breakpoints ()
-                                         || Vdebugging;
+    m_evaluator.debug_mode (bp_table::have_breakpoints () || Vdebugging);
 
     return retval;
   }
@@ -697,19 +697,19 @@
   {
     intmap retval;
 
-    octave_user_code *dbg_fcn = get_user_code (fname);
+    octave_user_code *dbg_fcn = m_evaluator.get_user_code (fname);
 
     if (dbg_fcn)
       {
         std::string file = dbg_fcn->fcn_file_name ();
 
-        octave::tree_statement_list *cmds = dbg_fcn->body ();
+        tree_statement_list *cmds = dbg_fcn->body ();
 
         if (cmds)
           {
             retval = cmds->remove_all_breakpoints (file);
 
-            bp_set_iterator it = m_bp_set.find (fname);
+            auto it = m_bp_set.find (fname);
             if (it != m_bp_set.end ())
               m_bp_set.erase (it);
           }
@@ -718,25 +718,24 @@
       error ("remove_all_breakpoint_in_file: "
              "unable to find function %s\n", fname.c_str ());
 
-    octave::tree_evaluator::debug_mode = bp_table::have_breakpoints ()
-                                         || Vdebugging;
+    m_evaluator.debug_mode (bp_table::have_breakpoints () || Vdebugging);
 
     return retval;
   }
 
   void bp_table::remove_all_breakpoints (void)
   {
-    // Odd loop structure required because delete will invalidate m_bp_set iterators
-    for (const_bp_set_iterator it = m_bp_set.begin (), it_next = it;
-         it != m_bp_set.end ();
+    // Odd loop structure required because delete will invalidate
+    // m_bp_set iterators.
+    for (auto it = m_bp_set.cbegin (), it_next = it;
+         it != m_bp_set.cend ();
          it = it_next)
       {
         ++it_next;
         remove_all_breakpoints_in_file (*it);
       }
 
-    octave::tree_evaluator::debug_mode = bp_table::have_breakpoints ()
-                                         || Vdebugging;
+    m_evaluator.debug_mode (bp_table::have_breakpoints () || Vdebugging);
   }
 
   std::string find_bkpt_list (octave_value_list slist, std::string match)
@@ -768,11 +767,11 @@
         if (fname_list.empty ()
             || find_bkpt_list (fname_list, bp_fname) != "")
           {
-            octave_user_code *dbg_fcn = get_user_code (bp_fname);
+            octave_user_code *dbg_fcn = m_evaluator.get_user_code (bp_fname);
 
             if (dbg_fcn)
               {
-                octave::tree_statement_list *cmds = dbg_fcn->body ();
+                tree_statement_list *cmds = dbg_fcn->body ();
 
                 // FIXME: move the operation on cmds to the
                 //        tree_statement_list class?
@@ -917,7 +916,7 @@
       }
 
     // print dbstop if interrupt information
-    if (octave::Vdebug_on_interrupt)
+    if (Vdebug_on_interrupt)
       {
         if (to_screen)
           octave_stdout << "stop if interrupt\n";
@@ -928,46 +927,11 @@
     return retval;
   }
 
-  // Return a pointer to the user-defined function FNAME.  If FNAME is empty,
-  // search backward for the first user-defined function in the
-  // current call stack.
-
   octave_user_code *
   get_user_code (const std::string& fname)
   {
-    octave_user_code *dbg_fcn = nullptr;
-
-    if (fname.empty ())
-      {
-        octave::call_stack& cs = octave::__get_call_stack__ ("get_user_code");
-
-        dbg_fcn = cs.debug_user_code ();
-      }
-    else
-      {
-        std::string name = fname;
+    tree_evaluator& tw = __get_evaluator__ ("get_user_code");
 
-        if (octave::sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
-          {
-            auto beg = name.begin () + 2;  // never have @/method
-            auto end = name.end () - 1;    // never have trailing '/'
-            std::replace (beg, end, '/', octave::sys::file_ops::dir_sep_char ());
-          }
-
-        size_t name_len = name.length ();
-
-        if (name_len > 2 && name.substr (name_len-2) == ".m")
-          name = name.substr (0, name_len-2);
-
-        octave::symbol_table& symtab =
-          octave::__get_symbol_table__ ("get_user_code");
-
-        octave_value fcn = symtab.find_function (name);
-
-        if (fcn.is_defined () && fcn.is_user_code ())
-          dbg_fcn = fcn.user_code_value ();
-      }
-
-    return dbg_fcn;
+    return tw.get_user_code (fname);
   }
 }
--- a/libinterp/parse-tree/bp-table.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/bp-table.h	Thu Dec 20 17:18:56 2018 -0500
@@ -36,6 +36,8 @@
 
 namespace octave
 {
+  class tree_evaluator;
+
   struct bp_type
   {
     int line;
@@ -49,9 +51,9 @@
   {
   public:
 
-    bp_table (void)
-      : m_bp_set (), m_errors_that_stop (), m_caught_that_stop (),
-        m_warnings_that_stop ()
+    bp_table (tree_evaluator& tw)
+      : m_evaluator (tw), m_bp_set (), m_errors_that_stop (),
+        m_caught_that_stop (), m_warnings_that_stop ()
     { }
 
     ~bp_table (void) = default;
@@ -128,6 +130,8 @@
     typedef std::set<std::string>::const_iterator const_bp_set_iterator;
     typedef std::set<std::string>::iterator bp_set_iterator;
 
+    tree_evaluator& m_evaluator;
+
     // Set of function (.m file) names containing at least one breakpoint.
     std::set<std::string> m_bp_set;
 
@@ -149,6 +153,7 @@
                                              const std::string& fname);
   };
 
+  OCTAVE_DEPRECATED (5, "use 'octave::get_user_code' instead")
   extern octave_user_code * get_user_code (const std::string& fname = "");
 }
 
--- a/libinterp/parse-tree/comment-list.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/comment-list.h	Thu Dec 20 17:18:56 2018 -0500
@@ -85,14 +85,14 @@
   };
 
   class
-  comment_list : public octave::base_list<comment_elt>
+  comment_list : public base_list<comment_elt>
   {
   public:
 
     comment_list (void) { }
 
     void append (const comment_elt& elt)
-    { octave::base_list<comment_elt>::append (elt); }
+    { base_list<comment_elt>::append (elt); }
 
     void append (const std::string& s,
                  comment_elt::comment_type t = comment_elt::unknown)
--- a/libinterp/parse-tree/jit-ir.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/jit-ir.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -50,7 +50,7 @@
   // -------------------- jit_factory --------------------
   jit_factory::~jit_factory (void)
   {
-    for (value_list::iterator iter = m_all_values.begin ();
+    for (auto iter = m_all_values.begin ();
          iter != m_all_values.end (); ++iter)
       delete *iter;
   }
@@ -111,7 +111,7 @@
   jit_block_list::print_dom (std::ostream& os) const
   {
     os << "-------------------- dom info --------------------\n";
-    for (const_iterator iter = begin (); iter != end (); ++iter)
+    for (auto iter = begin (); iter != end (); ++iter)
       {
         assert (*iter);
         (*iter)->print_dom (os);
@@ -125,15 +125,14 @@
   jit_block_list::push_back (jit_block *b)
   {
     m_list.push_back (b);
-    iterator iter = m_list.end ();
+    auto iter = m_list.end ();
     b->stash_location (--iter);
   }
 
   std::ostream&
   operator<<(std::ostream& os, const jit_block_list& blocks)
   {
-    for (jit_block_list::const_iterator iter = blocks.begin ();
-         iter != blocks.end (); ++iter)
+    for (auto iter = blocks.begin (); iter != blocks.end (); ++iter)
       {
         assert (*iter);
         (*iter)->print (os, 0);
@@ -290,7 +289,7 @@
       old_term->remove ();
 
     bool was_empty = end () == begin ();
-    iterator merge_begin = end ();
+    auto merge_begin = end ();
     if (! was_empty)
       --merge_begin;
 
@@ -302,7 +301,7 @@
 
     // now merge_begin points to the start of the new instructions, we must
     // update their parent information
-    for (iterator iter = merge_begin; iter != end (); ++iter)
+    for (auto iter = merge_begin; iter != end (); ++iter)
       {
         jit_instruction *instr = *iter;
         instr->stash_parent (this, iter);
@@ -323,7 +322,7 @@
   jit_block::prepend_after_phi (jit_instruction *instr)
   {
     // FIXME: Make this O(1)
-    for (iterator iter = begin (); iter != end (); ++iter)
+    for (auto iter = begin (); iter != end (); ++iter)
       {
         jit_instruction *temp = *iter;
         if (! isa<jit_phi> (temp))
@@ -346,7 +345,7 @@
   jit_instruction *
   jit_block::insert_before (iterator loc, jit_instruction *instr)
   {
-    iterator iloc = m_instructions.insert (loc, instr);
+    auto iloc = m_instructions.insert (loc, instr);
     instr->stash_parent (this, iloc);
     return instr;
   }
@@ -355,7 +354,7 @@
   jit_block::insert_after (iterator loc, jit_instruction *instr)
   {
     ++loc;
-    iterator iloc = m_instructions.insert (loc, instr);
+    auto iloc = m_instructions.insert (loc, instr);
     instr->stash_parent (this, iloc);
     return instr;
   }
@@ -419,7 +418,7 @@
       os << "NULL";
     os << std::endl;
     os << "  df: ";
-    for (df_iterator iter = df_begin (); iter != df_end (); ++iter)
+    for (auto iter = df_begin (); iter != df_end (); ++iter)
       os << **iter << ' ';
     os << std::endl;
 
@@ -505,7 +504,7 @@
   void
   jit_block::pop_all (void)
   {
-    for (iterator iter = begin (); iter != end (); ++iter)
+    for (auto iter = begin (); iter != end (); ++iter)
       {
         jit_instruction *instr = *iter;
         instr->pop_variable ();
@@ -526,7 +525,7 @@
       }
     os << std::endl;
 
-    for (const_iterator iter = begin (); iter != end (); ++iter)
+    for (auto iter = begin (); iter != end (); ++iter)
       {
         jit_instruction *instr = *iter;
         instr->print (os, indent + 1) << std::endl;
--- a/libinterp/parse-tree/jit-typeinfo.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/jit-typeinfo.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -216,7 +216,7 @@
   extern "C" void
   octave_jit_err_nan_to_logical_conversion (void)
   {
-    octave::err_nan_to_logical_conversion ();
+    err_nan_to_logical_conversion ();
   }
 
   extern "C" void
@@ -225,14 +225,14 @@
     // FIXME: 0-argument form of octave::err_invalid_index removed in
     //        cset dd6345fd8a97.  Report -1 as the bad index for all
     //        occurrences.
-    octave::err_invalid_index (static_cast<octave_idx_type> (-1));
+    err_invalid_index (static_cast<octave_idx_type> (-1));
   }
 
   extern "C" void
   octave_jit_gindex_range (int nd, int dim, octave_idx_type iext,
                            octave_idx_type ext)
   {
-    octave::err_index_out_of_range (nd, dim, iext, ext);
+    err_index_out_of_range (nd, dim, iext, ext);
   }
 
   extern "C" jit_matrix
@@ -397,7 +397,7 @@
   static inline int
   xisint (double x)
   {
-    return (octave::math::x_nint (x) == x
+    return (math::x_nint (x) == x
             && ((x >= 0 && x < std::numeric_limits<int>::max ())
                 || (x <= 0 && x > std::numeric_limits<int>::min ())));
   }
@@ -438,7 +438,7 @@
   extern "C" void
   octave_jit_print_matrix (jit_matrix *m)
   {
-    std::cout << *m << std::endl;
+    octave_stdout << *m << std::endl;
   }
 
   OCTAVE_NORETURN static
@@ -586,8 +586,7 @@
           }
       }
 
-    for (std::vector<jit_type *>::const_iterator iter = m_args.begin ();
-         iter != m_args.end (); ++iter)
+    for (auto iter = m_args.cbegin (); iter != m_args.cend (); ++iter)
       {
         jit_type *ty = *iter;
         assert (ty);
@@ -751,7 +750,7 @@
     // FIXME: We should be treating arguments like a list, not a vector.
     // Shouldn't matter much for now, as the number of arguments shouldn't
     // be much bigger than 4
-    llvm::Function::arg_iterator iter = m_llvm_function->arg_begin ();
+    auto iter = m_llvm_function->arg_begin ();
     if (sret ())
       ++iter;
 
@@ -804,8 +803,7 @@
   // -------------------- jit_operation --------------------
   jit_operation::~jit_operation (void)
   {
-    for (generated_map::iterator iter = m_generated.begin ();
-         iter != m_generated.end (); ++iter)
+    for (auto iter = m_generated.begin (); iter != m_generated.end (); ++iter)
       {
         delete iter->first;
         delete iter->second;
@@ -878,7 +876,7 @@
   jit_operation::to_idx (const std::vector<jit_type*>& types) const
   {
     octave_idx_type numel = types.size ();
-    numel = std::max (numel, static_cast<octave_idx_type>(2));
+    numel = std::max (numel, static_cast<octave_idx_type> (2));
 
     Array<octave_idx_type> idx (dim_vector (1, numel));
     for (octave_idx_type i = 0;
@@ -1975,7 +1973,7 @@
     std::vector<jit_type *> args;
     args.resize (1);
 
-    for (std::map<std::string, jit_type *>::iterator iter = m_builtins.begin ();
+    for (auto iter = m_builtins.begin ();
          iter != m_builtins.end (); ++iter)
       {
         jit_type *btype = iter->second;
--- a/libinterp/parse-tree/jit-typeinfo.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/jit-typeinfo.h	Thu Dec 20 17:18:56 2018 -0500
@@ -754,7 +754,7 @@
 
     const jit_operation& do_binary_op (int op) const
     {
-      assert (static_cast<size_t>(op) < m_binary_ops.size ());
+      assert (static_cast<size_t> (op) < m_binary_ops.size ());
       return m_binary_ops[op];
     }
 
--- a/libinterp/parse-tree/lex.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/lex.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,6 @@
 #include "octave-config.h"
 
 #include <deque>
-#include <limits>
 #include <list>
 #include <set>
 #include <stack>
@@ -41,7 +40,7 @@
   class interpreter;
 
   // Is the given string a keyword?
-  extern bool is_keyword (const std::string& s);
+  extern bool iskeyword (const std::string& s);
 
   // For communication between the lexer and parser.
 
@@ -581,7 +580,7 @@
       comment_list *m_comment_list;
     };
 
-    base_lexer (interpreter *interp = nullptr)
+    base_lexer (interpreter& interp)
       : lexical_feedback (), m_scanner (nullptr), m_input_buf (),
         m_comment_buf (), m_interpreter (interp)
     {
@@ -676,6 +675,12 @@
 
     void fatal_error (const char *msg);
 
+    bool debug_flag (void) const;
+
+    bool display_tokens (void) const;
+
+    void increment_token_count (void);
+
     void lexer_debug (const char *pattern);
 
     // Internal state of the flex-generated lexer.
@@ -688,7 +693,7 @@
     comment_buffer m_comment_buf;
 
     // Interpreter that contains us, if any.
-    interpreter *m_interpreter;
+    interpreter& m_interpreter;
 
     virtual void increment_promptflag (void) = 0;
 
@@ -706,6 +711,8 @@
 
     virtual bool input_from_eval_string (void) const { return false; }
 
+    bool input_from_tmp_history_file (void);
+
     void push_start_state (int state);
 
     void pop_start_state (void);
@@ -755,15 +762,15 @@
   {
   public:
 
-    lexer (interpreter *interp = nullptr)
+    lexer (interpreter& interp)
       : base_lexer (interp), m_reader (this)
     { }
 
-    lexer (FILE *file, interpreter *interp = nullptr)
+    lexer (FILE *file, interpreter& interp)
       : base_lexer (interp), m_reader (file, this)
     { }
 
-    lexer (const std::string& eval_string, interpreter *interp = nullptr)
+    lexer (const std::string& eval_string, interpreter& interp)
       : base_lexer (interp), m_reader (eval_string, this)
     { }
 
@@ -818,26 +825,25 @@
   {
   public:
 
-    push_lexer (interpreter *interp = nullptr)
+    push_lexer (interpreter& interp)
       : base_lexer (interp), m_pflag (1)
     {
       append_input ("", false);
     }
 
-    push_lexer (const std::string& input, interpreter *interp = nullptr)
+    push_lexer (const std::string& input, interpreter& interp)
       : base_lexer (interp), m_pflag (1)
     {
       append_input (input, false);
     }
 
-    push_lexer (bool eof, interpreter *interp = nullptr)
+    push_lexer (bool eof, interpreter& interp)
       : base_lexer (interp), m_pflag (1)
     {
       append_input ("", eof);
     }
 
-    push_lexer (const std::string& input, bool eof,
-                interpreter *interp = nullptr)
+    push_lexer (const std::string& input, bool eof, interpreter& interp)
       : base_lexer (interp), m_pflag (1)
     {
       append_input (input, eof);
--- a/libinterp/parse-tree/lex.ll	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/lex.ll	Thu Dec 20 17:18:56 2018 -0500
@@ -323,13 +323,6 @@
      }                                                                  \
    while (0)
 
-static bool Vdisplay_tokens = false;
-
-static unsigned int Vtoken_count = 0;
-
-// Internal variable for lexer debugging state.
-static bool lexer_debug_flag = false;
-
 %}
 
 D       [0-9]
@@ -514,6 +507,8 @@
 <MATRIX_START>{S}* {
     curr_lexer->lexer_debug ("<MATRIX_START>{S}*");
 
+    curr_lexer->m_current_input_column += yyleng;
+
     curr_lexer->mark_previous_token_trailing_space ();
   }
 
@@ -555,14 +550,7 @@
 <MATRIX_START>\] {
     curr_lexer->lexer_debug ("<MATRIX_START>\\]");
 
-    curr_lexer->m_looking_at_object_index.pop_front ();
-
-    curr_lexer->m_looking_for_object_index = true;
-    curr_lexer->m_at_beginning_of_statement = false;
-
-    curr_lexer->handle_close_bracket (']');
-
-    return curr_lexer->count_token (']');
+    return curr_lexer->handle_close_bracket (']');
   }
 
 %{
@@ -572,14 +560,7 @@
 <MATRIX_START>\} {
     curr_lexer->lexer_debug ("<MATRIX_START>\\}*");
 
-    curr_lexer->m_looking_at_object_index.pop_front ();
-
-    curr_lexer->m_looking_for_object_index = true;
-    curr_lexer->m_at_beginning_of_statement = false;
-
-    curr_lexer->handle_close_bracket ('}');
-
-    return curr_lexer->count_token ('}');
+    return curr_lexer->handle_close_bracket ('}');
   }
 
 \[ {
@@ -1149,6 +1130,8 @@
           {
             yyless (0);
             unput (',');
+            // Adjust for comma that was not really in the input stream.
+            curr_lexer->m_current_input_column--;
           }
         else
           {
@@ -1184,6 +1167,8 @@
           {
             yyless (0);
             unput (',');
+            // Adjust for comma that was not really in the input stream.
+            curr_lexer->m_current_input_column--;
           }
         else
           {
@@ -1330,6 +1315,8 @@
           {
             yyless (0);
             unput (',');
+            // Adjust for comma that was not really in the input stream.
+            curr_lexer->m_current_input_column--;
           }
         else
           {
@@ -1441,7 +1428,10 @@
                     curr_lexer->begin_string (SQ_STRING_START);
                   }
                 else
-                  return curr_lexer->count_token (HERMITIAN);
+                  {
+                    curr_lexer->m_current_input_column++;
+                    return curr_lexer->count_token (HERMITIAN);
+                  }
               }
           }
         else
@@ -1454,7 +1444,10 @@
                 curr_lexer->begin_string (SQ_STRING_START);
               }
             else
-              return curr_lexer->count_token (HERMITIAN);
+              {
+                curr_lexer->m_current_input_column++;
+                return curr_lexer->count_token (HERMITIAN);
+              }
           }
       }
   }
@@ -1761,7 +1754,7 @@
         std::ostringstream buf;
 
         buf << "invalid character '"
-            << undo_string_escape (static_cast<char> (c))
+            << octave::undo_string_escape (static_cast<char> (c))
             << "' (ASCII " << c << ")";
 
         octave::token *tok
@@ -1959,7 +1952,7 @@
 namespace octave
 {
   bool
-  is_keyword (const std::string& s)
+  iskeyword (const std::string& s)
   {
     // Parsing function names like "set.property_name" inside
     // classdef-style class definitions is simplified by handling the
@@ -1996,7 +1989,7 @@
   if (nargin == 0)
     {
       // Neither set nor get are keywords.  See the note in the
-      // is_keyword function for additional details.
+      // iskeyword function for additional details.
 
       string_vector lst (TOTAL_KEYWORDS);
 
@@ -2017,7 +2010,7 @@
   else
     {
       std::string name = args(0).xstring_value ("iskeyword: NAME must be a string");
-      retval = octave::is_keyword (name);
+      retval = octave::iskeyword (name);
     }
 
   return retval;
@@ -2036,44 +2029,6 @@
 
 */
 
-DEFUN (__display_tokens__, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} __display_tokens__ ()
-Query or set the internal variable that determines whether Octave's
-lexer displays tokens as they are read.
-@seealso{__lexer_debug_flag__, __token_count__}
-@end deftypefn */)
-{
-  return SET_INTERNAL_VARIABLE (display_tokens);
-}
-
-DEFUN (__token_count__, , ,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} __token_count__ ()
-Return the number of language tokens processed since Octave startup.
-@seealso{__lexer_debug_flag__, __display_tokens__}
-@end deftypefn */)
-{
-  return octave_value (Vtoken_count);
-}
-
-DEFUN (__lexer_debug_flag__, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} __lexer_debug_flag__ ()
-@deftypefnx {} {@var{old_val} =} __lexer_debug_flag__ (@var{new_val})
-Query or set the internal flag that determines whether Octave's lexer prints
-debug information as it processes an expression.
-@seealso{__display_tokens__, __token_count__, __parse_debug_flag__}
-@end deftypefn */)
-{
-  octave_value retval;
-
-  retval = set_internal_variable (lexer_debug_flag, args, nargout,
-                                  "__lexer_debug_flag__");
-
-  return retval;
-}
-
 namespace octave
 {
   void
@@ -2239,7 +2194,7 @@
   lexical_feedback::previous_token_is_keyword (void) const
   {
     const token *tok = m_tokens.front ();
-    return tok ? tok->is_keyword () : false;
+    return tok ? tok->iskeyword () : false;
   }
 
   bool
@@ -2438,7 +2393,7 @@
   {
     int c = yyinput (m_scanner);
 
-    if (lexer_debug_flag)
+    if (debug_flag ())
       {
         std::cerr << "I: ";
         display_character (c);
@@ -2451,7 +2406,7 @@
       {
         c = yyinput (m_scanner);
 
-        if (lexer_debug_flag)
+        if (debug_flag ())
           {
             std::cerr << "I: ";
             display_character (c);
@@ -2473,7 +2428,7 @@
   {
     if (c != EOF)
       {
-        if (lexer_debug_flag)
+        if (debug_flag ())
           {
             std::cerr << "U: ";
             display_character (c);
@@ -2968,7 +2923,12 @@
   int
   base_lexer::handle_close_bracket (int bracket_type)
   {
-    int retval = bracket_type;
+    m_looking_at_object_index.pop_front ();
+
+    m_looking_for_object_index = true;
+    m_at_beginning_of_statement = false;
+
+    m_current_input_column++;
 
     if (! m_nesting_level.none ())
       {
@@ -2984,7 +2944,7 @@
 
     pop_start_state ();
 
-    return retval;
+    return count_token (bracket_type);
   }
 
   bool
@@ -3407,10 +3367,33 @@
     error ("fatal lexer error: %s", msg);
   }
 
+  bool
+  base_lexer::debug_flag (void) const
+  {
+    settings& stgs = m_interpreter.get_settings ();
+    return stgs.lexer_debug_flag ();
+  }
+
+  bool
+  base_lexer::display_tokens (void) const
+  {
+    settings& stgs = m_interpreter.get_settings ();
+    return stgs.display_tokens ();
+  }
+
+  void
+  base_lexer::increment_token_count (void)
+  {
+    settings& stgs = m_interpreter.get_settings ();
+    stgs.increment_token_count ();
+
+    m_token_count++;
+  }
+
   void
   base_lexer::lexer_debug (const char *pattern)
   {
-    if (lexer_debug_flag)
+    if (debug_flag ())
       {
         std::cerr << std::endl;
 
@@ -3421,6 +3404,14 @@
       }
   }
 
+  bool
+  base_lexer::input_from_tmp_history_file (void)
+  {
+    history_system& history_sys = m_interpreter.get_history_system ();
+
+    return history_sys.input_from_tmp_file ();
+  }
+
   void
   base_lexer::push_start_state (int state)
   {
@@ -3600,10 +3591,7 @@
   base_lexer::count_token_internal (int tok)
   {
     if (tok != '\n')
-      {
-        Vtoken_count++;
-        m_token_count++;
-      }
+      increment_token_count ();
 
     return show_token (tok);
   }
@@ -3611,10 +3599,11 @@
   int
   base_lexer::show_token (int tok)
   {
-    if (Vdisplay_tokens)
+
+    if (display_tokens ())
       display_token (tok);
 
-    if (lexer_debug_flag)
+    if (debug_flag ())
       {
         std::cerr << "R: ";
         display_token (tok);
--- a/libinterp/parse-tree/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -9,6 +9,7 @@
   %reldir%/parse.h \
   %reldir%/profiler.h \
   %reldir%/pt-all.h \
+  %reldir%/pt-anon-scopes.h \
   %reldir%/pt-arg-list.h \
   %reldir%/pt-array-list.h \
   %reldir%/pt-assign.h \
@@ -59,6 +60,7 @@
   %reldir%/oct-parse.h \
   %reldir%/oct-parse.yy \
   %reldir%/profiler.cc \
+  %reldir%/pt-anon-scopes.cc \
   %reldir%/pt-arg-list.cc \
   %reldir%/pt-array-list.cc \
   %reldir%/pt-assign.cc \
@@ -79,7 +81,6 @@
   %reldir%/pt-id.cc \
   %reldir%/pt-idx.cc \
   %reldir%/pt-jit.cc \
-  %reldir%/pt-jump.cc \
   %reldir%/pt-loop.cc \
   %reldir%/pt-mat.cc \
   %reldir%/pt-misc.cc \
@@ -105,9 +106,6 @@
 	mv $@-t $@ && \
 	rm -f $@-t1
 
-%reldir%/oct-parse.yy: %reldir%/oct-parse.in.yy
-	$(AM_V_GEN)$(call subst-bison-api-decls,octave_)
-
 noinst_LTLIBRARIES += \
   %reldir%/libparse-tree.la
 
@@ -117,15 +115,5 @@
   $(libinterp_liboctinterp_la_CPPFLAGS) \
   $(LLVM_CPPFLAGS)
 
-%canon_reldir%_libparse_tree_la_CFLAGS = \
-  $(AM_CFLAGS) \
-  $(WARN_CFLAGS)
-
-%canon_reldir%_libparse_tree_la_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS) \
-  $(LLVM_CXXFLAGS)
-
 libinterp_EXTRA_DIST += \
-  %reldir%/oct-parse.in.yy \
   %reldir%/octave.gperf
--- a/libinterp/parse-tree/oct-parse.in.yy	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5982 +0,0 @@
-/*
-
-Copyright (C) 1993-2018 John W. Eaton
-Copyright (C) 2009 David Grundberg
-Copyright (C) 2009-2010 VZLU Prague
-Copyright (C) 2016-2018 Oliver Heimlich
-
-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/>.
-
-*/
-
-// Parser for Octave.
-
-// C decarations.
-
-%{
-
-#define YYDEBUG 1
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include <cassert>
-#include <cstdio>
-#include <cstdlib>
-
-#include <iostream>
-#include <map>
-#include <sstream>
-
-#include "Matrix.h"
-#include "cmd-edit.h"
-#include "cmd-hist.h"
-#include "file-ops.h"
-#include "file-stat.h"
-#include "oct-env.h"
-#include "oct-time.h"
-#include "quit.h"
-
-#include "Cell.h"
-#include "builtin-defun-decls.h"
-#include "call-stack.h"
-#include "defaults.h"
-#include "defun.h"
-#include "dirfns.h"
-#include "dynamic-ld.h"
-#include "error.h"
-#include "input.h"
-#include "interpreter-private.h"
-#include "interpreter.h"
-#include "lex.h"
-#include "load-path.h"
-#include "oct-hist.h"
-#include "oct-map.h"
-#include "ov-classdef.h"
-#include "ov-fcn-handle.h"
-#include "ov-usr-fcn.h"
-#include "ov-null-mat.h"
-#include "pager.h"
-#include "parse.h"
-#include "pt-all.h"
-#include "pt-eval.h"
-#include "pt-funcall.h"
-#include "symtab.h"
-#include "token.h"
-#include "unwind-prot.h"
-#include "utils.h"
-#include "variables.h"
-
-// oct-parse.h must be included after pt-all.h
-#include "oct-parse.h"
-
-extern int octave_lex (YYSTYPE *, void *);
-
-// List of autoloads (function -> file mapping).
-static std::map<std::string, std::string> autoload_map;
-
-// Forward declarations for some functions defined at the bottom of
-// the file.
-
-static void yyerror (octave::base_parser& parser, const char *s);
-
-#define lexer parser.m_lexer
-#define scanner lexer.m_scanner
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-   // Disable this warning for code that is generated by Bison,
-   // including grammar rules.  Push the current state so we can
-   // restore the warning state prior to functions we define at
-   // the bottom of the file.
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-%}
-
-// Bison declarations.
-
-// The grammar currently has 9 shift/reduce conflicts.  Ensure that
-// we notice if that number changes.
-
-%expect 9
-
-%API_PREFIX_DECL%
-
-// We are using the pure parser interface and the reentrant lexer
-// interface but the Octave parser and lexer are NOT properly
-// reentrant because both still use many global variables.  It should be
-// safe to create a parser object and call it while another parser
-// object is active (to parse a callback function while the main
-// interactive parser is waiting for input, for example) if you take
-// care to properly save and restore (typically with an unwind_protect
-// object) relevant global values before and after the nested call.
-
-%define api.pure
-%PUSH_PULL_DECL%
-%parse-param { octave::base_parser& parser }
-%lex-param { void *lexer.scanner }
-
-%union
-{
-  int dummy_type;
-
-  // The type of the basic tokens returned by the lexer.
-  octave::token *tok_val;
-
-  // Comment strings that we need to deal with mid-rule.
-  octave::comment_list *comment_type;
-
-  // Types for the nonterminals we generate.
-  char punct_type;
-  octave::tree *tree_type;
-  octave::tree_matrix *tree_matrix_type;
-  octave::tree_cell *tree_cell_type;
-  octave::tree_expression *tree_expression_type;
-  octave::tree_constant *tree_constant_type;
-  octave::tree_fcn_handle *tree_fcn_handle_type;
-  octave::tree_funcall *tree_funcall_type;
-  octave::tree_function_def *tree_function_def_type;
-  octave::tree_anon_fcn_handle *tree_anon_fcn_handle_type;
-  octave::tree_identifier *tree_identifier_type;
-  octave::tree_index_expression *tree_index_expression_type;
-  octave::tree_colon_expression *tree_colon_expression_type;
-  octave::tree_argument_list *tree_argument_list_type;
-  octave::tree_parameter_list *tree_parameter_list_type;
-  octave::tree_command *tree_command_type;
-  octave::tree_if_command *tree_if_command_type;
-  octave::tree_if_clause *tree_if_clause_type;
-  octave::tree_if_command_list *tree_if_command_list_type;
-  octave::tree_switch_command *tree_switch_command_type;
-  octave::tree_switch_case *tree_switch_case_type;
-  octave::tree_switch_case_list *tree_switch_case_list_type;
-  octave::tree_decl_elt *tree_decl_elt_type;
-  octave::tree_decl_init_list *tree_decl_init_list_type;
-  octave::tree_decl_command *tree_decl_command_type;
-  octave::tree_statement *tree_statement_type;
-  octave::tree_statement_list *tree_statement_list_type;
-  octave_user_function *octave_user_function_type;
-
-  octave::tree_classdef *tree_classdef_type;
-  octave::tree_classdef_attribute* tree_classdef_attribute_type;
-  octave::tree_classdef_attribute_list* tree_classdef_attribute_list_type;
-  octave::tree_classdef_superclass* tree_classdef_superclass_type;
-  octave::tree_classdef_superclass_list* tree_classdef_superclass_list_type;
-  octave::tree_classdef_body* tree_classdef_body_type;
-  octave::tree_classdef_property* tree_classdef_property_type;
-  octave::tree_classdef_property_list* tree_classdef_property_list_type;
-  octave::tree_classdef_properties_block* tree_classdef_properties_block_type;
-  octave::tree_classdef_methods_list* tree_classdef_methods_list_type;
-  octave::tree_classdef_methods_block* tree_classdef_methods_block_type;
-  octave::tree_classdef_event* tree_classdef_event_type;
-  octave::tree_classdef_events_list* tree_classdef_events_list_type;
-  octave::tree_classdef_events_block* tree_classdef_events_block_type;
-  octave::tree_classdef_enum* tree_classdef_enum_type;
-  octave::tree_classdef_enum_list* tree_classdef_enum_list_type;
-  octave::tree_classdef_enum_block* tree_classdef_enum_block_type;
-}
-
-// Tokens with line and column information.
-%token <tok_val> '=' ':' '-' '+' '*' '/'
-%token <tok_val> ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ
-%token <tok_val> EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ AND_EQ OR_EQ
-%token <tok_val> EXPR_AND_AND EXPR_OR_OR
-%token <tok_val> EXPR_AND EXPR_OR EXPR_NOT
-%token <tok_val> EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT
-%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> 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> IF ELSEIF ELSE
-%token <tok_val> SWITCH CASE OTHERWISE
-%token <tok_val> BREAK CONTINUE FUNC_RET
-%token <tok_val> UNWIND CLEANUP
-%token <tok_val> TRY CATCH
-%token <tok_val> GLOBAL PERSISTENT
-%token <tok_val> FCN_HANDLE
-%token <tok_val> CLASSDEF
-%token <tok_val> PROPERTIES METHODS EVENTS ENUMERATION
-%token <tok_val> METAQUERY
-%token <tok_val> SUPERCLASSREF
-%token <tok_val> FQ_IDENT
-%token <tok_val> GET SET
-%token <tok_val> FCN
-%token <tok_val> LEXICAL_ERROR
-
-// Other tokens.
-%token<dummy_type> END_OF_INPUT
-%token<dummy_type> INPUT_FILE
-// %token VARARGIN VARARGOUT
-
-%token<dummy_type> '(' ')' '[' ']' '{' '}' '.' ',' ';' '@' '\n'
-
-// Nonterminals we construct.
-%type <dummy_type> indirect_ref_op decl_param_init
-%type <dummy_type> push_fcn_symtab push_script_symtab begin_file
-%type <dummy_type> param_list_beg param_list_end stmt_begin parse_error
-%type <dummy_type> parsing_local_fcns
-%type <comment_type> stash_comment
-%type <tok_val> function_beg classdef_beg
-%type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep
-%type <tree_type> input
-%type <tree_constant_type> string constant magic_colon
-%type <tree_anon_fcn_handle_type> anon_fcn_handle
-%type <tree_fcn_handle_type> fcn_handle
-%type <tree_matrix_type> matrix_rows
-%type <tree_cell_type> cell_rows
-%type <tree_expression_type> matrix cell
-%type <tree_expression_type> primary_expr oper_expr power_expr expr_no_assign
-%type <tree_expression_type> simple_expr colon_expr assign_expr expression
-%type <tree_identifier_type> identifier fcn_name magic_tilde
-%type <tree_funcall_type> superclass_identifier meta_identifier
-%type <tree_index_expression_type> word_list_cmd
-%type <tree_argument_list_type> arg_list word_list assign_lhs
-%type <tree_argument_list_type> cell_or_matrix_row
-%type <tree_parameter_list_type> opt_param_list param_list
-%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_function_def_type> function
-%type <tree_classdef_type> classdef
-%type <tree_command_type> file
-%type <tree_if_command_type> if_command
-%type <tree_if_clause_type> elseif_clause else_clause
-%type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
-%type <tree_switch_command_type> switch_command
-%type <tree_switch_case_type> switch_case default_case
-%type <tree_switch_case_list_type> case_list1 case_list
-%type <tree_decl_elt_type> decl2 param_list_elt
-%type <tree_decl_init_list_type> decl1
-%type <tree_decl_command_type> declaration
-%type <tree_statement_type> statement function_end
-%type <tree_statement_list_type> simple_list simple_list1 list list1
-%type <tree_statement_list_type> opt_list
-%type <tree_statement_list_type> opt_fcn_list fcn_list fcn_list1
-%type <tree_classdef_attribute_type> attr
-%type <tree_classdef_attribute_list_type> attr_list opt_attr_list
-%type <tree_classdef_superclass_type> superclass
-%type <tree_classdef_superclass_list_type> superclass_list opt_superclass_list
-%type <tree_classdef_body_type> class_body
-%type <tree_classdef_property_type> class_property
-%type <tree_classdef_property_list_type> property_list
-%type <tree_classdef_properties_block_type> properties_block
-%type <tree_classdef_methods_list_type> methods_list
-%type <tree_classdef_methods_block_type> methods_block
-%type <tree_classdef_event_type> class_event
-%type <tree_classdef_events_list_type> events_list
-%type <tree_classdef_events_block_type> events_block
-%type <tree_classdef_enum_type> class_enum
-%type <tree_classdef_enum_list_type> enum_list
-%type <tree_classdef_enum_block_type> enum_block
-%type <tree_function_def_type> method_decl method
-%type <octave_user_function_type> method_decl1
-
-// Precedence and associativity.
-%right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ
-%left EXPR_OR_OR
-%left EXPR_AND_AND
-%left EXPR_OR
-%left EXPR_AND
-%left EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT
-%left ':'
-%left '-' '+' EPLUS EMINUS
-%left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV
-%right UNARY EXPR_NOT
-%left POW EPOW HERMITIAN TRANSPOSE
-%right PLUS_PLUS MINUS_MINUS
-%left '(' '.' '{'
-
-// How to clean up if there is a parse error.  We handle deleting tokens
-// and comments seperately and separators are just characters.  The
-// remaining items are dynamically allocated parse tree objects that
-// must be deleted.  Use the wildcard case (<*>) to detect unhandled
-// cases (for example, a new semantic type is added but not handled
-// here).
-
-%destructor { } <tok_val>
-%destructor { } <punct_type>
-%destructor { } <comment_type>
-%destructor { } <>
-
-%destructor { delete $$; } <tree_type>
-%destructor { delete $$; } <tree_matrix_type>
-%destructor { delete $$; } <tree_cell_type>
-%destructor { delete $$; } <tree_expression_type>
-%destructor { delete $$; } <tree_constant_type>
-%destructor { delete $$; } <tree_fcn_handle_type>
-%destructor { delete $$; } <tree_funcall_type>
-%destructor { delete $$; } <tree_function_def_type>
-%destructor { delete $$; } <tree_anon_fcn_handle_type>
-%destructor { delete $$; } <tree_identifier_type>
-%destructor { delete $$; } <tree_index_expression_type>
-%destructor { delete $$; } <tree_argument_list_type>
-%destructor { delete $$; } <tree_parameter_list_type>
-%destructor { delete $$; } <tree_command_type>
-%destructor { delete $$; } <tree_if_command_type>
-%destructor { delete $$; } <tree_if_clause_type>
-%destructor { delete $$; } <tree_if_command_list_type>
-%destructor { delete $$; } <tree_switch_command_type>
-%destructor { delete $$; } <tree_switch_case_type>
-%destructor { delete $$; } <tree_switch_case_list_type>
-%destructor { delete $$; } <tree_decl_elt_type>
-%destructor { delete $$; } <tree_decl_init_list_type>
-%destructor { delete $$; } <tree_decl_command_type>
-%destructor { delete $$; } <tree_statement_type>
-%destructor { delete $$; } <tree_statement_list_type>
-%destructor { delete $$; } <octave_user_function_type>
-
-%destructor { delete $$; } <tree_classdef_type>
-%destructor { delete $$; } <tree_classdef_attribute_type>
-%destructor { delete $$; } <tree_classdef_attribute_list_type>
-%destructor { delete $$; } <tree_classdef_superclass_type>
-%destructor { delete $$; } <tree_classdef_superclass_list_type>
-%destructor { delete $$; } <tree_classdef_body_type>
-%destructor { delete $$; } <tree_classdef_property_type>
-%destructor { delete $$; } <tree_classdef_property_list_type>
-%destructor { delete $$; } <tree_classdef_properties_block_type>
-%destructor { delete $$; } <tree_classdef_methods_list_type>
-%destructor { delete $$; } <tree_classdef_methods_block_type>
-%destructor { delete $$; } <tree_classdef_event_type>
-%destructor { delete $$; } <tree_classdef_events_list_type>
-%destructor { delete $$; } <tree_classdef_events_block_type>
-%destructor { delete $$; } <tree_classdef_enum_type>
-%destructor { delete $$; } <tree_classdef_enum_list_type>
-%destructor { delete $$; } <tree_classdef_enum_block_type>
-
-// Defining a generic destructor generates a warning if destructors are
-// already explicitly declared for all types.
-//
-// %destructor {
-//    warning_with_id
-//      ("Octave:parser-destructor",
-//       "possible memory leak in cleanup following parse error");
-// } <*>
-
-// Where to start.
-%start input
-
-%%
-
-// ==============================
-// Statements and statement lists
-// ==============================
-
-input           : simple_list '\n'
-                  {
-                    $$ = nullptr;
-                    parser.m_stmt_list = $1;
-                    YYACCEPT;
-                  }
-                | simple_list END_OF_INPUT
-                  {
-                    $$ = nullptr;
-                    lexer.m_end_of_input = true;
-                    parser.m_stmt_list = $1;
-                    YYACCEPT;
-                  }
-                | parse_error
-                  {
-                    $$ = nullptr;
-                    YYABORT;
-                  }
-                ;
-
-simple_list     : opt_sep_no_nl
-                  {
-                    YYUSE ($1);
-
-                    $$ = nullptr;
-                  }
-                | simple_list1 opt_sep_no_nl
-                  { $$ = parser.set_stmt_print_flag ($1, $2, false); }
-                ;
-
-simple_list1    : statement
-                  { $$ = parser.make_statement_list ($1); }
-                | simple_list1 sep_no_nl statement
-                  { $$ = parser.append_statement_list ($1, $2, $3, false); }
-                ;
-
-opt_list        : // empty
-                  { $$ = new octave::tree_statement_list (); }
-                | list
-                  { $$ = $1; }
-                ;
-
-list            : list1 opt_sep
-                  { $$ = parser.set_stmt_print_flag ($1, $2, true); }
-                ;
-
-list1           : statement
-                  { $$ = parser.make_statement_list ($1); }
-                | list1 sep statement
-                  { $$ = parser.append_statement_list ($1, $2, $3, true); }
-                ;
-
-opt_fcn_list    : // empty
-                  { $$ = new octave::tree_statement_list (); }
-                | fcn_list
-                  { $$ = $1; }
-                ;
-
-fcn_list        : fcn_list1 opt_sep
-                  {
-                    YYUSE ($2);
-
-                    $$ = $1;
-                  }
-                ;
-
-fcn_list1       : function
-                  {
-                    octave::tree_statement *stmt = parser.make_statement ($1);
-                    $$ = new octave::tree_statement_list (stmt);
-                  }
-                | fcn_list1 opt_sep function
-                  {
-                    octave::tree_statement *stmt = parser.make_statement ($3);
-                    $$ = parser.append_statement_list ($1, $2, stmt, false);
-                  }
-                ;
-
-statement       : expression
-                  { $$ = parser.make_statement ($1); }
-                | command
-                  { $$ = parser.make_statement ($1); }
-                | word_list_cmd
-                  { $$ = parser.make_statement ($1); }
-                ;
-
-// =================
-// Word-list command
-// =================
-
-// These are not really like expressions since they can't appear on
-// the RHS of an assignment.  But they are also not like commands (IF,
-// WHILE, etc.
-
-word_list_cmd   : identifier word_list
-                  {
-                    $$ = parser.make_index_expression ($1, $2, '(');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1 and $2.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-word_list       : string
-                  { $$ = new octave::tree_argument_list ($1); }
-                | word_list string
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-// ===========
-// Expressions
-// ===========
-
-identifier      : NAME
-                  {
-                    octave::symbol_record sr = $1->sym_rec ();
-                    $$ = new octave::tree_identifier (sr, $1->line (), $1->column ());
-                  }
-                ;
-
-superclass_identifier
-                : SUPERCLASSREF
-                  {
-                    std::string method_nm = $1->superclass_method_name ();
-                    std::string class_nm = $1->superclass_class_name ();
-
-                    $$ = parser.make_superclass_ref (method_nm, class_nm);
-                  }
-                ;
-
-meta_identifier : METAQUERY
-                  {
-                    std::string class_nm = $1->text ();
-
-                    $$ = parser.make_meta_class_query (class_nm);
-                  }
-                ;
-
-string          : DQ_STRING
-                  { $$ = parser.make_constant (DQ_STRING, $1); }
-                | SQ_STRING
-                  { $$ = parser.make_constant (SQ_STRING, $1); }
-                ;
-
-constant        : NUM
-                  { $$ = parser.make_constant (NUM, $1); }
-                | IMAG_NUM
-                  { $$ = parser.make_constant (IMAG_NUM, $1); }
-                | string
-                  { $$ = $1; }
-                ;
-
-matrix          : '[' matrix_rows ']'
-                  { $$ = parser.finish_matrix ($2); }
-                ;
-
-matrix_rows     : cell_or_matrix_row
-                  { $$ = $1 ? new octave::tree_matrix ($1) : nullptr; }
-                | matrix_rows ';' cell_or_matrix_row
-                  {
-                    if ($1)
-                      {
-                        if ($3)
-                          $1->append ($3);
-
-                        $$ = $1;
-                      }
-                    else
-                      $$ = $3 ? new octave::tree_matrix ($3) : nullptr;
-                  }
-                ;
-
-cell            : '{' cell_rows '}'
-                  { $$ = parser.finish_cell ($2); }
-                ;
-
-cell_rows       : cell_or_matrix_row
-                  { $$ = $1 ? new octave::tree_cell ($1) : nullptr; }
-                | cell_rows ';' cell_or_matrix_row
-                  {
-                    if ($1)
-                      {
-                        if ($3)
-                          $1->append ($3);
-
-                        $$ = $1;
-                      }
-                    else
-                      $$ = $3 ? new octave::tree_cell ($3) : nullptr;
-                  }
-                ;
-
-// tree_argument_list objects can't be empty or have leading or trailing
-// commas, but those are all allowed in matrix and cell array rows.
-
-cell_or_matrix_row
-                : // empty
-                  { $$ = nullptr; }
-                | ','
-                  { $$ = nullptr; }
-                | arg_list
-                  { $$ = $1; }
-                | arg_list ','
-                  { $$ = $1; }
-                | ',' arg_list
-                  { $$ = $2; }
-                | ',' arg_list ','
-                  { $$ = $2; }
-                ;
-
-fcn_handle      : '@' FCN_HANDLE
-                  {
-                    $$ = parser.make_fcn_handle ($2);
-                    lexer.m_looking_at_function_handle--;
-                  }
-                ;
-
-anon_fcn_handle : '@' param_list stmt_begin expr_no_assign
-                  {
-                    $$ = parser.make_anon_fcn_handle ($2, $4);
-                    lexer.m_nesting_level.remove ();
-                  }
-                | '@' param_list stmt_begin error
-                  {
-                    YYUSE ($2);
-
-                    $$ = nullptr;
-                    parser.bison_error ("anonymous function bodies must be single expressions");
-                    YYABORT;
-                  }
-                ;
-
-primary_expr    : identifier
-                  { $$ = $1; }
-                | constant
-                  { $$ = $1; }
-                | fcn_handle
-                  { $$ = $1; }
-                | matrix
-                  {
-                    lexer.m_looking_at_matrix_or_assign_lhs = false;
-                    $$ = $1;
-                  }
-                | cell
-                  { $$ = $1; }
-                | meta_identifier
-                  { $$ = $1; }
-                | superclass_identifier
-                  { $$ = $1; }
-                | '(' expression ')'
-                  { $$ = $2->mark_in_parens (); }
-                ;
-
-magic_colon     : ':'
-                  {
-                    YYUSE ($1);
-
-                    octave_value tmp (octave_value::magic_colon_t);
-                    $$ = new octave::tree_constant (tmp);
-                  }
-                ;
-
-magic_tilde     : EXPR_NOT
-                  {
-                    YYUSE ($1);
-
-                    $$ = new octave::tree_black_hole ();
-                  }
-                ;
-
-arg_list        : expression
-                  { $$ = new octave::tree_argument_list ($1); }
-                | magic_colon
-                  { $$ = new octave::tree_argument_list ($1); }
-                | magic_tilde
-                  { $$ = new octave::tree_argument_list ($1); }
-                | arg_list ',' magic_colon
-                  {
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                | arg_list ',' magic_tilde
-                  {
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                | arg_list ',' expression
-                  {
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-indirect_ref_op : '.'
-                  {
-                    $$ = 0;
-                    lexer.m_looking_at_indirect_ref = true;
-                  }
-                ;
-
-oper_expr       : primary_expr
-                  { $$ = $1; }
-                | oper_expr PLUS_PLUS
-                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
-                | oper_expr MINUS_MINUS
-                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
-                | oper_expr '(' ')'
-                  {
-                    $$ = parser.make_index_expression ($1, nullptr, '(');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1.
-                        YYABORT;
-                      }
-                  }
-                | oper_expr '(' arg_list ')'
-                  {
-                    $$ = parser.make_index_expression ($1, $3, '(');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1 and $3.
-                        YYABORT;
-                      }
-                  }
-                | oper_expr '{' '}'
-                  {
-                    $$ = parser.make_index_expression ($1, nullptr, '{');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1.
-                        YYABORT;
-                      }
-                  }
-                | oper_expr '{' arg_list '}'
-                  {
-                    $$ = parser.make_index_expression ($1, $3, '{');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1 and $3.
-                        YYABORT;
-                      }
-                  }
-                | oper_expr HERMITIAN
-                  { $$ = parser.make_postfix_op (HERMITIAN, $1, $2); }
-                | oper_expr TRANSPOSE
-                  { $$ = parser.make_postfix_op (TRANSPOSE, $1, $2); }
-                | oper_expr indirect_ref_op STRUCT_ELT
-                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
-                | oper_expr indirect_ref_op '(' expression ')'
-                  { $$ = parser.make_indirect_ref ($1, $4); }
-                | PLUS_PLUS oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
-                | MINUS_MINUS oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
-                | EXPR_NOT oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); }
-                | '+' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('+', $2, $1); }
-                | '-' oper_expr %prec UNARY
-                  { $$ = parser.make_prefix_op ('-', $2, $1); }
-                | oper_expr POW power_expr
-                  { $$ = parser.make_binary_op (POW, $1, $2, $3); }
-                | oper_expr EPOW power_expr
-                  { $$ = parser.make_binary_op (EPOW, $1, $2, $3); }
-                | oper_expr '+' oper_expr
-                  { $$ = parser.make_binary_op ('+', $1, $2, $3); }
-                | oper_expr '-' oper_expr
-                  { $$ = parser.make_binary_op ('-', $1, $2, $3); }
-                | oper_expr '*' oper_expr
-                  { $$ = parser.make_binary_op ('*', $1, $2, $3); }
-                | oper_expr '/' oper_expr
-                  { $$ = parser.make_binary_op ('/', $1, $2, $3); }
-                | oper_expr EPLUS oper_expr
-                  { $$ = parser.make_binary_op ('+', $1, $2, $3); }
-                | oper_expr EMINUS oper_expr
-                  { $$ = parser.make_binary_op ('-', $1, $2, $3); }
-                | oper_expr EMUL oper_expr
-                  { $$ = parser.make_binary_op (EMUL, $1, $2, $3); }
-                | oper_expr EDIV oper_expr
-                  { $$ = parser.make_binary_op (EDIV, $1, $2, $3); }
-                | oper_expr LEFTDIV oper_expr
-                  { $$ = parser.make_binary_op (LEFTDIV, $1, $2, $3); }
-                | oper_expr ELEFTDIV oper_expr
-                  { $$ = parser.make_binary_op (ELEFTDIV, $1, $2, $3); }
-                ;
-
-power_expr      : primary_expr
-                  { $$ = $1; }
-                | power_expr PLUS_PLUS
-                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
-                | power_expr MINUS_MINUS
-                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
-                | power_expr '(' ')'
-                  {
-                    $$ = parser.make_index_expression ($1, nullptr, '(');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1.
-                        YYABORT;
-                      }
-                  }
-                | power_expr '(' arg_list ')'
-                  {
-                    $$ = parser.make_index_expression ($1, $3, '(');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1 and $3.
-                        YYABORT;
-                      }
-                  }
-                | power_expr '{' '}'
-                  {
-                    $$ = parser.make_index_expression ($1, nullptr, '{');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1.
-                        YYABORT;
-                      }
-                  }
-                | power_expr '{' arg_list '}'
-                  {
-                    $$ = parser.make_index_expression ($1, $3, '{');
-                    if (! $$)
-                      {
-                        // make_index_expression deleted $1 and $3.
-                        YYABORT;
-                      }
-                  }
-                | power_expr indirect_ref_op STRUCT_ELT
-                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
-                | power_expr indirect_ref_op '(' expression ')'
-                  { $$ = parser.make_indirect_ref ($1, $4); }
-                | PLUS_PLUS power_expr %prec POW
-                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
-                | MINUS_MINUS power_expr %prec POW
-                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
-                | EXPR_NOT power_expr %prec POW
-                  { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); }
-                | '+' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('+', $2, $1); }
-                | '-' power_expr %prec POW
-                  { $$ = parser.make_prefix_op ('-', $2, $1); }
-                ;
-
-colon_expr      : oper_expr ':' oper_expr
-                  {
-                    YYUSE ($2);
-
-                    $$ = parser.make_colon_expression ($1, $3);
-
-                    if (! $$)
-                      {
-                        // finish_colon_expression deleted $1 and $3.
-                        YYABORT;
-                      }
-                  }
-                | oper_expr ':' oper_expr ':' oper_expr
-                  {
-                    YYUSE ($2);
-                    YYUSE ($4);
-
-                    $$ = parser.make_colon_expression ($1, $5, $3);
-
-                    if (! $$)
-                      {
-                        // finish_colon_expression deleted $1, $3, and $5.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-simple_expr     : oper_expr
-                  { $$ = $1; }
-                | colon_expr
-                  { $$ = $1; }
-                | simple_expr EXPR_LT simple_expr
-                  { $$ = parser.make_binary_op (EXPR_LT, $1, $2, $3); }
-                | simple_expr EXPR_LE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_LE, $1, $2, $3); }
-                | simple_expr EXPR_EQ simple_expr
-                  { $$ = parser.make_binary_op (EXPR_EQ, $1, $2, $3); }
-                | simple_expr EXPR_GE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_GE, $1, $2, $3); }
-                | simple_expr EXPR_GT simple_expr
-                  { $$ = parser.make_binary_op (EXPR_GT, $1, $2, $3); }
-                | simple_expr EXPR_NE simple_expr
-                  { $$ = parser.make_binary_op (EXPR_NE, $1, $2, $3); }
-                | simple_expr EXPR_AND simple_expr
-                  { $$ = parser.make_binary_op (EXPR_AND, $1, $2, $3); }
-                | simple_expr EXPR_OR simple_expr
-                  { $$ = parser.make_binary_op (EXPR_OR, $1, $2, $3); }
-                | simple_expr EXPR_AND_AND simple_expr
-                  { $$ = parser.make_boolean_op (EXPR_AND_AND, $1, $2, $3); }
-                | simple_expr EXPR_OR_OR simple_expr
-                  { $$ = parser.make_boolean_op (EXPR_OR_OR, $1, $2, $3); }
-                ;
-
-assign_lhs      : simple_expr
-                  {
-                    $$ = parser.validate_matrix_for_assignment ($1);
-
-                    if ($$)
-                      { lexer.m_looking_at_matrix_or_assign_lhs = false; }
-                    else
-                      {
-                        // validate_matrix_for_assignment deleted $1.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-assign_expr     : assign_lhs '=' expression
-                  { $$ = parser.make_assign_op ('=', $1, $2, $3); }
-                | assign_lhs ADD_EQ expression
-                  { $$ = parser.make_assign_op (ADD_EQ, $1, $2, $3); }
-                | assign_lhs SUB_EQ expression
-                  { $$ = parser.make_assign_op (SUB_EQ, $1, $2, $3); }
-                | assign_lhs MUL_EQ expression
-                  { $$ = parser.make_assign_op (MUL_EQ, $1, $2, $3); }
-                | assign_lhs DIV_EQ expression
-                  { $$ = parser.make_assign_op (DIV_EQ, $1, $2, $3); }
-                | assign_lhs LEFTDIV_EQ expression
-                  { $$ = parser.make_assign_op (LEFTDIV_EQ, $1, $2, $3); }
-                | assign_lhs POW_EQ expression
-                  { $$ = parser.make_assign_op (POW_EQ, $1, $2, $3); }
-                | assign_lhs EMUL_EQ expression
-                  { $$ = parser.make_assign_op (EMUL_EQ, $1, $2, $3); }
-                | assign_lhs EDIV_EQ expression
-                  { $$ = parser.make_assign_op (EDIV_EQ, $1, $2, $3); }
-                | assign_lhs ELEFTDIV_EQ expression
-                  { $$ = parser.make_assign_op (ELEFTDIV_EQ, $1, $2, $3); }
-                | assign_lhs EPOW_EQ expression
-                  { $$ = parser.make_assign_op (EPOW_EQ, $1, $2, $3); }
-                | assign_lhs AND_EQ expression
-                  { $$ = parser.make_assign_op (AND_EQ, $1, $2, $3); }
-                | assign_lhs OR_EQ expression
-                  { $$ = parser.make_assign_op (OR_EQ, $1, $2, $3); }
-                ;
-
-expr_no_assign  : simple_expr
-                  {
-                    if ($1 && ($1->is_matrix () || $1->iscell ()))
-                      {
-                        if (parser.validate_array_list ($1))
-                          $$ = $1;
-                        else
-                          {
-                            delete $1;
-                            YYABORT;
-                          }
-                      }
-                    else
-                      $$ = $1;
-                  }
-                | anon_fcn_handle
-                  { $$ = $1; }
-                ;
-
-expression      : expr_no_assign
-                  { $$ = $1; }
-                | assign_expr
-                  {
-                    if (! $1)
-                      YYABORT;
-
-                    $$ = $1;
-                  }
-
-// ================================================
-// Commands, declarations, and function definitions
-// ================================================
-
-command         : declaration
-                  { $$ = $1; }
-                | select_command
-                  { $$ = $1; }
-                | loop_command
-                  { $$ = $1; }
-                | jump_command
-                  { $$ = $1; }
-                | except_command
-                  { $$ = $1; }
-                | function
-                  { $$ = $1; }
-                | file
-                  { $$ = $1; }
-                ;
-
-// =====================
-// Declaration statemnts
-// =====================
-
-declaration     : GLOBAL decl1
-                  {
-                    $$ = parser.make_decl_command (GLOBAL, $1, $2);
-                    lexer.m_looking_at_decl_list = false;
-                  }
-                | PERSISTENT decl1
-                  {
-                    $$ = parser.make_decl_command (PERSISTENT, $1, $2);
-                    lexer.m_looking_at_decl_list = false;
-                  }
-                ;
-
-decl1           : decl2
-                  { $$ = new octave::tree_decl_init_list ($1); }
-                | decl1 decl2
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-decl_param_init : // empty
-                  {
-                    $$ = 0;
-                    lexer.m_looking_at_initializer_expression = true;
-                  }
-
-decl2           : identifier
-                  { $$ = new octave::tree_decl_elt ($1); }
-                | identifier '=' decl_param_init expression
-                  {
-                    YYUSE ($2);
-
-                    lexer.m_looking_at_initializer_expression = false;
-                    $$ = new octave::tree_decl_elt ($1, $4);
-                  }
-                ;
-
-// ====================
-// Selection statements
-// ====================
-
-select_command  : if_command
-                  { $$ = $1; }
-                | switch_command
-                  { $$ = $1; }
-                ;
-
-// ============
-// If statement
-// ============
-
-if_command      : IF stash_comment if_cmd_list END
-                  {
-                    if (! ($$ = parser.finish_if_command ($1, $3, $4, $2)))
-                      {
-                        // finish_if_command deleted $3.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-if_cmd_list     : if_cmd_list1
-                  { $$ = $1; }
-                | if_cmd_list1 else_clause
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-if_cmd_list1    : expression stmt_begin opt_sep opt_list
-                  {
-                    YYUSE ($3);
-
-                    $1->mark_braindead_shortcircuit ();
-
-                    $$ = parser.start_if_command ($1, $4);
-                  }
-                | if_cmd_list1 elseif_clause
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-elseif_clause   : ELSEIF stash_comment opt_sep expression stmt_begin opt_sep opt_list
-                  {
-                    YYUSE ($3);
-                    YYUSE ($6);
-
-                    $4->mark_braindead_shortcircuit ();
-
-                    $$ = parser.make_elseif_clause ($1, $4, $7, $2);
-                  }
-                ;
-
-else_clause     : ELSE stash_comment opt_sep opt_list
-                  {
-                    YYUSE ($1);
-                    YYUSE ($3);
-
-                    $$ = new octave::tree_if_clause ($4, $2);
-                  }
-                ;
-
-// ================
-// Switch statement
-// ================
-
-switch_command  : SWITCH stash_comment expression opt_sep case_list END
-                  {
-                    YYUSE ($4);
-
-                    if (! ($$ = parser.finish_switch_command ($1, $3, $5, $6, $2)))
-                      {
-                        // finish_switch_command deleted $3 adn $5.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-case_list       : // empty
-                  { $$ = new octave::tree_switch_case_list (); }
-                | default_case
-                  { $$ = new octave::tree_switch_case_list ($1); }
-                | case_list1
-                  { $$ = $1; }
-                | case_list1 default_case
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-case_list1      : switch_case
-                  { $$ = new octave::tree_switch_case_list ($1); }
-                | case_list1 switch_case
-                  {
-                    $1->append ($2);
-                    $$ = $1;
-                  }
-                ;
-
-switch_case     : CASE stash_comment opt_sep expression stmt_begin opt_sep opt_list
-                  {
-                    YYUSE ($3);
-                    YYUSE ($6);
-
-                    $$ = parser.make_switch_case ($1, $4, $7, $2);
-                  }
-                ;
-
-default_case    : OTHERWISE stash_comment opt_sep opt_list
-                  {
-                    YYUSE ($1);
-                    YYUSE ($3);
-
-                    $$ = new octave::tree_switch_case ($4, $2);
-                  }
-                ;
-
-// =======
-// Looping
-// =======
-
-loop_command    : WHILE stash_comment expression stmt_begin opt_sep opt_list END
-                  {
-                    YYUSE ($5);
-
-                    $3->mark_braindead_shortcircuit ();
-
-                    if (! ($$ = parser.make_while_command ($1, $3, $6, $7, $2)))
-                      {
-                        // make_while_command deleted $3 and $6.
-                        YYABORT;
-                      }
-                  }
-                | DO stash_comment opt_sep opt_list UNTIL expression
-                  {
-                    YYUSE ($1);
-                    YYUSE ($3);
-
-                    $$ = parser.make_do_until_command ($5, $4, $6, $2);
-                  }
-                | FOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($7);
-
-                    if (! ($$ = parser.make_for_command (FOR, $1, $3, $5,
-                                                         nullptr, $8, $9, $2)))
-                      {
-                        // make_for_command deleted $3, $5, and $8.
-                        YYABORT;
-                      }
-                  }
-                | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END
-                  {
-                    YYUSE ($5);
-                    YYUSE ($8);
-
-                    if (! ($$ = parser.make_for_command (FOR, $1, $4, $6,
-                                                         nullptr, $9, $10, $2)))
-                      {
-                        // make_for_command deleted $4, $6, and $9.
-                        YYABORT;
-                      }
-                  }
-                | PARFOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($7);
-
-                    if (! ($$ = parser.make_for_command (PARFOR, $1, $3, $5,
-                                                         nullptr, $8, $9, $2)))
-                      {
-                        // make_for_command deleted $3, $5, and $8.
-                        YYABORT;
-                      }
-                  }
-                | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END
-                  {
-                    YYUSE ($5);
-                    YYUSE ($10);
-
-                    if (! ($$ = parser.make_for_command (PARFOR, $1, $4, $6,
-                                                         $8, $11, $12, $2)))
-                      {
-                        // make_for_command deleted $4, $6, $8, and $11.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-// =======
-// Jumping
-// =======
-
-jump_command    : BREAK
-                  {
-                    if (! ($$ = parser.make_break_command ($1)))
-                      YYABORT;
-                  }
-                | CONTINUE
-                  { $$ = parser.make_continue_command ($1); }
-                | FUNC_RET
-                  { $$ = parser.make_return_command ($1); }
-                ;
-
-// ==========
-// Exceptions
-// ==========
-
-except_command  : UNWIND stash_comment opt_sep opt_list CLEANUP
-                  stash_comment opt_sep opt_list END
-                  {
-                    YYUSE ($3);
-                    YYUSE ($5);
-                    YYUSE ($7);
-
-                    if (! ($$ = parser.make_unwind_command ($1, $4, $8, $9, $2, $6)))
-                      {
-                        // make_unwind_command deleted $4 and $8.
-                        YYABORT;
-                      }
-                  }
-                | TRY stash_comment opt_sep opt_list CATCH stash_comment
-                  opt_sep opt_list END
-                  {
-                    YYUSE ($3);
-                    YYUSE ($5);
-                    YYUSE ($7);
-
-                    if (! ($$ = parser.make_try_command ($1, $4, $7, $8, $9, $2, $6)))
-                      {
-                        // make_try_command deleted $4 and $8.
-                        YYABORT;
-                      }
-                  }
-                | TRY stash_comment opt_sep opt_list END
-                  {
-                    YYUSE ($3);
-
-                    if (! ($$ = parser.make_try_command ($1, $4, 0, nullptr,
-                                                         $5, $2, nullptr)))
-                      {
-                        // make_try_command deleted $4.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-// ===========================================
-// Some 'subroutines' for function definitions
-// ===========================================
-
-push_fcn_symtab : // empty
-                  {
-                    $$ = 0;
-
-                    parser.m_curr_fcn_depth++;
-
-                    if (parser.m_max_fcn_depth < parser.m_curr_fcn_depth)
-                      parser.m_max_fcn_depth = parser.m_curr_fcn_depth;
-
-                    // Will get a real name later.
-                    lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_fcn_symtab"));
-                    parser.m_function_scopes.push (lexer.m_symtab_context.curr_scope ());
-
-                    if (! lexer.m_reading_script_file
-                        && parser.m_curr_fcn_depth == 1
-                        && ! parser.m_parsing_subfunctions)
-                      parser.m_primary_fcn_scope
-                        = lexer.m_symtab_context.curr_scope ();
-
-                    if (lexer.m_reading_script_file
-                        && parser.m_curr_fcn_depth > 1)
-                      {
-                        parser.bison_error ("nested functions not implemented in this context");
-                        YYABORT;
-                      }
-                  }
-                ;
-
-// ===========================
-// List of function parameters
-// ===========================
-
-param_list_beg  : '('
-                  {
-                    $$ = 0;
-                    lexer.m_looking_at_parameter_list = true;
-
-                    if (lexer.m_looking_at_function_handle)
-                      {
-                        // Will get a real name later.
-                        lexer.m_symtab_context.push (octave::symbol_scope ("parser:param_lsit_beg"));
-                        lexer.m_looking_at_function_handle--;
-                        lexer.m_looking_at_anon_fcn_args = true;
-                      }
-                  }
-                ;
-
-param_list_end  : ')'
-                  {
-                    $$ = 0;
-                    lexer.m_looking_at_parameter_list = false;
-                    lexer.m_looking_for_object_index = false;
-                  }
-                ;
-
-opt_param_list  : // empty
-                  { $$ = nullptr; }
-                | param_list
-                  { $$ = $1; }
-                ;
-
-param_list      : param_list_beg param_list1 param_list_end
-                  {
-                    if ($2)
-                      lexer.mark_as_variables ($2->variable_names ());
-
-                    $$ = $2;
-                  }
-                | param_list_beg error
-                  {
-                    $$ = nullptr;
-                    parser.bison_error ("invalid parameter list");
-                    YYABORT;
-                  }
-                ;
-
-param_list1     : // empty
-                  { $$ = nullptr; }
-                | param_list2
-                  {
-                    $1->mark_as_formal_parameters ();
-
-                    if (parser.validate_param_list ($1, octave::tree_parameter_list::in))
-                      {
-                        lexer.mark_as_variables ($1->variable_names ());
-                        $$ = $1;
-                      }
-                    else
-                      {
-                        delete $1;
-                        YYABORT;
-                      }
-                  }
-                ;
-
-param_list2     : param_list_elt
-                  { $$ = new octave::tree_parameter_list ($1); }
-                | param_list2 ',' param_list_elt
-                  {
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-param_list_elt  : decl2
-                  { $$ = $1; }
-                | magic_tilde
-                  { $$ = new octave::tree_decl_elt ($1); }
-                ;
-
-// ===================================
-// List of function return value names
-// ===================================
-
-return_list     : '[' ']'
-                  {
-                    lexer.m_looking_at_return_list = false;
-
-                    $$ = new octave::tree_parameter_list ();
-                  }
-                | identifier
-                  {
-                    lexer.m_looking_at_return_list = false;
-
-                    octave::tree_parameter_list *tmp = new octave::tree_parameter_list ($1);
-
-                    // Even though this parameter list can contain only
-                    // a single identifier, we still need to validate it
-                    // to check for varargin or varargout.
-
-                    if (parser.validate_param_list (tmp, octave::tree_parameter_list::out))
-                      $$ = tmp;
-                    else
-                      {
-                        delete tmp;
-                        YYABORT;
-                      }
-                  }
-                | '[' return_list1 ']'
-                  {
-                    lexer.m_looking_at_return_list = false;
-
-                    // Check for duplicate parameter names, varargin,
-                    // or varargout.
-
-                    if (parser.validate_param_list ($2, octave::tree_parameter_list::out))
-                      $$ = $2;
-                    else
-                      {
-                        delete $2;
-                        YYABORT;
-                      }
-                  }
-                ;
-
-return_list1    : identifier
-                  { $$ = new octave::tree_parameter_list (new octave::tree_decl_elt ($1)); }
-                | return_list1 ',' identifier
-                  {
-                    $1->append (new octave::tree_decl_elt ($3));
-                    $$ = $1;
-                  }
-                ;
-
-// =======================
-// Script or function file
-// =======================
-
-parsing_local_fcns
-                : // empty
-                  { parser.m_parsing_local_functions = true; }
-                ;
-
-push_script_symtab : // empty
-                  {
-                    $$ = 0;
-
-                    // This scope may serve as the parent scope for local
-                    // functions in classdef files..
-                    lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_script_symtab"));
-                  }
-                ;
-
-begin_file      : push_script_symtab INPUT_FILE
-                  { $$ = 0; }
-                ;
-
-file            : begin_file opt_nl opt_list END_OF_INPUT
-                  {
-                    YYUSE ($2);
-
-                    if (lexer.m_reading_fcn_file)
-                      {
-                        // Delete the dummy statement_list we created
-                        // after parsing the function.  Any function
-                        // definitions found in the file have already
-                        // been stored in the symbol table or in
-                        // base_parser::m_primary_fcn_ptr.
-
-                        // Unused symbol table context.
-                        lexer.m_symtab_context.pop ();
-
-                        delete $3;
-                      }
-                    else
-                      {
-                        octave::tree_statement *end_of_script
-                          = parser.make_end ("endscript", true,
-                                             lexer.m_input_line_number,
-                                             lexer.m_current_input_column);
-
-                        parser.make_script ($3, end_of_script);
-                      }
-
-                    $$ = nullptr;
-                  }
-                | begin_file opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT
-                  {
-                    YYUSE ($2);
-                    YYUSE ($5);
-
-                    // Unused symbol table context.
-                    lexer.m_symtab_context.pop ();
-
-                    parser.finish_classdef_file ($3, $6);
-
-                    $$ = nullptr;
-                  }
-                ;
-
-// ===================
-// Function definition
-// ===================
-
-function_beg    : push_fcn_symtab FCN
-                  {
-                    $$ = $2;
-                    if (lexer.m_reading_classdef_file
-                        || lexer.m_parsing_classdef)
-                      lexer.m_maybe_classdef_get_set_method = true;
-                  }
-                ;
-
-fcn_name        : identifier
-                  {
-                    std::string id = $1->name ();
-
-                    // Make classdef local functions unique from
-                    // classdef methods.
-
-                    if (parser.m_parsing_local_functions
-                        && parser.m_curr_fcn_depth == 1)
-                      id = lexer.m_fcn_file_name + ">" + id;
-
-                    if (! parser.m_function_scopes.name_current_scope (id))
-                      {
-                        parser.bison_error ("duplicate subfunction or nested function name",
-                                            $1->line (), $1->column ());
-
-                        delete $1;
-
-                        YYABORT;
-                      }
-
-                    octave::symbol_scope curr_scope
-                      = lexer.m_symtab_context.curr_scope ();
-                    curr_scope.cache_name (id);
-
-                    lexer.m_parsed_function_name.top () = true;
-                    lexer.m_maybe_classdef_get_set_method = false;
-
-                    $$ = $1;
-                  }
-                | GET '.' identifier
-                  {
-                    YYUSE ($1);
-
-                    lexer.m_parsed_function_name.top () = true;
-                    lexer.m_maybe_classdef_get_set_method = false;
-                    lexer.m_parsing_classdef_get_method = true;
-                    $$ = $3;
-                  }
-                | SET '.' identifier
-                  {
-                    YYUSE ($1);
-
-                    lexer.m_parsed_function_name.top () = true;
-                    lexer.m_maybe_classdef_get_set_method = false;
-                    lexer.m_parsing_classdef_set_method = true;
-                    $$ = $3;
-                  }
-                ;
-
-function_end    : END
-                  {
-                    parser.m_endfunction_found = true;
-
-                    if (parser.end_token_ok ($1, octave::token::function_end))
-                      $$ = parser.make_end ("endfunction", false,
-                                            $1->line (), $1->column ());
-                    else
-                      {
-                        parser.end_token_error ($1, octave::token::function_end);
-                        YYABORT;
-                      }
-                  }
-                | END_OF_INPUT
-                  {
-// A lot of tests are based on the assumption that this is OK
-//                  if (lexer.m_reading_script_file)
-//                    {
-//                      parser.bison_error ("function body open at end of script");
-//                      YYABORT;
-//                    }
-
-                    if (parser.m_endfunction_found)
-                      {
-                        parser.bison_error ("inconsistent function endings -- "
-                                 "if one function is explicitly ended, "
-                                 "so must all the others");
-                        YYABORT;
-                      }
-
-                    if (! (lexer.m_reading_fcn_file || lexer.m_reading_script_file
-                           || lexer.input_from_eval_string ()))
-                      {
-                        parser.bison_error ("function body open at end of input");
-                        YYABORT;
-                      }
-
-                    if (lexer.m_reading_classdef_file)
-                      {
-                        parser.bison_error ("classdef body open at end of input");
-                        YYABORT;
-                      }
-
-                    $$ = parser.make_end ("endfunction", true,
-                                          lexer.m_input_line_number,
-                                          lexer.m_current_input_column);
-                  }
-                ;
-
-function        : function_beg stash_comment fcn_name
-                  opt_param_list opt_sep opt_list function_end
-                  {
-                    YYUSE ($5);
-
-                    $$ = parser.make_function ($1, nullptr, $3, $4, $6, $7, $2);
-                  }
-                | function_beg stash_comment return_list '=' fcn_name
-                  opt_param_list opt_sep opt_list function_end
-                  {
-                    YYUSE ($4);
-                    YYUSE ($7);
-
-                    $$ = parser.make_function ($1, $3, $5, $6, $8, $9, $2);
-                  }
-                ;
-
-// ========
-// Classdef
-// ========
-
-classdef_beg    : CLASSDEF
-                  {
-                    if (! lexer.m_reading_classdef_file)
-                      {
-                        parser.bison_error ("classdef must appear inside a file containing only a class definition");
-                        YYABORT;
-                      }
-
-                    // Create invalid parent scope.
-                    lexer.m_symtab_context.push (octave::symbol_scope ());
-                    lexer.m_parsing_classdef = true;
-                    $$ = $1;
-                  }
-                ;
-
-classdef        : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END
-                  {
-                    YYUSE ($6);
-                    YYUSE ($8);
-
-                    lexer.m_parsing_classdef = false;
-
-                    if (! ($$ = parser.make_classdef ($1, $3, $4, $5, $7, $9, $2)))
-                      {
-                        // make_classdef deleted $3, $4, $5, and $7.
-                        YYABORT;
-                      }
-                  }
-                | classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep END
-                  {
-                    YYUSE ($6);
-
-                    lexer.m_parsing_classdef = false;
-
-                    if (! ($$ = parser.make_classdef ($1, $3, $4, $5, nullptr,
-                                                      $7, $2)))
-                      {
-                        // make_classdef deleted $3, $4, and $5.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-opt_attr_list   : // empty
-                  { $$ = nullptr; }
-                | '(' attr_list ')'
-                  { $$ = $2; }
-                ;
-
-attr_list       : attr
-                  { $$ = new octave::tree_classdef_attribute_list ($1); }
-                | attr_list ',' attr
-                  {
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-attr            : identifier
-                  { $$ = new octave::tree_classdef_attribute ($1); }
-                | identifier '=' decl_param_init expression
-                  {
-                    YYUSE ($2);
-
-                    lexer.m_looking_at_initializer_expression = false;
-                    $$ = new octave::tree_classdef_attribute ($1, $4);
-                  }
-                | EXPR_NOT identifier
-                  {
-                    YYUSE ($1);
-
-                    $$ = new octave::tree_classdef_attribute ($2, false);
-                  }
-                ;
-
-opt_superclass_list
-                : // empty
-                  { $$ = nullptr; }
-                | superclass_list
-                  { $$ = $1; }
-                ;
-
-superclass_list : EXPR_LT
-                  {
-                    YYUSE ($1);
-
-                    lexer.enable_fq_identifier ();
-                  }
-                  superclass
-                  { $$ = new octave::tree_classdef_superclass_list ($3); }
-                | superclass_list EXPR_AND
-                  {
-                    YYUSE ($2);
-
-                    lexer.enable_fq_identifier ();
-                  }
-                  superclass
-                  {
-                    $1->append ($4);
-                    $$ = $1;
-                  }
-                ;
-
-superclass      : FQ_IDENT
-                  { $$ = new octave::tree_classdef_superclass ($1->text ()); }
-                ;
-
-class_body      : properties_block
-                  { $$ = new octave::tree_classdef_body ($1); }
-                | methods_block
-                  { $$ = new octave::tree_classdef_body ($1); }
-                | events_block
-                  { $$ = new octave::tree_classdef_body ($1); }
-                | enum_block
-                  { $$ = new octave::tree_classdef_body ($1); }
-                | class_body opt_sep properties_block
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                | class_body opt_sep methods_block
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                | class_body opt_sep events_block
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                | class_body opt_sep enum_block
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-properties_block
-                : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($6);
-
-                    if (! ($$ = parser.make_classdef_properties_block
-                           ($1, $3, $5, $7, $2)))
-                      {
-                        // make_classdef_properties_block delete $3 and $5.
-                        YYABORT;
-                      }
-                  }
-                | PROPERTIES stash_comment opt_attr_list opt_sep END
-                  {
-                    YYUSE ($4);
-
-                    if (! ($$ = parser.make_classdef_properties_block
-                           ($1, $3, nullptr, $5, $2)))
-                      {
-                        // make_classdef_properties_block delete $3.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-property_list
-                : class_property
-                  { $$ = new octave::tree_classdef_property_list ($1); }
-                | property_list sep class_property
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-class_property  : identifier
-                  { $$ = new octave::tree_classdef_property ($1); }
-                | identifier '=' decl_param_init expression
-                  {
-                    YYUSE ($2);
-
-                    lexer.m_looking_at_initializer_expression = false;
-                    $$ = new octave::tree_classdef_property ($1, $4);
-                  }
-                ;
-
-methods_block   : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($6);
-
-                    if (! ($$ = parser.make_classdef_methods_block
-                           ($1, $3, $5, $7, $2)))
-                      {
-                        // make_classdef_methods_block deleted $3 and $5.
-                        YYABORT;
-                      }
-                  }
-                | METHODS stash_comment opt_attr_list opt_sep END
-                  {
-                    YYUSE ($4);
-
-                    if (! ($$ = parser.make_classdef_methods_block
-                           ($1, $3, nullptr, $5, $2)))
-                      {
-                        // make_classdef_methods_block deleted $3.
-                        YYABORT;
-                      }
-                  }
-                ;
-                ;
-
-method_decl1    : identifier
-                  {
-                    if (! ($$ = parser.start_classdef_external_method ($1, nullptr)))
-                      YYABORT;
-                  }
-                | identifier param_list
-                  {
-                    if (! ($$ = parser.start_classdef_external_method ($1, $2)))
-                      YYABORT;
-                  }
-                ;
-
-method_decl     : stash_comment method_decl1
-                  { $$ = parser.finish_classdef_external_method ($2, nullptr, $1); }
-                | stash_comment return_list '='
-                  {
-                    YYUSE ($3);
-
-                    lexer.m_defining_func++;
-                    lexer.m_parsed_function_name.push (false);
-                  }
-                  method_decl1
-                  {
-                    lexer.m_defining_func--;
-                    lexer.m_parsed_function_name.pop ();
-                    $$ = parser.finish_classdef_external_method ($5, $2, $1);
-                  }
-                ;
-
-method          : method_decl
-                  { $$ = $1; }
-                | function
-                  { $$ = $1; }
-                ;
-
-methods_list    : method
-                  {
-                    octave_value fcn;
-                    if ($1)
-                      fcn = $1->function ();
-                    delete $1;
-                    $$ = new octave::tree_classdef_methods_list (fcn);
-                  }
-                | methods_list opt_sep method
-                  {
-                    YYUSE ($2);
-
-                    octave_value fcn;
-                    if ($3)
-                      fcn = $3->function ();
-                    delete $3;
-
-                    $1->append (fcn);
-                    $$ = $1;
-                  }
-                ;
-
-events_block    : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($6);
-
-                    if (! ($$ = parser.make_classdef_events_block
-                           ($1, $3, $5, $7, $2)))
-                      {
-                        // make_classdef_events_block deleted $3 and $5.
-                        YYABORT;
-                      }
-                  }
-                | EVENTS stash_comment opt_attr_list opt_sep END
-                  {
-                    YYUSE ($4);
-
-                    if (! ($$ = parser.make_classdef_events_block
-                           ($1, $3, nullptr, $5, $2)))
-                      {
-                        // make_classdef_events_block deleted $3.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-events_list     : class_event
-                  { $$ = new octave::tree_classdef_events_list ($1); }
-                | events_list opt_sep class_event
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-class_event     : identifier
-                  { $$ = new octave::tree_classdef_event ($1); }
-                ;
-
-enum_block      : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END
-                  {
-                    YYUSE ($4);
-                    YYUSE ($6);
-
-                    if (! ($$ = parser.make_classdef_enum_block
-                           ($1, $3, $5, $7, $2)))
-                      {
-                        // make_classdef_enum_block deleted $3 and $5.
-                        YYABORT;
-                      }
-                  }
-                | ENUMERATION stash_comment opt_attr_list opt_sep END
-                  {
-                    YYUSE ($4);
-
-                    if (! ($$ = parser.make_classdef_enum_block
-                           ($1, $3, nullptr, $5, $2)))
-                      {
-                        // make_classdef_enum_block deleted $3.
-                        YYABORT;
-                      }
-                  }
-                ;
-
-enum_list       : class_enum
-                  { $$ = new octave::tree_classdef_enum_list ($1); }
-                | enum_list opt_sep class_enum
-                  {
-                    YYUSE ($2);
-
-                    $1->append ($3);
-                    $$ = $1;
-                  }
-                ;
-
-class_enum      : identifier '(' expression ')'
-                  { $$ = new octave::tree_classdef_enum ($1, $3); }
-                ;
-
-// =============
-// Miscellaneous
-// =============
-
-stmt_begin      : // empty
-                  {
-                    $$ = 0;
-                    lexer.m_at_beginning_of_statement = true;
-                  }
-                ;
-
-stash_comment   : // empty
-                  { $$ = lexer.get_comment (); }
-                ;
-
-parse_error     : LEXICAL_ERROR
-                  {
-                    $$ = 0;
-                    std::string msg = $1->text ();
-                    parser.bison_error (msg.c_str ());
-                  }
-                | error
-                  { $$ = 0; }
-                ;
-
-sep_no_nl       : ','
-                  { $$ = ','; }
-                | ';'
-                  { $$ = ';'; }
-                | sep_no_nl ','
-                  { $$ = $1; }
-                | sep_no_nl ';'
-                  { $$ = $1; }
-                ;
-
-opt_sep_no_nl   : // empty
-                  { $$ = 0; }
-                | sep_no_nl
-                  { $$ = $1; }
-                ;
-
-opt_nl          : // empty
-                  { $$ = 0; }
-                | nl
-                  { $$ = $1; }
-                ;
-
-nl              : '\n'
-                  { $$ = '\n'; }
-                | nl '\n'
-                  { $$ = $1; }
-                ;
-
-sep             : ','
-                  { $$ = ','; }
-                | ';'
-                  { $$ = ';'; }
-                | '\n'
-                  { $$ = '\n'; }
-                | sep ','
-                  { $$ = $1; }
-                | sep ';'
-                  { $$ = $1; }
-                | sep '\n'
-                  { $$ = $1; }
-                ;
-
-opt_sep         : // empty
-                  { $$ = 0; }
-                | sep
-                  { $$ = $1; }
-                ;
-
-%%
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-   // Restore prevailing warning state for remainder of the file.
-#  pragma GCC diagnostic pop
-#endif
-
-// Generic error messages.
-
-#undef lexer
-#undef scanner
-
-static void
-yyerror (octave::base_parser& parser, const char *s)
-{
-  parser.bison_error (s);
-}
-
-namespace octave
-{
-  size_t
-  base_parser::parent_scope_info::size (void) const
-  {
-    return m_info.size ();
-  }
-
-  void
-  base_parser::parent_scope_info::push (const value_type& elt)
-  {
-    m_info.push_back (elt);
-  }
-
-  void
-  base_parser::parent_scope_info::push (const symbol_scope& scope)
-  {
-    push (value_type (scope, ""));
-  }
-
-  void
-  base_parser::parent_scope_info::pop (void)
-  {
-    m_info.pop_back ();
-  }
-
-  bool
-  base_parser::parent_scope_info::name_ok (const std::string& name)
-  {
-    // Name can't be the same as any parent function or any other
-    // function we've already seen.  We could maintain a complex
-    // tree structure of names, or we can just store the set of
-    // full names of all the functions, which must be unique.
-
-    std::string full_name;
-
-    for (size_t i = 0; i < size()-1; i++)
-      {
-        const value_type& elt = m_info[i];
-
-        if (name == elt.second)
-          return false;
-
-        full_name += elt.second + ">";
-      }
-
-    full_name += name;
-
-    if (m_all_names.find (full_name) != m_all_names.end ())
-      return false;
-
-    m_all_names.insert (full_name);
-
-    return true;
-  }
-
-  bool
-  base_parser::parent_scope_info::name_current_scope (const std::string& name)
-  {
-    if (! name_ok (name))
-      return false;
-
-    if (size () > 0)
-      m_info.back().second = name;
-
-    return true;
-  }
-
-  symbol_scope
-  base_parser::parent_scope_info::parent_scope (void) const
-  {
-    return size () > 1 ? m_info[size()-2].first : symbol_scope ();
-  }
-
-  std::string
-  base_parser::parent_scope_info::parent_name (void) const
-  {
-    return m_info[size()-2].second;
-  }
-
-  void base_parser::parent_scope_info::clear (void)
-  {
-    m_info.clear ();
-    m_all_names.clear ();
-  }
-
-  base_parser::base_parser (base_lexer& lxr)
-    : m_endfunction_found (false), m_autoloading (false),
-      m_fcn_file_from_relative_lookup (false),
-      m_parsing_subfunctions (false), m_parsing_local_functions (false),
-      m_max_fcn_depth (0), m_curr_fcn_depth (0), m_primary_fcn_scope (),
-      m_curr_class_name (), m_curr_package_name (), m_function_scopes (),
-      m_primary_fcn_ptr (nullptr), m_subfunction_names (),
-      m_classdef_object (nullptr), m_stmt_list (nullptr), m_lexer (lxr),
-      m_parser_state (yypstate_new ())
-  { }
-
-  base_parser::~base_parser (void)
-  {
-    delete m_stmt_list;
-
-    delete &m_lexer;
-
-    // FIXME: Deleting the internal Bison parser state structure does
-    // not clean up any partial parse trees in the event of an interrupt or
-    // error.  It's not clear how to safely do that with the C language
-    // parser that Bison generates.  The C++ language parser that Bison
-    // generates would do it for us automatically whenever an exception
-    // is thrown while parsing input, but there is currently no C++
-    // interface for a push parser.
-
-    yypstate_delete (static_cast<yypstate *> (m_parser_state));
-  }
-
-  void
-  base_parser::reset (void)
-  {
-    m_endfunction_found = false;
-    m_autoloading = false;
-    m_fcn_file_from_relative_lookup = false;
-    m_parsing_subfunctions = false;
-    m_parsing_local_functions = false;
-    m_max_fcn_depth = 0;
-    m_curr_fcn_depth = 0;
-    m_primary_fcn_scope = symbol_scope ();
-    m_curr_class_name = "";
-    m_curr_package_name = "";
-    m_function_scopes.clear ();
-    m_primary_fcn_ptr  = nullptr;
-    m_subfunction_names.clear ();
-    m_classdef_object = nullptr;
-
-    delete m_stmt_list;
-    m_stmt_list = nullptr;
-
-    m_lexer.reset ();
-
-    yypstate_delete (static_cast<yypstate *> (m_parser_state));
-    m_parser_state = yypstate_new ();
-  }
-}
-
-// Error mesages for mismatched end tokens.
-
-static std::string
-end_token_as_string (octave::token::end_tok_type ettype)
-{
-  std::string retval = "<unknown>";
-
-  switch (ettype)
-    {
-    case octave::token::simple_end:
-      retval = "end";
-      break;
-
-    case octave::token::classdef_end:
-      retval = "endclassdef";
-      break;
-
-    case octave::token::enumeration_end:
-      retval = "endenumeration";
-      break;
-
-    case octave::token::events_end:
-      retval = "endevents";
-      break;
-
-    case octave::token::for_end:
-      retval = "endfor";
-      break;
-
-    case octave::token::function_end:
-      retval = "endfunction";
-      break;
-
-    case octave::token::if_end:
-      retval = "endif";
-      break;
-
-    case octave::token::methods_end:
-      retval = "endmethods";
-      break;
-
-    case octave::token::parfor_end:
-      retval = "endparfor";
-      break;
-
-    case octave::token::properties_end:
-      retval = "endproperties";
-      break;
-
-    case octave::token::switch_end:
-      retval = "endswitch";
-      break;
-
-    case octave::token::try_catch_end:
-      retval = "end_try_catch";
-      break;
-
-    case octave::token::unwind_protect_end:
-      retval = "end_unwind_protect";
-      break;
-
-    case octave::token::while_end:
-      retval = "endwhile";
-      break;
-
-    default:
-      panic_impossible ();
-      break;
-    }
-
-  return retval;
-}
-
-namespace octave
-{
-  void
-  base_parser::end_token_error (token *tok, token::end_tok_type expected)
-  {
-    std::string msg = ("'" + end_token_as_string (expected)
-                       + "' command matched by '"
-                       + end_token_as_string (tok->ettype ()) + "'");
-
-    bison_error (msg, tok->line (), tok->column ());
-  }
-
-  // Check to see that end tokens are properly matched.
-
-  bool
-  base_parser::end_token_ok (token *tok, token::end_tok_type expected)
-  {
-    token::end_tok_type ettype = tok->ettype ();
-
-    return ettype == expected || ettype == token::simple_end;
-  }
-
-  // Maybe print a warning if an assignment expression is used as the
-  // test in a logical expression.
-
-  void
-  base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr)
-  {
-    if (expr->is_assignment_expression ()
-        && expr->paren_count () < 2)
-      {
-        if (m_lexer.m_fcn_file_full_name.empty ())
-          warning_with_id
-            ("Octave:assign-as-truth-value",
-             "suggest parenthesis around assignment used as truth value");
-        else
-          warning_with_id
-            ("Octave:assign-as-truth-value",
-             "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'",
-             expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ());
-      }
-  }
-
-  // Maybe print a warning about switch labels that aren't constants.
-
-  void
-  base_parser::maybe_warn_variable_switch_label (tree_expression *expr)
-  {
-    if (! expr->is_constant ())
-      {
-        if (m_lexer.m_fcn_file_full_name.empty ())
-          warning_with_id ("Octave:variable-switch-label",
-                           "variable switch label");
-        else
-          warning_with_id
-            ("Octave:variable-switch-label",
-             "variable switch label near line %d, column %d in file '%s'",
-             expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ());
-      }
-  }
-
-  // Make a constant.
-
-  tree_constant *
-  base_parser::make_constant (int op, token *tok_val)
-  {
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    tree_constant *retval = nullptr;
-
-    switch (op)
-      {
-      case NUM:
-        {
-          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->stash_original_text (tok_val->text_rep ());
-        }
-        break;
-
-      case DQ_STRING:
-      case SQ_STRING:
-        {
-          std::string txt = tok_val->text ();
-
-          char delim = op == DQ_STRING ? '"' : '\'';
-          octave_value tmp (txt, delim);
-
-          if (txt.empty ())
-            {
-              if (op == DQ_STRING)
-                tmp = octave_null_str::instance;
-              else
-                tmp = octave_null_sq_str::instance;
-            }
-
-          retval = new tree_constant (tmp, l, c);
-
-          if (op == DQ_STRING)
-            txt = undo_string_escapes (txt);
-
-          // FIXME: maybe this should also be handled by
-          // tok_val->text_rep () for character strings?
-          retval->stash_original_text (delim + txt + delim);
-        }
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    return retval;
-  }
-
-  // Make a function handle.
-
-  tree_fcn_handle *
-  base_parser::make_fcn_handle (token *tok_val)
-  {
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c);
-
-    return retval;
-  }
-
-  // Make an anonymous function handle.
-
-  tree_anon_fcn_handle *
-  base_parser::make_anon_fcn_handle (tree_parameter_list *param_list,
-                                     tree_expression *expr)
-  {
-    // FIXME: need to get these from the location of the @ symbol.
-    int l = m_lexer.m_input_line_number;
-    int c = m_lexer.m_current_input_column;
-
-    symbol_scope fcn_scope = m_lexer.m_symtab_context.curr_scope ();
-    symbol_scope parent_scope = m_lexer.m_symtab_context.parent_scope ();
-
-    m_lexer.m_symtab_context.pop ();
-
-    expr->set_print_flag (false);
-
-    fcn_scope.mark_static ();
-
-    tree_anon_fcn_handle *retval
-      = new tree_anon_fcn_handle (param_list, expr, fcn_scope,
-                                  parent_scope, l, c);
-
-    std::ostringstream buf;
-
-    tree_print_code tpc (buf);
-
-    retval->accept (tpc);
-
-    std::string file = m_lexer.m_fcn_file_full_name;
-    if (! file.empty ())
-      buf << ": file: " << file;
-    else if (m_lexer.input_from_terminal ())
-      buf << ": *terminal input*";
-    else if (m_lexer.input_from_eval_string ())
-      buf << ": *eval string*";
-    buf << ": line: " << l << " column: " << c;
-
-    std::string scope_name = buf.str ();
-
-    fcn_scope.cache_name (scope_name);
-
-    // FIXME: Stash the filename.  This does not work and produces
-    // errors when executed.
-    //retval->stash_file_name (m_lexer.m_fcn_file_name);
-
-    return retval;
-  }
-
-  // Build a colon expression.
-
-  tree_expression *
-  base_parser::make_colon_expression (tree_expression *base,
-                                      tree_expression *limit,
-                                      tree_expression *incr)
-  {
-    tree_expression *retval = nullptr;
-
-    unwind_protect frame;
-
-    frame.protect_var (discard_error_messages);
-    frame.protect_var (discard_warning_messages);
-
-    discard_error_messages = true;
-    discard_warning_messages = true;
-
-    if (! base || ! limit)
-      {
-        delete base;
-        delete limit;
-        delete incr;
-
-        return retval;
-      }
-
-    int l = base->line ();
-    int c = base->column ();
-
-    tree_colon_expression *e
-      = new tree_colon_expression (base, limit, incr, l, c);
-
-    if (base->is_constant () && limit->is_constant ()
-        && (! incr || (incr && incr->is_constant ())))
-      {
-        try
-          {
-            tree_evaluator& tw
-              = __get_evaluator__ ("finish_colon_expression");
-
-            octave_value tmp = tw.evaluate (e);
-
-            tree_constant *tc_retval
-              = new tree_constant (tmp, e->line (), e->column ());
-
-            std::ostringstream buf;
-
-            tree_print_code tpc (buf);
-
-            e->accept (tpc);
-
-            tc_retval->stash_original_text (buf.str ());
-
-            delete e;
-
-            retval = tc_retval;
-          }
-        catch (const execution_exception&)
-          {
-            interpreter::recover_from_exception ();
-          }
-      }
-    else
-      retval = e;
-
-    return retval;
-  }
-
-  // Build a binary expression.
-
-  tree_expression *
-  base_parser::make_binary_op (int op, tree_expression *op1,
-                               token *tok_val, tree_expression *op2)
-  {
-    octave_value::binary_op t = octave_value::unknown_binary_op;
-
-    switch (op)
-      {
-      case POW:
-        t = octave_value::op_pow;
-        break;
-
-      case EPOW:
-        t = octave_value::op_el_pow;
-        break;
-
-      case '+':
-        t = octave_value::op_add;
-        break;
-
-      case '-':
-        t = octave_value::op_sub;
-        break;
-
-      case '*':
-        t = octave_value::op_mul;
-        break;
-
-      case '/':
-        t = octave_value::op_div;
-        break;
-
-      case EMUL:
-        t = octave_value::op_el_mul;
-        break;
-
-      case EDIV:
-        t = octave_value::op_el_div;
-        break;
-
-      case LEFTDIV:
-        t = octave_value::op_ldiv;
-        break;
-
-      case ELEFTDIV:
-        t = octave_value::op_el_ldiv;
-        break;
-
-      case EXPR_LT:
-        t = octave_value::op_lt;
-        break;
-
-      case EXPR_LE:
-        t = octave_value::op_le;
-        break;
-
-      case EXPR_EQ:
-        t = octave_value::op_eq;
-        break;
-
-      case EXPR_GE:
-        t = octave_value::op_ge;
-        break;
-
-      case EXPR_GT:
-        t = octave_value::op_gt;
-        break;
-
-      case EXPR_NE:
-        t = octave_value::op_ne;
-        break;
-
-      case EXPR_AND:
-        t = octave_value::op_el_and;
-        break;
-
-      case EXPR_OR:
-        t = octave_value::op_el_or;
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    return maybe_compound_binary_expression (op1, op2, l, c, t);
-  }
-
-  // Build a boolean expression.
-
-  tree_expression *
-  base_parser::make_boolean_op (int op, tree_expression *op1,
-                                token *tok_val, tree_expression *op2)
-  {
-    tree_boolean_expression::type t;
-
-    switch (op)
-      {
-      case EXPR_AND_AND:
-        t = tree_boolean_expression::bool_and;
-        break;
-
-      case EXPR_OR_OR:
-        t = tree_boolean_expression::bool_or;
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    return new tree_boolean_expression (op1, op2, l, c, t);
-  }
-
-  // Build a prefix expression.
-
-  tree_expression *
-  base_parser::make_prefix_op (int op, tree_expression *op1, token *tok_val)
-  {
-    octave_value::unary_op t = octave_value::unknown_unary_op;
-
-    switch (op)
-      {
-      case EXPR_NOT:
-        t = octave_value::op_not;
-        break;
-
-      case '+':
-        t = octave_value::op_uplus;
-        break;
-
-      case '-':
-        t = octave_value::op_uminus;
-        break;
-
-      case PLUS_PLUS:
-        t = octave_value::op_incr;
-        break;
-
-      case MINUS_MINUS:
-        t = octave_value::op_decr;
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    return new tree_prefix_expression (op1, l, c, t);
-  }
-
-  // Build a postfix expression.
-
-  tree_expression *
-  base_parser::make_postfix_op (int op, tree_expression *op1, token *tok_val)
-  {
-    octave_value::unary_op t = octave_value::unknown_unary_op;
-
-    switch (op)
-      {
-      case HERMITIAN:
-        t = octave_value::op_hermitian;
-        break;
-
-      case TRANSPOSE:
-        t = octave_value::op_transpose;
-        break;
-
-      case PLUS_PLUS:
-        t = octave_value::op_incr;
-        break;
-
-      case MINUS_MINUS:
-        t = octave_value::op_decr;
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    return new tree_postfix_expression (op1, l, c, t);
-  }
-
-  // Build an unwind-protect command.
-
-  tree_command *
-  base_parser::make_unwind_command (token *unwind_tok,
-                                    tree_statement_list *body,
-                                    tree_statement_list *cleanup_stmts,
-                                    token *end_tok,
-                                    comment_list *lc,
-                                    comment_list *mc)
-  {
-    tree_command *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::unwind_protect_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = unwind_tok->line ();
-        int c = unwind_tok->column ();
-
-        retval = new tree_unwind_protect_command (body, cleanup_stmts,
-                                                  lc, mc, tc, l, c);
-      }
-    else
-      {
-        delete body;
-        delete cleanup_stmts;
-
-        end_token_error (end_tok, token::unwind_protect_end);
-      }
-
-    return retval;
-  }
-
-  // Build a try-catch command.
-
-  tree_command *
-  base_parser::make_try_command (token *try_tok,
-                                 tree_statement_list *body,
-                                 char catch_sep,
-                                 tree_statement_list *cleanup_stmts,
-                                 token *end_tok,
-                                 comment_list *lc,
-                                 comment_list *mc)
-  {
-    tree_command *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::try_catch_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = try_tok->line ();
-        int c = try_tok->column ();
-
-        tree_identifier *id = nullptr;
-
-        if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ())
-          {
-            tree_statement *stmt = cleanup_stmts->front ();
-
-            if (stmt)
-              {
-                tree_expression *expr = stmt->expression ();
-
-                if (expr && expr->is_identifier ())
-                  {
-                    id = dynamic_cast<tree_identifier *> (expr);
-
-                    cleanup_stmts->pop_front ();
-
-                    stmt->set_expression (nullptr);
-                    delete stmt;
-                  }
-              }
-          }
-
-        retval = new tree_try_catch_command (body, cleanup_stmts, id,
-                                             lc, mc, tc, l, c);
-      }
-    else
-      {
-        delete body;
-        delete cleanup_stmts;
-
-        end_token_error (end_tok, token::try_catch_end);
-      }
-
-    return retval;
-  }
-
-  // Build a while command.
-
-  tree_command *
-  base_parser::make_while_command (token *while_tok,
-                                   tree_expression *expr,
-                                   tree_statement_list *body,
-                                   token *end_tok,
-                                   comment_list *lc)
-  {
-    tree_command *retval = nullptr;
-
-    maybe_warn_assign_as_truth_value (expr);
-
-    if (end_token_ok (end_tok, token::while_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        m_lexer.m_looping--;
-
-        int l = while_tok->line ();
-        int c = while_tok->column ();
-
-        retval = new tree_while_command (expr, body, lc, tc, l, c);
-      }
-    else
-      {
-        delete expr;
-        delete body;
-
-        end_token_error (end_tok, token::while_end);
-      }
-
-    return retval;
-  }
-
-  // Build a do-until command.
-
-  tree_command *
-  base_parser::make_do_until_command (token *until_tok,
-                                      tree_statement_list *body,
-                                      tree_expression *expr,
-                                      comment_list *lc)
-  {
-    maybe_warn_assign_as_truth_value (expr);
-
-    comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-    m_lexer.m_looping--;
-
-    int l = until_tok->line ();
-    int c = until_tok->column ();
-
-    return new tree_do_until_command (expr, body, lc, tc, l, c);
-  }
-
-  // Build a for command.
-
-  tree_command *
-  base_parser::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)
-  {
-    tree_command *retval = nullptr;
-
-    bool parfor = tok_id == PARFOR;
-
-    if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end))
-      {
-        expr->mark_as_for_cmd_expr ();
-
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        m_lexer.m_looping--;
-
-        int l = for_tok->line ();
-        int c = for_tok->column ();
-
-        if (lhs->length () == 1)
-          {
-            tree_expression *tmp = lhs->remove_front ();
-
-            retval = new tree_simple_for_command (parfor, tmp, expr, maxproc,
-                                                  body, lc, tc, l, c);
-
-            delete lhs;
-          }
-        else
-          {
-            if (parfor)
-              {
-                delete lhs;
-                delete expr;
-                delete maxproc;
-                delete body;
-
-                bison_error ("invalid syntax for parfor statement");
-              }
-            else
-              retval = new tree_complex_for_command (lhs, expr, body,
-                                                     lc, tc, l, c);
-          }
-      }
-    else
-      {
-        delete lhs;
-        delete expr;
-        delete maxproc;
-        delete body;
-
-        end_token_error (end_tok, parfor ? token::parfor_end : token::for_end);
-      }
-
-    return retval;
-  }
-
-  // Build a break command.
-
-  tree_command *
-  base_parser::make_break_command (token *break_tok)
-  {
-    int l = break_tok->line ();
-    int c = break_tok->column ();
-
-    if (! m_lexer.m_looping)
-      {
-        bison_error ("break must appear in a loop in the same file as loop command");
-        return nullptr;
-      }
-    else
-      return new tree_break_command (l, c);
-  }
-
-  // Build a continue command.
-
-  tree_command *
-  base_parser::make_continue_command (token *continue_tok)
-  {
-    int l = continue_tok->line ();
-    int c = continue_tok->column ();
-
-    return new tree_continue_command (l, c);
-  }
-
-  // Build a return command.
-
-  tree_command *
-  base_parser::make_return_command (token *return_tok)
-  {
-    int l = return_tok->line ();
-    int c = return_tok->column ();
-
-    return new tree_return_command (l, c);
-  }
-
-  // Start an if command.
-
-  tree_if_command_list *
-  base_parser::start_if_command (tree_expression *expr,
-                                 tree_statement_list *list)
-  {
-    maybe_warn_assign_as_truth_value (expr);
-
-    tree_if_clause *t = new tree_if_clause (expr, list);
-
-    return new tree_if_command_list (t);
-  }
-
-  // Finish an if command.
-
-  tree_if_command *
-  base_parser::finish_if_command (token *if_tok,
-                                  tree_if_command_list *list,
-                                  token *end_tok,
-                                  comment_list *lc)
-  {
-    tree_if_command *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::if_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = if_tok->line ();
-        int c = if_tok->column ();
-
-        if (list && ! list->empty ())
-          {
-            tree_if_clause *elt = list->front ();
-
-            if (elt)
-              {
-                elt->line (l);
-                elt->column (c);
-              }
-          }
-
-        retval = new tree_if_command (list, lc, tc, l, c);
-      }
-    else
-      {
-        delete list;
-
-        end_token_error (end_tok, token::if_end);
-      }
-
-    return retval;
-  }
-
-  // Build an elseif clause.
-
-  tree_if_clause *
-  base_parser::make_elseif_clause (token *elseif_tok,
-                                   tree_expression *expr,
-                                   tree_statement_list *list,
-                                   comment_list *lc)
-  {
-    maybe_warn_assign_as_truth_value (expr);
-
-    int l = elseif_tok->line ();
-    int c = elseif_tok->column ();
-
-    return new tree_if_clause (expr, list, lc, l, c);
-  }
-
-  // Finish a switch command.
-
-  tree_switch_command *
-  base_parser::finish_switch_command (token *switch_tok,
-                                      tree_expression *expr,
-                                      tree_switch_case_list *list,
-                                      token *end_tok,
-                                      comment_list *lc)
-  {
-    tree_switch_command *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::switch_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = switch_tok->line ();
-        int c = switch_tok->column ();
-
-        if (list && ! list->empty ())
-          {
-            tree_switch_case *elt = list->front ();
-
-            if (elt)
-              {
-                elt->line (l);
-                elt->column (c);
-              }
-          }
-
-        retval = new tree_switch_command (expr, list, lc, tc, l, c);
-      }
-    else
-      {
-        delete expr;
-        delete list;
-
-        end_token_error (end_tok, token::switch_end);
-      }
-
-    return retval;
-  }
-
-  // Build a switch case.
-
-  tree_switch_case *
-  base_parser::make_switch_case (token *case_tok,
-                                 tree_expression *expr,
-                                 tree_statement_list *list,
-                                 comment_list *lc)
-  {
-    maybe_warn_variable_switch_label (expr);
-
-    int l = case_tok->line ();
-    int c = case_tok->column ();
-
-    return new tree_switch_case (expr, list, lc, l, c);
-  }
-
-  // Build an assignment to a variable.
-
-  tree_expression *
-  base_parser::make_assign_op (int op, tree_argument_list *lhs,
-                               token *eq_tok, tree_expression *rhs)
-  {
-    octave_value::assign_op t = octave_value::unknown_assign_op;
-
-    switch (op)
-      {
-      case '=':
-        t = octave_value::op_asn_eq;
-        break;
-
-      case ADD_EQ:
-        t = octave_value::op_add_eq;
-        break;
-
-      case SUB_EQ:
-        t = octave_value::op_sub_eq;
-        break;
-
-      case MUL_EQ:
-        t = octave_value::op_mul_eq;
-        break;
-
-      case DIV_EQ:
-        t = octave_value::op_div_eq;
-        break;
-
-      case LEFTDIV_EQ:
-        t = octave_value::op_ldiv_eq;
-        break;
-
-      case POW_EQ:
-        t = octave_value::op_pow_eq;
-        break;
-
-      case EMUL_EQ:
-        t = octave_value::op_el_mul_eq;
-        break;
-
-      case EDIV_EQ:
-        t = octave_value::op_el_div_eq;
-        break;
-
-      case ELEFTDIV_EQ:
-        t = octave_value::op_el_ldiv_eq;
-        break;
-
-      case EPOW_EQ:
-        t = octave_value::op_el_pow_eq;
-        break;
-
-      case AND_EQ:
-        t = octave_value::op_el_and_eq;
-        break;
-
-      case OR_EQ:
-        t = octave_value::op_el_or_eq;
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    int l = eq_tok->line ();
-    int c = eq_tok->column ();
-
-    if (! lhs->is_simple_assign_lhs () && t != octave_value::op_asn_eq)
-      {
-        // Multiple assignments like [x,y] OP= rhs are only valid for
-        // '=', not '+=', etc.
-
-        delete lhs;
-        delete rhs;
-
-        bison_error ("computed multiple assignment not allowed", l, c);
-
-        return nullptr;
-      }
-
-    if (lhs->is_simple_assign_lhs ())
-      {
-        // We are looking at a simple assignment statement like x = rhs;
-
-        tree_expression *tmp = lhs->remove_front ();
-
-        if ((tmp->is_identifier () || tmp->is_index_expression ())
-            && is_keyword (tmp->name ()))
-          {
-            std::string kw = tmp->name ();
-
-            delete tmp;
-            delete lhs;
-            delete rhs;
-
-            bison_error ("invalid assignment to keyword \"" + kw + "\"", l, c);
-
-            return nullptr;
-          }
-
-        delete lhs;
-
-        return new tree_simple_assignment (tmp, rhs, false, l, c, t);
-      }
-    else
-      {
-        std::list<std::string> names = lhs->variable_names ();
-
-        for (const auto& kw : names)
-          {
-            if (is_keyword (kw))
-              {
-                delete lhs;
-                delete rhs;
-
-                bison_error ("invalid assignment to keyword \"" + kw + "\"",
-                             l, c);
-
-                return nullptr;
-              }
-          }
-
-        return new tree_multi_assignment (lhs, rhs, false, l, c);
-      }
-  }
-
-  // Define a script.
-
-  void
-  base_parser::make_script (tree_statement_list *cmds,
-                            tree_statement *end_script)
-  {
-    if (! cmds)
-      cmds = new tree_statement_list ();
-
-    cmds->append (end_script);
-
-    symbol_scope script_scope = m_lexer.m_symtab_context.curr_scope ();
-
-    script_scope.cache_name (m_lexer.m_fcn_file_full_name);
-
-    octave_user_script *script
-      = new octave_user_script (m_lexer.m_fcn_file_full_name,
-                                m_lexer.m_fcn_file_name, script_scope,
-                                cmds, m_lexer.m_help_text);
-
-    m_lexer.m_symtab_context.pop ();
-    m_lexer.m_help_text = "";
-
-    sys::time now;
-
-    script->stash_fcn_file_time (now);
-
-    m_primary_fcn_ptr = script;
-  }
-
-  // Define a function.
-
-  // FIXME: combining start_function, finish_function, and
-  // recover_from_parsing_function should be possible, but it makes
-  // for a large mess.  Maybe this could be a bit better organized?
-
-  tree_function_def *
-  base_parser::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)
-  {
-    tree_function_def *retval = nullptr;
-
-    int l = fcn_tok->line ();
-    int c = fcn_tok->column ();
-
-    octave_user_function *tmp_fcn
-      = start_function (id, param_list, body, end_fcn_stmt);
-
-    retval = finish_function (ret_list, tmp_fcn, lc, l, c);
-
-    recover_from_parsing_function ();
-
-    return retval;
-  }
-
-  // Begin defining a function.
-
-  octave_user_function *
-  base_parser::start_function (tree_identifier *id,
-                               tree_parameter_list *param_list,
-                               tree_statement_list *body,
-                               tree_statement *end_fcn_stmt)
-  {
-    // We'll fill in the return list later.
-
-    std::string id_name = id->name ();
-
-    delete id;
-
-    if (m_lexer.m_parsing_classdef_get_method)
-      id_name.insert (0, "get.");
-    else if (m_lexer.m_parsing_classdef_set_method)
-      id_name.insert (0, "set.");
-
-    m_lexer.m_parsing_classdef_get_method = false;
-    m_lexer.m_parsing_classdef_set_method = false;
-
-    if (! body)
-      body = new tree_statement_list ();
-
-    body->append (end_fcn_stmt);
-
-    octave_user_function *fcn
-      = new octave_user_function (m_lexer.m_symtab_context.curr_scope (),
-                                  param_list, nullptr, body);
-
-    if (fcn)
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        fcn->stash_trailing_comment (tc);
-        fcn->stash_fcn_end_location (end_fcn_stmt->line (),
-                                     end_fcn_stmt->column ());
-      }
-
-    // If input is coming from a file, issue a warning if the name of
-    // the file does not match the name of the function stated in the
-    // file.  Matlab doesn't provide a diagnostic (it ignores the stated
-    // name).
-    if (! m_autoloading && m_lexer.m_reading_fcn_file
-        && m_curr_fcn_depth == 1 && ! m_parsing_subfunctions)
-      {
-        // FIXME: should m_lexer.m_fcn_file_name already be
-        // preprocessed when we get here?  It seems to only be a
-        // problem with relative filenames.
-
-        std::string nm = m_lexer.m_fcn_file_name;
-
-        size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ());
-
-        if (pos != std::string::npos)
-          nm = m_lexer.m_fcn_file_name.substr (pos+1);
-
-        if (nm != id_name)
-          {
-            warning_with_id
-              ("Octave:function-name-clash",
-               "function name '%s' does not agree with function filename '%s'",
-               id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ());
-
-            id_name = nm;
-          }
-      }
-
-    if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_classdef_file || m_autoloading)
-      {
-        sys::time now;
-
-        fcn->stash_fcn_file_name (m_lexer.m_fcn_file_full_name);
-        fcn->stash_fcn_file_time (now);
-        fcn->stash_dir_name (m_lexer.m_dir_name);
-        fcn->stash_package_name (m_lexer.m_package_name);
-        fcn->mark_as_system_fcn_file ();
-
-        if (m_fcn_file_from_relative_lookup)
-          fcn->mark_relative ();
-
-        if (m_lexer.m_parsing_class_method)
-          {
-            if (m_curr_class_name == id_name)
-              fcn->mark_as_class_constructor ();
-            else
-              fcn->mark_as_class_method ();
-
-            fcn->stash_dispatch_class (m_curr_class_name);
-          }
-
-        std::string nm = fcn->fcn_file_name ();
-
-        sys::file_stat fs (nm);
-
-        if (fs && fs.is_newer (now))
-          warning_with_id ("Octave:future-time-stamp",
-                           "time stamp for '%s' is in the future", nm.c_str ());
-      }
-    else if (! input_from_tmp_history_file
-             && ! m_lexer.m_force_script
-             && m_lexer.m_reading_script_file
-             && m_lexer.m_fcn_file_name == id_name)
-      {
-        warning ("function '%s' defined within script file '%s'",
-                 id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ());
-      }
-
-    fcn->stash_function_name (id_name);
-
-    // Record help text for functions other than nested functions.
-    // We cannot currently record help for nested functions (bug #46008)
-    // because the doc_string of the outermost function is read first,
-    // whereas this function is called for the innermost function first.
-    // We could have a stack of help_text in lexer.
-    if (! m_lexer.m_help_text.empty () && m_curr_fcn_depth == 1)
-      {
-        fcn->document (m_lexer.m_help_text);
-
-        m_lexer.m_help_text = "";
-      }
-
-    if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 1
-        && ! m_parsing_subfunctions)
-      m_primary_fcn_ptr = fcn;
-
-    return fcn;
-  }
-
-  tree_statement *
-  base_parser::make_end (const std::string& type, bool eof, int l, int c)
-  {
-    return make_statement (new tree_no_op_command (type, eof, l, c));
-  }
-
-  tree_function_def *
-  base_parser::finish_function (tree_parameter_list *ret_list,
-                                octave_user_function *fcn,
-                                comment_list *lc,
-                                int l, int c)
-  {
-    tree_function_def *retval = nullptr;
-
-    if (ret_list)
-      ret_list->mark_as_formal_parameters ();
-
-    if (fcn)
-      {
-        std::string nm = fcn->name ();
-        std::string file = fcn->fcn_file_name ();
-
-        std::string tmp = nm;
-        if (! file.empty ())
-          tmp += ": " + file;
-
-        symbol_scope fcn_scope = fcn->scope ();
-        fcn_scope.cache_name (tmp);
-
-        if (lc)
-          fcn->stash_leading_comment (lc);
-
-        fcn->define_ret_list (ret_list);
-
-        if (m_curr_fcn_depth > 1 || m_parsing_subfunctions)
-          {
-            fcn->stash_fcn_location (l, c);
-            fcn->stash_parent_fcn_name (m_lexer.m_fcn_file_name);
-
-            octave_value ov_fcn (fcn);
-
-            if (m_endfunction_found && m_function_scopes.size () > 1)
-              {
-                fcn->mark_as_nested_function ();
-                fcn_scope.mark_nested ();
-
-                symbol_scope pscope = m_function_scopes.parent_scope ();
-                fcn_scope.set_parent (pscope);
-                pscope.install_nestfunction (nm, ov_fcn, fcn_scope);
-              }
-            else
-              {
-                fcn->mark_as_subfunction ();
-                m_subfunction_names.push_back (nm);
-                fcn_scope.set_parent (m_primary_fcn_scope);
-                m_primary_fcn_scope.install_subfunction (nm, ov_fcn);
-              }
-          }
-
-        if (m_curr_fcn_depth == 1)
-          fcn_scope.update_nest ();
-
-        if (! m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 1)
-          {
-            // We are either reading a script file or defining a function
-            // at the command line, so this definition creates a
-            // tree_function object that is placed in the parse tree.
-            // Otherwise, it is just inserted in the symbol table,
-            // either as a subfunction or nested function (see above),
-            // or as the primary function for the file, via
-            // m_primary_fcn_ptr (see also load_fcn_from_file,,
-            // parse_fcn_file, and
-            // fcn_info::fcn_info_rep::find_user_function).
-
-            if (m_lexer.m_buffer_function_text)
-              {
-                fcn->cache_function_text (m_lexer.m_function_text,
-                                          fcn->time_parsed ());
-                m_lexer.m_buffer_function_text = false;
-              }
-
-            retval = new tree_function_def (fcn);
-          }
-      }
-
-    return retval;
-  }
-
-  void
-  base_parser::recover_from_parsing_function (void)
-  {
-    m_lexer.m_symtab_context.pop ();
-
-    if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 1
-        && ! m_parsing_subfunctions)
-      m_parsing_subfunctions = true;
-
-    m_curr_fcn_depth--;
-    m_function_scopes.pop ();
-
-    m_lexer.m_defining_func--;
-    m_lexer.m_parsed_function_name.pop ();
-    m_lexer.m_looking_at_return_list = false;
-    m_lexer.m_looking_at_parameter_list = false;
-  }
-
-  tree_funcall *
-  base_parser::make_superclass_ref (const std::string& method_nm,
-                                    const std::string& class_nm)
-  {
-    octave_value_list args;
-
-    args(1) = class_nm;
-    args(0) = method_nm;
-
-    symbol_table& symtab
-      = __get_symbol_table__ ("base_parser::make_superclass_ref");
-
-    octave_value fcn
-      = symtab.find_built_in_function ("__superclass_reference__");
-
-    return new tree_funcall (fcn, args);
-  }
-
-  tree_funcall *
-  base_parser::make_meta_class_query (const std::string& class_nm)
-  {
-    octave_value_list args;
-
-    args(0) = class_nm;
-
-    symbol_table& symtab
-      = __get_symbol_table__ ("base_parser::make_meta_class_query");
-
-    octave_value fcn
-      = symtab.find_built_in_function ("__meta_class_query__");
-
-    return new tree_funcall (fcn, args);
-  }
-
-  // A CLASSDEF block defines a class that has a constructor and other
-  // methods, but it is not an executable command.  Parsing the block
-  // makes some changes in the symbol table (inserting the constructor
-  // and methods, and adding to the list of known objects) and creates
-  // a parse tree containing meta information about the class.
-
-  tree_classdef *
-  base_parser::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)
-  {
-    tree_classdef *retval = nullptr;
-
-    m_lexer.m_symtab_context.pop ();
-
-    std::string cls_name = id->name ();
-
-    std::string nm = m_lexer.m_fcn_file_name;
-
-    size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ());
-
-    if (pos != std::string::npos)
-      nm = m_lexer.m_fcn_file_name.substr (pos+1);
-
-    if (nm != cls_name)
-      {
-        delete a;
-        delete id;
-        delete sc;
-        delete body;
-
-        bison_error ("invalid classdef definition, the class name must match the filename");
-
-      }
-    else
-      {
-        if (end_token_ok (end_tok, token::classdef_end))
-          {
-            comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-            int l = tok_val->line ();
-            int c = tok_val->column ();
-
-            if (! body)
-              body = new tree_classdef_body ();
-
-            retval = new tree_classdef (a, id, sc, body, lc, tc,
-                                        m_curr_package_name, l, c);
-          }
-        else
-          {
-            delete a;
-            delete id;
-            delete sc;
-            delete body;
-
-            end_token_error (end_tok, token::switch_end);
-          }
-      }
-
-    return retval;
-  }
-
-  tree_classdef_properties_block *
-  base_parser::make_classdef_properties_block (token *tok_val,
-                                               tree_classdef_attribute_list *a,
-                                               tree_classdef_property_list *plist,
-                                               token *end_tok,
-                                               comment_list *lc)
-  {
-    tree_classdef_properties_block *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::properties_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = tok_val->line ();
-        int c = tok_val->column ();
-
-        if (! plist)
-          plist = new tree_classdef_property_list ();
-
-        retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c);
-      }
-    else
-      {
-        delete a;
-        delete plist;
-
-        end_token_error (end_tok, token::properties_end);
-      }
-
-    return retval;
-  }
-
-  tree_classdef_methods_block *
-  base_parser::make_classdef_methods_block (token *tok_val,
-                                            tree_classdef_attribute_list *a,
-                                            tree_classdef_methods_list *mlist,
-                                            token *end_tok,
-                                            comment_list *lc)
-  {
-    tree_classdef_methods_block *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::methods_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = tok_val->line ();
-        int c = tok_val->column ();
-
-        if (! mlist)
-          mlist = new tree_classdef_methods_list ();
-
-        retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c);
-      }
-    else
-      {
-        delete a;
-        delete mlist;
-
-        end_token_error (end_tok, token::methods_end);
-      }
-
-    return retval;
-  }
-
-  tree_classdef_events_block *
-  base_parser::make_classdef_events_block (token *tok_val,
-                                           tree_classdef_attribute_list *a,
-                                           tree_classdef_events_list *elist,
-                                           token *end_tok,
-                                           comment_list *lc)
-  {
-    tree_classdef_events_block *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::events_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = tok_val->line ();
-        int c = tok_val->column ();
-
-        if (! elist)
-          elist = new tree_classdef_events_list ();
-
-        retval = new tree_classdef_events_block (a, elist, lc, tc, l, c);
-      }
-    else
-      {
-        delete a;
-        delete elist;
-
-        end_token_error (end_tok, token::events_end);
-      }
-
-    return retval;
-  }
-
-  tree_classdef_enum_block *
-  base_parser::make_classdef_enum_block (token *tok_val,
-                                         tree_classdef_attribute_list *a,
-                                         tree_classdef_enum_list *elist,
-                                         token *end_tok,
-                                         comment_list *lc)
-  {
-    tree_classdef_enum_block *retval = nullptr;
-
-    if (end_token_ok (end_tok, token::enumeration_end))
-      {
-        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
-
-        int l = tok_val->line ();
-        int c = tok_val->column ();
-
-        if (! elist)
-          elist = new tree_classdef_enum_list ();
-
-        retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c);
-      }
-    else
-      {
-        delete a;
-        delete elist;
-
-        end_token_error (end_tok, token::enumeration_end);
-      }
-
-    return retval;
-  }
-
-  octave_user_function*
-  base_parser::start_classdef_external_method (tree_identifier *id,
-                                               tree_parameter_list *pl)
-  {
-    octave_user_function* retval = nullptr;
-
-    // External methods are only allowed within @-folders. In this case,
-    // m_curr_class_name will be non-empty.
-
-    if (! m_curr_class_name.empty ())
-      {
-
-        std::string mname = id->name ();
-
-        // Methods that cannot be declared outside the classdef file:
-        // - methods with '.' character (e.g. property accessors)
-        // - class constructor
-        // - `delete'
-
-        if (mname.find_first_of (".") == std::string::npos
-            && mname != "delete"
-            && mname != m_curr_class_name)
-          {
-            // Create a dummy function that is used until the real method
-            // is loaded.
-
-            retval = new octave_user_function (symbol_scope (), pl);
-
-            retval->stash_function_name (mname);
-
-            int l = id->line ();
-            int c = id->column ();
-
-            retval->stash_fcn_location (l, c);
-          }
-        else
-          bison_error ("invalid external method declaration, an external "
-                       "method cannot be the class constructor, `delete' "
-                       "or have a dot (.) character in its name");
-      }
-    else
-      bison_error ("external methods are only allowed in @-folders");
-
-    if (! retval)
-      delete id;
-
-    return retval;
-  }
-
-  tree_function_def *
-  base_parser::finish_classdef_external_method (octave_user_function *fcn,
-                                                tree_parameter_list *ret_list,
-                                                comment_list *cl)
-  {
-    if (ret_list)
-      fcn->define_ret_list (ret_list);
-
-    if (cl)
-      fcn->stash_leading_comment (cl);
-
-    int l = fcn->beginning_line ();
-    int c = fcn->beginning_column ();
-
-    return new tree_function_def (fcn, l, c);
-  }
-
-  void
-  base_parser::finish_classdef_file (tree_classdef *cls,
-                                     tree_statement_list *local_fcns)
-  {
-    if (m_lexer.m_reading_classdef_file)
-      m_classdef_object = cls;
-
-    if (local_fcns)
-      {
-        symbol_table& symtab
-          = __get_symbol_table__ ("base_parser::finish_classdef_file");
-
-        for (tree_statement *elt : *local_fcns)
-          {
-            tree_command *cmd = elt->command ();
-
-            tree_function_def *fcn_def
-              = dynamic_cast<tree_function_def *> (cmd);
-
-            octave_value ov_fcn = fcn_def->function ();
-            octave_function *fcn = ov_fcn.function_value ();
-            std::string nm = fcn->name ();
-            std::string file = fcn->fcn_file_name ();
-
-            symtab.install_local_function (nm, ov_fcn, file);
-          }
-
-        delete local_fcns;
-      }
-  }
-
-  // Make an index expression.
-
-  tree_index_expression *
-  base_parser::make_index_expression (tree_expression *expr,
-                                      tree_argument_list *args,
-                                      char type)
-  {
-    tree_index_expression *retval = nullptr;
-
-    if (args && args->has_magic_tilde ())
-      {
-        delete expr;
-        delete args;
-
-        bison_error ("invalid use of empty argument (~) in index expression");
-      }
-    else
-      {
-        int l = expr->line ();
-        int c = expr->column ();
-
-        if (! expr->is_postfix_indexed ())
-          expr->set_postfix_index (type);
-
-        if (expr->is_index_expression ())
-          {
-            tree_index_expression *tmp =
-              static_cast<tree_index_expression *> (expr);
-
-            tmp->append (args, type);
-
-            retval = tmp;
-          }
-        else
-          retval = new tree_index_expression (expr, args, l, c, type);
-      }
-
-    return retval;
-  }
-
-  // Make an indirect reference expression.
-
-  tree_index_expression *
-  base_parser::make_indirect_ref (tree_expression *expr,
-                                  const std::string& elt)
-  {
-    tree_index_expression *retval = nullptr;
-
-    int l = expr->line ();
-    int c = expr->column ();
-
-    if (! expr->is_postfix_indexed ())
-      expr->set_postfix_index ('.');
-
-    if (expr->is_index_expression ())
-      {
-        tree_index_expression *tmp = static_cast<tree_index_expression *> (expr);
-
-        tmp->append (elt);
-
-        retval = tmp;
-      }
-    else
-      retval = new tree_index_expression (expr, elt, l, c);
-
-    m_lexer.m_looking_at_indirect_ref = false;
-
-    return retval;
-  }
-
-  // Make an indirect reference expression with dynamic field name.
-
-  tree_index_expression *
-  base_parser::make_indirect_ref (tree_expression *expr,
-                                  tree_expression *elt)
-  {
-    tree_index_expression *retval = nullptr;
-
-    int l = expr->line ();
-    int c = expr->column ();
-
-    if (! expr->is_postfix_indexed ())
-      expr->set_postfix_index ('.');
-
-    if (expr->is_index_expression ())
-      {
-        tree_index_expression *tmp = static_cast<tree_index_expression *> (expr);
-
-        tmp->append (elt);
-
-        retval = tmp;
-      }
-    else
-      retval = new tree_index_expression (expr, elt, l, c);
-
-    m_lexer.m_looking_at_indirect_ref = false;
-
-    return retval;
-  }
-
-  // Make a declaration command.
-
-  tree_decl_command *
-  base_parser::make_decl_command (int tok, token *tok_val,
-                                  tree_decl_init_list *lst)
-  {
-    tree_decl_command *retval = nullptr;
-
-    int l = tok_val->line ();
-    int c = tok_val->column ();
-
-    if (lst)
-      m_lexer.mark_as_variables (lst->variable_names ());
-
-    switch (tok)
-      {
-      case GLOBAL:
-        {
-          retval = new tree_decl_command ("global", lst, l, c);
-          retval->mark_global ();
-        }
-        break;
-
-      case PERSISTENT:
-        if (m_curr_fcn_depth > 0)
-          {
-            retval = new tree_decl_command ("persistent", lst, l, c);
-            retval->mark_persistent ();
-          }
-        else
-          {
-            if (m_lexer.m_reading_script_file)
-              warning ("ignoring persistent declaration near line %d of file '%s'",
-                       l, m_lexer.m_fcn_file_full_name.c_str ());
-            else
-              warning ("ignoring persistent declaration near line %d", l);
-          }
-        break;
-
-      default:
-        panic_impossible ();
-        break;
-      }
-
-    return retval;
-  }
-
-  bool
-  base_parser::validate_param_list (tree_parameter_list *lst,
-                                    tree_parameter_list::in_or_out type)
-  {
-    std::set<std::string> dict;
-
-    for (tree_decl_elt *elt : *lst)
-      {
-        tree_identifier *id = elt->ident ();
-
-        if (id)
-          {
-            std::string name = id->name ();
-
-            if (id->is_black_hole ())
-              {
-                if (type != tree_parameter_list::in)
-                  {
-                    bison_error ("invalid use of ~ in output list");
-                    return false;
-                  }
-              }
-            else if (dict.find (name) != dict.end ())
-              {
-                bison_error ("'" + name
-                             + "' appears more than once in parameter list");
-                return false;
-              }
-            else
-              dict.insert (name);
-          }
-      }
-
-    std::string va_type = (type == tree_parameter_list::in
-                           ? "varargin" : "varargout");
-
-    size_t len = lst->length ();
-
-    if (len > 0)
-      {
-        tree_decl_elt *elt = lst->back ();
-
-        tree_identifier *id = elt->ident ();
-
-        if (id && id->name () == va_type)
-          {
-            if (len == 1)
-              lst->mark_varargs_only ();
-            else
-              lst->mark_varargs ();
-
-            tree_parameter_list::iterator p = lst->end ();
-            --p;
-            delete *p;
-            lst->erase (p);
-          }
-      }
-
-    return true;
-  }
-
-  bool
-  base_parser::validate_array_list (tree_expression *e)
-  {
-    bool retval = true;
-
-    tree_array_list *al = dynamic_cast<tree_array_list *> (e);
-
-    for (tree_argument_list* row : *al)
-      {
-        if (row && row->has_magic_tilde ())
-          {
-            retval = false;
-
-            if (e->is_matrix ())
-              bison_error ("invalid use of tilde (~) in matrix expression");
-            else
-              bison_error ("invalid use of tilde (~) in cell expression");
-
-            break;
-          }
-      }
-
-    return retval;
-  }
-
-  tree_argument_list *
-  base_parser::validate_matrix_for_assignment (tree_expression *e)
-  {
-    tree_argument_list *retval = nullptr;
-
-    if (e->is_constant ())
-      {
-        tree_evaluator& tw
-          = __get_evaluator__ ("validate_matrix_for_assignment");
-
-        octave_value ov = tw.evaluate (e);
-
-        delete e;
-
-        if (ov.isempty ())
-          bison_error ("invalid empty left hand side of assignment");
-        else
-          bison_error ("invalid constant left hand side of assignment");
-      }
-    else
-      {
-        bool is_simple_assign = true;
-
-        tree_argument_list *tmp = nullptr;
-
-        if (e->is_matrix ())
-          {
-            tree_matrix *mat = dynamic_cast<tree_matrix *> (e);
-
-            if (mat && mat->size () == 1)
-              {
-                tmp = mat->front ();
-                mat->pop_front ();
-                delete e;
-                is_simple_assign = false;
-              }
-          }
-        else
-          tmp = new tree_argument_list (e);
-
-        if (tmp && tmp->is_valid_lvalue_list ())
-          {
-            m_lexer.mark_as_variables (tmp->variable_names ());
-            retval = tmp;
-          }
-        else
-          {
-            delete tmp;
-
-            bison_error ("invalid left hand side of assignment");
-          }
-
-        if (retval && is_simple_assign)
-          retval->mark_as_simple_assign_lhs ();
-      }
-
-    return retval;
-  }
-
-  // Finish building an array_list.
-
-  tree_expression *
-  base_parser::finish_array_list (tree_array_list *array_list)
-  {
-    tree_expression *retval = array_list;
-
-    unwind_protect frame;
-
-    frame.protect_var (discard_error_messages);
-    frame.protect_var (discard_warning_messages);
-
-    discard_error_messages = true;
-    discard_warning_messages = true;
-
-    if (array_list->all_elements_are_constant ())
-      {
-        try
-          {
-            tree_evaluator& tw
-              = __get_evaluator__ ("finish_array_list");
-
-            octave_value tmp = tw.evaluate (array_list);
-
-            tree_constant *tc_retval
-              = new tree_constant (tmp, array_list->line (),
-                                   array_list->column ());
-
-            std::ostringstream buf;
-
-            tree_print_code tpc (buf);
-
-            array_list->accept (tpc);
-
-            tc_retval->stash_original_text (buf.str ());
-
-            delete array_list;
-
-            retval = tc_retval;
-          }
-        catch (const execution_exception&)
-          {
-            interpreter::recover_from_exception ();
-          }
-      }
-
-    return retval;
-  }
-
-  // Finish building a matrix list.
-
-  tree_expression *
-  base_parser::finish_matrix (tree_matrix *m)
-  {
-    return (m
-            ? finish_array_list (m)
-            : new tree_constant (octave_null_matrix::instance));
-  }
-
-  // Finish building a cell list.
-
-  tree_expression *
-  base_parser::finish_cell (tree_cell *c)
-  {
-    return (c
-            ? finish_array_list (c)
-            : new tree_constant (octave_value (Cell ())));
-  }
-
-  void
-  base_parser::maybe_warn_missing_semi (tree_statement_list *t)
-  {
-    if (m_curr_fcn_depth > 0)
-      {
-        tree_statement *tmp = t->back ();
-
-        if (tmp->is_expression ())
-          warning_with_id
-            ("Octave:missing-semicolon",
-             "missing semicolon near line %d, column %d in file '%s'",
-             tmp->line (), tmp->column (), m_lexer.m_fcn_file_full_name.c_str ());
-      }
-  }
-
-  tree_statement_list *
-  base_parser::set_stmt_print_flag (tree_statement_list *list,
-                                    char sep, bool warn_missing_semi)
-  {
-    tree_statement *tmp = list->back ();
-
-    switch (sep)
-      {
-      case ';':
-        tmp->set_print_flag (false);
-        break;
-
-      case 0:
-      case ',':
-      case '\n':
-        tmp->set_print_flag (true);
-        if (warn_missing_semi)
-          maybe_warn_missing_semi (list);
-        break;
-
-      default:
-        warning ("unrecognized separator type!");
-        break;
-      }
-
-    // Even if a statement is null, we add it to the list then remove it
-    // here so that the print flag is applied to the correct statement.
-
-    if (tmp->is_null_statement ())
-      {
-        list->pop_back ();
-        delete tmp;
-      }
-
-    return list;
-  }
-
-  // Finish building a statement.
-  template <typename T>
-  tree_statement *
-  base_parser::make_statement (T *arg)
-  {
-    comment_list *comment = m_lexer.get_comment ();
-
-    return new tree_statement (arg, comment);
-  }
-
-  tree_statement_list *
-  base_parser::make_statement_list (tree_statement *stmt)
-  {
-    return new tree_statement_list (stmt);
-  }
-
-  tree_statement_list *
-  base_parser::append_statement_list (tree_statement_list *list,
-                                      char sep, tree_statement *stmt,
-                                      bool warn_missing_semi)
-  {
-    set_stmt_print_flag (list, sep, warn_missing_semi);
-
-    list->append (stmt);
-
-    return list;
-  }
-
-  void
-  base_parser::bison_error (const std::string& str, int l, int c)
-  {
-    int err_line = l < 0 ? m_lexer.m_input_line_number : l;
-    int err_col = c < 0 ? m_lexer.m_current_input_column - 1 : c;
-
-    std::ostringstream output_buf;
-
-    if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_script_file
-        || m_lexer.m_reading_classdef_file)
-      output_buf << "parse error near line " << err_line
-                 << " of file " << m_lexer.m_fcn_file_full_name;
-    else
-      output_buf << "parse error:";
-
-    if (str != "parse error")
-      output_buf << "\n\n  " << str;
-
-    output_buf << "\n\n";
-
-    std::string curr_line = m_lexer.m_current_input_line;
-
-    if (! curr_line.empty ())
-      {
-        size_t len = curr_line.length ();
-
-        if (curr_line[len-1] == '\n')
-          curr_line.resize (len-1);
-
-        // Print the line, maybe with a pointer near the error token.
-
-        output_buf << ">>> " << curr_line << "\n";
-
-        if (err_col == 0)
-          err_col = len;
-
-        for (int i = 0; i < err_col + 3; i++)
-          output_buf << " ";
-
-        output_buf << "^";
-      }
-
-    output_buf << "\n";
-
-    m_parse_error_msg = output_buf.str ();
-  }
-
-  int
-  parser::run (void)
-  {
-    int status = -1;
-
-    yypstate *pstate = static_cast<yypstate *> (m_parser_state);
-
-    try
-      {
-        status = octave_pull_parse (pstate, *this);
-      }
-    catch (execution_exception& e)
-      {
-        std::string file = m_lexer.m_fcn_file_full_name;
-
-        if (file.empty ())
-          error (e, "parse error");
-        else
-          error (e, "parse error in %s", file.c_str ());
-      }
-    catch (const exit_exception&)
-      {
-        throw;
-      }
-    catch (interrupt_exception &)
-      {
-        throw;
-      }
-    catch (...)
-      {
-        std::string file = m_lexer.m_fcn_file_full_name;
-
-        if (file.empty ())
-          error ("unexpected exception while parsing input");
-        else
-          error ("unexpected exception while parsing %s", file.c_str ());
-      }
-
-    if (status != 0)
-      parse_error ("%s", m_parse_error_msg.c_str ());
-
-    return status;
-  }
-
-  // Parse input from INPUT.  Pass TRUE for EOF if the end of INPUT should
-  // finish the parse.
-
-  int
-  push_parser::run (const std::string& input, bool eof)
-  {
-    int status = -1;
-
-    dynamic_cast<push_lexer&> (m_lexer).append_input (input, eof);
-
-    do
-      {
-        YYSTYPE lval;
-
-        int token = octave_lex (&lval, m_lexer.m_scanner);
-
-        if (token < 0)
-          {
-            if (! eof && m_lexer.at_end_of_buffer ())
-              {
-                status = -1;
-                break;
-              }
-          }
-
-        yypstate *pstate = static_cast<yypstate *> (m_parser_state);
-
-        try
-          {
-            status = octave_push_parse (pstate, token, &lval, *this);
-          }
-        catch (execution_exception& e)
-          {
-            std::string file = m_lexer.m_fcn_file_full_name;
-
-            if (file.empty ())
-              error (e, "parse error");
-            else
-              error (e, "parse error in %s", file.c_str ());
-          }
-        catch (const exit_exception&)
-          {
-            throw;
-          }
-        catch (interrupt_exception &)
-          {
-            throw;
-          }
-        catch (...)
-          {
-            std::string file = m_lexer.m_fcn_file_full_name;
-
-            if (file.empty ())
-              error ("unexpected exception while parsing input");
-            else
-              error ("unexpected exception while parsing %s", file.c_str ());
-          }
-      }
-    while (status == YYPUSH_MORE);
-
-    if (status != 0)
-      parse_error ("%s", m_parse_error_msg.c_str ());
-
-    return status;
-  }
-}
-
-static void
-safe_fclose (FILE *f)
-{
-  if (f)
-    fclose (static_cast<FILE *> (f));
-}
-
-static octave_value
-parse_fcn_file (const std::string& full_file, const std::string& file,
-                const std::string& dir_name, const std::string& dispatch_type,
-                const std::string& package_name, bool require_file,
-                bool force_script, bool autoload, bool relative_lookup,
-                const std::string& warn_for)
-{
-  octave_value retval;
-
-  octave::unwind_protect frame;
-
-  octave_function *fcn_ptr = nullptr;
-
-  // Open function file and parse.
-
-  FILE *in_stream = octave::command_editor::get_input_stream ();
-
-  frame.add_fcn (octave::command_editor::set_input_stream, in_stream);
-
-  frame.add_fcn (octave::command_history::ignore_entries,
-                 octave::command_history::ignoring_entries ());
-
-  octave::command_history::ignore_entries ();
-
-  FILE *ffile = nullptr;
-
-  if (! full_file.empty ())
-    ffile = std::fopen (full_file.c_str (), "rb");
-
-  if (ffile)
-    {
-      frame.add_fcn (safe_fclose, ffile);
-
-      octave::parser parser (ffile);
-
-      parser.m_curr_class_name = dispatch_type;
-      parser.m_curr_package_name = package_name;
-      parser.m_autoloading = autoload;
-      parser.m_fcn_file_from_relative_lookup = relative_lookup;
-
-      parser.m_lexer.m_force_script = force_script;
-      parser.m_lexer.prep_for_file ();
-      parser.m_lexer.m_parsing_class_method = ! dispatch_type.empty ();
-
-      parser.m_lexer.m_fcn_file_name = file;
-      parser.m_lexer.m_fcn_file_full_name = full_file;
-      parser.m_lexer.m_dir_name = dir_name;
-      parser.m_lexer.m_package_name = package_name;
-
-      int status = parser.run ();
-
-      fcn_ptr = parser.m_primary_fcn_ptr;
-
-      if (status == 0)
-        {
-          if (parser.m_lexer.m_reading_classdef_file
-              && parser.m_classdef_object)
-            {
-              // Convert parse tree for classdef object to
-              // meta.class info (and stash it in the symbol
-              // table?).  Return pointer to constructor?
-
-              if (fcn_ptr)
-                panic_impossible ();
-
-              bool is_at_folder = ! dispatch_type.empty ();
-
-              octave::interpreter& interp
-                = octave::__get_interpreter__ ("parse_fcn_file");
-
-              try
-                {
-                  fcn_ptr = parser.m_classdef_object->make_meta_class (interp, is_at_folder);
-                }
-              catch (const octave::execution_exception&)
-                {
-                  delete parser.m_classdef_object;
-                  throw;
-                }
-
-              if (fcn_ptr)
-                retval = octave_value (fcn_ptr);
-
-              delete parser.m_classdef_object;
-
-              parser.m_classdef_object = nullptr;
-            }
-          else if (fcn_ptr)
-            {
-              retval = octave_value (fcn_ptr);
-
-              fcn_ptr->maybe_relocate_end ();
-
-              if (parser.m_parsing_subfunctions)
-                {
-                  if (! parser.m_endfunction_found)
-                    parser.m_subfunction_names.reverse ();
-
-                  fcn_ptr->stash_subfunction_names (parser.m_subfunction_names);
-                }
-            }
-        }
-      else
-        error ("parse error while reading file %s", full_file.c_str ());
-    }
-  else if (require_file)
-    error ("no such file, '%s'", full_file.c_str ());
-  else if (! warn_for.empty ())
-    error ("%s: unable to open file '%s'", warn_for.c_str (),
-           full_file.c_str ());
-
-  return retval;
-}
-
-namespace octave
-{
-  std::string
-  get_help_from_file (const std::string& nm, bool& symbol_found,
-                      std::string& full_file)
-  {
-    std::string retval;
-
-    full_file = fcn_file_in_path (nm);
-
-    std::string file = full_file;
-
-    size_t file_len = file.length ();
-
-    if ((file_len > 4 && file.substr (file_len-4) == ".oct")
-        || (file_len > 4 && file.substr (file_len-4) == ".mex")
-        || (file_len > 2 && file.substr (file_len-2) == ".m"))
-      {
-        file = sys::env::base_pathname (file);
-        file = file.substr (0, file.find_last_of ('.'));
-
-        size_t pos = file.find_last_of (sys::file_ops::dir_sep_str ());
-        if (pos != std::string::npos)
-          file = file.substr (pos+1);
-      }
-
-    if (! file.empty ())
-      {
-        symbol_found = true;
-
-        octave_value ov_fcn
-          = parse_fcn_file (full_file, file, "", "", "", true,
-                            false, false, false, "");
-
-        if (ov_fcn.is_defined ())
-          {
-            octave_function *fcn = ov_fcn.function_value ();
-
-            if (fcn)
-              retval = fcn->doc_string ();
-          }
-      }
-
-    return retval;
-  }
-
-  std::string
-  get_help_from_file (const std::string& nm, bool& symbol_found)
-  {
-    std::string file;
-    return get_help_from_file (nm, symbol_found, file);
-  }
-
-  std::string
-  lookup_autoload (const std::string& nm)
-  {
-    std::string retval;
-
-    typedef std::map<std::string, std::string>::const_iterator am_iter;
-
-    am_iter p = autoload_map.find (nm);
-
-    if (p != autoload_map.end ())
-      {
-        load_path& lp = __get_load_path__ ("lookup_autoload");
-
-        retval = lp.find_file (p->second);
-      }
-
-    return retval;
-  }
-
-  string_vector
-  autoloaded_functions (void)
-  {
-    string_vector names (autoload_map.size ());
-
-    octave_idx_type i = 0;
-    for (const auto& fcn_fname : autoload_map)
-      names[i++] = fcn_fname.first;
-
-    return names;
-  }
-
-  string_vector
-  reverse_lookup_autoload (const std::string& nm)
-  {
-    string_vector names;
-
-    for (const auto& fcn_fname : autoload_map)
-      if (nm == fcn_fname.second)
-        names.append (fcn_fname.first);
-
-    return names;
-  }
-
-  octave_value
-  load_fcn_from_file (const std::string& file_name,
-                      const std::string& dir_name,
-                      const std::string& dispatch_type,
-                      const std::string& package_name,
-                      const std::string& fcn_name, bool autoload)
-  {
-    octave_value retval;
-
-    unwind_protect frame;
-
-    std::string nm = file_name;
-
-    size_t nm_len = nm.length ();
-
-    std::string file;
-
-    bool relative_lookup = false;
-
-    file = nm;
-
-    if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
-        || (nm_len > 4 && nm.substr (nm_len-4) == ".mex")
-        || (nm_len > 2 && nm.substr (nm_len-2) == ".m"))
-      {
-        nm = sys::env::base_pathname (file);
-        nm = nm.substr (0, nm.find_last_of ('.'));
-
-        size_t pos = nm.find_last_of (sys::file_ops::dir_sep_str ());
-        if (pos != std::string::npos)
-          nm = nm.substr (pos+1);
-      }
-
-    relative_lookup = ! sys::env::absolute_pathname (file);
-
-    file = sys::env::make_absolute (file);
-
-    int len = file.length ();
-
-      dynamic_loader& dyn_loader
-        = __get_dynamic_loader__ ("~octave_mex_function");
-
-    if (len > 4 && file.substr (len-4, len-1) == ".oct")
-      {
-        if (autoload && ! fcn_name.empty ())
-          nm = fcn_name;
-
-        octave_function *tmpfcn
-          = dyn_loader.load_oct (nm, file, relative_lookup);
-
-        if (tmpfcn)
-          {
-            tmpfcn->stash_package_name (package_name);
-            retval = octave_value (tmpfcn);
-          }
-      }
-    else if (len > 4 && file.substr (len-4, len-1) == ".mex")
-      {
-        // Temporarily load m-file version of mex-file, if it exists,
-        // to get the help-string to use.
-
-        std::string doc_string;
-
-        octave_value ov_fcn
-          = parse_fcn_file (file.substr (0, len - 2), nm, dir_name,
-                            dispatch_type, package_name, false,
-                            autoload, autoload, relative_lookup, "");
-
-        if (ov_fcn.is_defined ())
-          {
-            octave_function *tmpfcn = ov_fcn.function_value ();
-
-            if (tmpfcn)
-              doc_string = tmpfcn->doc_string ();
-          }
-
-        octave_function *tmpfcn
-          = dyn_loader.load_mex (nm, file, relative_lookup);
-
-        if (tmpfcn)
-          {
-            tmpfcn->document (doc_string);
-            tmpfcn->stash_package_name (package_name);
-
-            retval = octave_value (tmpfcn);
-          }
-      }
-    else if (len > 2)
-      {
-        retval = parse_fcn_file (file, nm, dir_name, dispatch_type,
-                                 package_name, true, autoload, autoload,
-                                 relative_lookup, "");
-      }
-
-    return retval;
-  }
-}
-
-DEFMETHOD (autoload, interp, args, ,
-           doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{autoload_map} =} autoload ()
-@deftypefnx {} {} autoload (@var{function}, @var{file})
-@deftypefnx {} {} autoload (@dots{}, "remove")
-Define @var{function} to autoload from @var{file}.
-
-The second argument, @var{file}, should be an absolute filename or a file
-name in the same directory as the function or script from which the autoload
-command was run.  @var{file} @emph{should not} depend on the Octave load
-path.
-
-Normally, calls to @code{autoload} appear in PKG_ADD script files that are
-evaluated when a directory is added to Octave's load path.  To avoid having
-to hardcode directory names in @var{file}, if @var{file} is in the same
-directory as the PKG_ADD script then
-
-@example
-autoload ("foo", "bar.oct");
-@end example
-
-@noindent
-will load the function @code{foo} from the file @code{bar.oct}.  The above
-usage when @code{bar.oct} is not in the same directory, or usages such as
-
-@example
-autoload ("foo", file_in_loadpath ("bar.oct"))
-@end example
-
-@noindent
-are strongly discouraged, as their behavior may be unpredictable.
-
-With no arguments, return a structure containing the current autoload map.
-
-If a third argument @qcode{"remove"} is given, the function is cleared and
-not loaded anymore during the current Octave session.
-
-@seealso{PKG_ADD}
-@end deftypefn */)
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 1 || nargin > 3)
-    print_usage ();
-
-  if (nargin == 0)
-    {
-      Cell func_names (dim_vector (autoload_map.size (), 1));
-      Cell file_names (dim_vector (autoload_map.size (), 1));
-
-      octave_idx_type i = 0;
-      for (const auto& fcn_fname : autoload_map)
-        {
-          func_names(i) = fcn_fname.first;
-          file_names(i) = fcn_fname.second;
-
-          i++;
-        }
-
-      octave_map m;
-
-      m.assign ("function", func_names);
-      m.assign ("file", file_names);
-
-      retval = m;
-    }
-  else
-    {
-      string_vector argv = args.make_argv ("autoload");
-
-      std::string nm = argv[2];
-
-      if (! octave::sys::env::absolute_pathname (nm))
-        {
-          octave::call_stack& cs = interp.get_call_stack ();
-
-          octave_user_code *fcn = cs.caller_user_code ();
-
-          bool found = false;
-
-          if (fcn)
-            {
-              std::string fname = fcn->fcn_file_name ();
-
-              if (! fname.empty ())
-                {
-                  fname = octave::sys::env::make_absolute (fname);
-                  fname = fname.substr (0, fname.find_last_of (octave::sys::file_ops::dir_sep_str ()) + 1);
-
-                  octave::sys::file_stat fs (fname + nm);
-
-                  if (fs.exists ())
-                    {
-                      nm = fname + nm;
-                      found = true;
-                    }
-                }
-            }
-          if (! found)
-            warning_with_id ("Octave:autoload-relative-file-name",
-                             "autoload: '%s' is not an absolute filename",
-                             nm.c_str ());
-        }
-      if (nargin == 2)
-        autoload_map[argv[1]] = nm;
-      else if (nargin == 3)
-        {
-          if (argv[3] != "remove")
-            error_with_id ("Octave:invalid-input-arg",
-                           "autoload: third argument can only be 'remove'");
-
-          // Remove function from symbol table and autoload map.
-          octave::symbol_table& symtab = interp.get_symbol_table ();
-          symtab.clear_dld_function (argv[1]);
-          autoload_map.erase (argv[1]);
-        }
-    }
-
-  return retval;
-}
-
-namespace octave
-{
-  // Execute the contents of a script file.  For compatibility with
-  // Matlab, also execute a function file by calling the function it
-  // defines with no arguments and nargout = 0.
-
-  void
-  source_file (const std::string& file_name, const std::string& context,
-               bool verbose, bool require_file, const std::string& warn_for)
-  {
-    // Map from absolute name of script file to recursion level.  We
-    // use a map instead of simply placing a limit on recursion in the
-    // source_file function so that two mutually recursive scripts
-    // written as
-    //
-    //   foo1.m:
-    //   ------
-    //   foo2
-    //
-    //   foo2.m:
-    //   ------
-    //   foo1
-    //
-    // and called with
-    //
-    //   foo1
-    //
-    // (for example) will behave the same if they are written as
-    //
-    //   foo1.m:
-    //   ------
-    //   source ("foo2.m")
-    //
-    //   foo2.m:
-    //   ------
-    //   source ("foo1.m")
-    //
-    // and called with
-    //
-    //   source ("foo1.m")
-    //
-    // (for example).
-
-    static std::map<std::string, int> source_call_depth;
-
-    std::string file_full_name
-      = sys::file_ops::tilde_expand (file_name);
-
-    size_t pos
-      = file_full_name.find_last_of (sys::file_ops::dir_sep_str ());
-
-    std::string dir_name = file_full_name.substr (0, pos);
-
-    file_full_name = sys::env::make_absolute (file_full_name);
-
-    unwind_protect frame;
-
-    if (source_call_depth.find (file_full_name) == source_call_depth.end ())
-      source_call_depth[file_full_name] = -1;
-
-    frame.protect_var (source_call_depth[file_full_name]);
-
-    source_call_depth[file_full_name]++;
-
-    tree_evaluator& tw = __get_evaluator__ ("source_file");
-
-    if (source_call_depth[file_full_name] >= tw.max_recursion_depth ())
-      error ("max_recursion_depth exceeded");
-
-    if (! context.empty ())
-      {
-        call_stack& cs = __get_call_stack__ ("source_file");
-
-        if (context == "caller")
-          cs.goto_caller_frame ();
-        else if (context == "base")
-          cs.goto_base_frame ();
-        else
-          error ("source: context must be \"caller\" or \"base\"");
-
-        frame.add_method (cs, &call_stack::pop);
-      }
-
-    // Find symbol name that would be in symbol_table, if it were loaded.
-    size_t dir_end
-      = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
-    dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
-
-    size_t extension = file_name.find_last_of ('.');
-    if (extension == std::string::npos)
-      extension = file_name.length ();
-
-    std::string symbol = file_name.substr (dir_end, extension - dir_end);
-    std::string full_name = sys::canonicalize_file_name (file_name);
-
-    // Check if this file is already loaded (or in the path)
-    symbol_table& symtab = __get_symbol_table__ ("source_file");
-    octave_value ov_code = symtab.find (symbol);
-
-    // For compatibility with Matlab, accept both scripts and
-    // functions.
-
-    if (ov_code.is_user_code ())
-      {
-        octave_user_code *code = ov_code.user_code_value ();
-
-        if (! code
-            || (sys::canonicalize_file_name (code->fcn_file_name ())
-                != full_name))
-          {
-            // Wrong file, so load it below.
-            ov_code = octave_value ();
-          }
-      }
-    else
-      {
-        // Not a script, so load it below.
-        ov_code = octave_value ();
-      }
-
-    // If no symbol of this name, or the symbol is for a different
-    // file, load.
-
-    if (ov_code.is_undefined ())
-      {
-        try
-          {
-            ov_code = parse_fcn_file (file_full_name, file_name, dir_name,
-                                      "", "", require_file, true, false,
-                                      false, warn_for);
-          }
-        catch (execution_exception& e)
-          {
-            error (e, "source: error sourcing file '%s'",
-                   file_full_name.c_str ());
-          }
-      }
-
-    // Return or error if we don't have a valid script or function.
-
-    if (ov_code.is_undefined ())
-      return;
-
-    if (! ov_code.is_user_code ())
-      error ("source: %s is not a script", full_name.c_str ());
-
-    if (verbose)
-      {
-        std::cout << "executing commands from " << full_name << " ... ";
-        std::cout.flush ();
-      }
-
-    octave_user_code *code = ov_code.user_code_value ();
-
-    code->call (tw, 0, octave_value_list ());
-
-    if (verbose)
-      std::cout << "done." << std::endl;
-  }
-}
-
-DEFMETHOD (mfilename, interp, args, ,
-           doc: /* -*- texinfo -*-
-@deftypefn  {} {} mfilename ()
-@deftypefnx {} {} mfilename ("fullpath")
-@deftypefnx {} {} mfilename ("fullpathext")
-Return the name of the currently executing file.
-
-When called from outside an m-file return the empty string.
-
-Given the argument @qcode{"fullpath"}, include the directory part of the
-filename, but not the extension.
-
-Given the argument @qcode{"fullpathext"}, include the directory part of
-the filename and the extension.
-@end deftypefn */)
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  if (nargin > 1)
-    print_usage ();
-
-  std::string arg;
-
-  if (nargin == 1)
-    arg = args(0).xstring_value ("mfilename: argument must be a string");
-
-  std::string fname;
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  octave_user_code *fcn = cs.caller_user_code ();
-
-  if (fcn)
-    {
-      fname = fcn->fcn_file_name ();
-
-      if (fname.empty ())
-        fname = fcn->name ();
-    }
-
-  if (arg == "fullpathext")
-    retval = fname;
-  else
-    {
-      size_t dpos = fname.rfind (octave::sys::file_ops::dir_sep_char ());
-      size_t epos = fname.rfind ('.');
-
-      if (epos <= dpos)
-        epos = std::string::npos;
-
-      fname = (epos != std::string::npos) ? fname.substr (0, epos) : fname;
-
-      if (arg == "fullpath")
-        retval = fname;
-      else
-        retval = (dpos != std::string::npos) ? fname.substr (dpos+1) : fname;
-    }
-
-  return retval;
-}
-
-DEFUN (source, args, ,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {} source (@var{file})
-@deftypefnx {} {} source (@var{file}, @var{context})
-Parse and execute the contents of @var{file}.
-
-Without specifying @var{context}, this is equivalent to executing commands
-from a script file, but without requiring the file to be named
-@file{@var{file}.m} or to be on the execution path.
-
-Instead of the current context, the script may be executed in either the
-context of the function that called the present function
-(@qcode{"caller"}), or the top-level context (@qcode{"base"}).
-@seealso{run}
-@end deftypefn */)
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin < 1 || nargin > 2)
-    print_usage ();
-
-  std::string file_name = args(0).xstring_value ("source: FILE must be a string");
-
-  std::string context;
-
-  if (nargin == 2)
-    context = args(1).xstring_value ("source: CONTEXT must be a string");
-
-  octave::source_file (file_name, context);
-
-  return retval;
-}
-
-namespace octave
-{
-  //! Evaluate an Octave function (built-in or interpreted) and return
-  //! the list of result values.
-  //!
-  //! @param name The name of the function to call.
-  //! @param args The arguments to the function.
-  //! @param nargout The number of output arguments expected.
-  //! @return A list of output values.  The length of the list is not
-  //!         necessarily the same as @c nargout.
-
-  octave_value_list
-  feval (const std::string& name, const octave_value_list& args, int nargout)
-  {
-    octave_value_list retval;
-
-    symbol_table& symtab = __get_symbol_table__ ("feval");
-
-    octave_value fcn = symtab.find_function (name, args);
-
-    if (fcn.is_defined ())
-      {
-        tree_evaluator& tw = __get_evaluator__ ("feval");
-
-        octave_function *of = fcn.function_value ();
-
-        retval = of->call (tw, nargout, args);
-      }
-    else
-      error ("feval: function '%s' not found", name.c_str ());
-
-    return retval;
-  }
-
-  octave_value_list
-  feval (octave_function *fcn, const octave_value_list& args, int nargout)
-  {
-    octave_value_list retval;
-
-    if (fcn)
-      {
-        tree_evaluator& tw = __get_evaluator__ ("feval");
-
-        retval = fcn->call (tw, nargout, args);
-      }
-
-    return retval;
-  }
-
-  octave_value_list
-  feval (octave_value& val, const octave_value_list& args, int nargout)
-  {
-    if (val.is_function ())
-      {
-        return feval (val.function_value (), args, nargout);
-      }
-    else if (val.is_function_handle ())
-      {
-        // This covers function handles, inline functions, and anonymous
-        //  functions.
-
-        std::list<octave_value_list> arg_list;
-        arg_list.push_back (args);
-
-        return val.subsref ("(", arg_list, nargout);
-      }
-    else if (val.is_string ())
-      {
-        return feval (val.string_value (), args, nargout);
-      }
-    else
-      error ("feval: first argument must be a string, inline function, or a function handle");
-
-    return ovl ();
-  }
-}
-
-static octave_value_list
-get_feval_args (const octave_value_list& args)
-{
-  return args.slice (1, args.length () - 1, true);
-}
-
-namespace octave
-{
-  //! Evaluate an Octave function (built-in or interpreted) and return
-  //! the list of result values.
-  //!
-  //! @param args The first element of @c args is the function to call.
-  //!             It may be the name of the function as a string, a function
-  //!             handle, or an inline function.  The remaining arguments are
-  //!             passed to the function.
-  //! @param nargout The number of output arguments expected.
-  //! @return A list of output values.  The length of the list is not
-  //!         necessarily the same as @c nargout.
-
-  octave_value_list
-  feval (const octave_value_list& args, int nargout)
-  {
-    if (args.length () > 0)
-      {
-        octave_value f_arg = args(0);
-
-        octave_value_list tmp_args = get_feval_args (args);
-
-        return feval (f_arg, tmp_args, nargout);
-      }
-    else
-      error ("feval: first argument must be a string, inline function, or a function handle");
-
-    return ovl ();
-  }
-}
-
-DEFUN (feval, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} feval (@var{name}, @dots{})
-Evaluate the function named @var{name}.
-
-Any arguments after the first are passed as inputs to the named function.
-For example,
-
-@example
-@group
-feval ("acos", -1)
-     @result{} 3.1416
-@end group
-@end example
-
-@noindent
-calls the function @code{acos} with the argument @samp{-1}.
-
-The function @code{feval} can also be used with function handles of any sort
-(@pxref{Function Handles}).  Historically, @code{feval} was the only way to
-call user-supplied functions in strings, but function handles are now
-preferred due to the cleaner syntax they offer.  For example,
-
-@example
-@group
-@var{f} = @@exp;
-feval (@var{f}, 1)
-    @result{} 2.7183
-@var{f} (1)
-    @result{} 2.7183
-@end group
-@end example
-
-@noindent
-are equivalent ways to call the function referred to by @var{f}.  If it
-cannot be predicted beforehand whether @var{f} is a function handle,
-function name in a string, or inline function then @code{feval} can be used
-instead.
-@end deftypefn */)
-{
-  if (args.length () == 0)
-    print_usage ();
-
-  return octave::feval (args, nargout);
-}
-
-DEFMETHOD (builtin, interp, args, nargout,
-           doc: /* -*- texinfo -*-
-@deftypefn {} {[@dots{}] =} builtin (@var{f}, @dots{})
-Call the base function @var{f} even if @var{f} is overloaded to another
-function for the given type signature.
-
-This is normally useful when doing object-oriented programming and there is
-a requirement to call one of Octave's base functions rather than the
-overloaded one of a new class.
-
-A trivial example which redefines the @code{sin} function to be the
-@code{cos} function shows how @code{builtin} works.
-
-@example
-@group
-sin (0)
-  @result{} 0
-function y = sin (x), y = cos (x); endfunction
-sin (0)
-  @result{} 1
-builtin ("sin", 0)
-  @result{} 0
-@end group
-@end example
-@end deftypefn */)
-{
-  octave_value_list retval;
-
-  if (args.length () == 0)
-    print_usage ();
-
-  const std::string name (args(0).xstring_value ("builtin: function name (F) must be a string"));
-
-  octave::symbol_table& symtab = interp.get_symbol_table ();
-
-  octave_value fcn = symtab.builtin_find (name);
-
-  if (fcn.is_defined ())
-    retval = octave::feval (fcn.function_value (), args.splice (0, 1), nargout);
-  else
-    error ("builtin: lookup for symbol '%s' failed", name.c_str ());
-
-  return retval;
-}
-
-namespace octave
-{
-  octave_value_list
-  eval_string (const std::string& eval_str, bool silent,
-               int& parse_status, int nargout)
-  {
-    octave_value_list retval;
-
-    parser parser (eval_str);
-
-    do
-      {
-        parser.reset ();
-
-        parse_status = parser.run ();
-
-        if (parse_status == 0)
-          {
-            if (parser.m_stmt_list)
-              {
-                tree_statement *stmt = nullptr;
-
-                tree_evaluator& tw = __get_evaluator__ ("eval_string");
-
-                if (parser.m_stmt_list->length () == 1
-                    && (stmt = parser.m_stmt_list->front ())
-                    && stmt->is_expression ())
-                  {
-                    tree_expression *expr = stmt->expression ();
-
-                    if (silent)
-                      expr->set_print_flag (false);
-
-                    bool do_bind_ans = false;
-
-                    if (expr->is_identifier ())
-                      {
-                        octave::symbol_scope scope = tw.get_current_scope ();
-
-                        octave::symbol_record::context_id context
-                          = scope.current_context ();
-
-                        tree_identifier *id
-                          = dynamic_cast<tree_identifier *> (expr);
-
-                        do_bind_ans = (! id->is_variable (context));
-                      }
-                    else
-                      do_bind_ans = (! expr->is_assignment_expression ());
-
-                    retval = tw.evaluate_n (expr, nargout);
-
-                    if (do_bind_ans && ! retval.empty ())
-                      tw.bind_ans (retval(0), expr->print_result ());
-
-                    if (nargout == 0)
-                      retval = octave_value_list ();
-                  }
-                else if (nargout == 0)
-                  parser.m_stmt_list->accept (tw);
-                else
-                  error ("eval: invalid use of statement list");
-
-                if (tree_return_command::returning
-                    || tree_break_command::breaking
-                    || tree_continue_command::continuing)
-                  break;
-              }
-            else if (parser.m_lexer.m_end_of_input)
-              break;
-          }
-      }
-    while (parse_status == 0);
-
-    return retval;
-  }
-
-  octave_value
-  eval_string (const std::string& eval_str, bool silent, int& parse_status)
-  {
-    octave_value retval;
-
-    octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
-
-    if (! tmp.empty ())
-      retval = tmp(0);
-
-    return retval;
-  }
-
-  static octave_value_list
-  eval_string (const octave_value& arg, bool silent, int& parse_status,
-               int nargout)
-  {
-    std::string s = arg.xstring_value ("eval: expecting std::string argument");
-
-    return eval_string (s, silent, parse_status, nargout);
-  }
-
-  void
-  cleanup_statement_list (tree_statement_list **lst)
-  {
-    if (*lst)
-      {
-        delete *lst;
-        *lst = nullptr;
-      }
-  }
-}
-
-DEFUN (eval, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {} eval (@var{try})
-@deftypefnx {} {} eval (@var{try}, @var{catch})
-Parse the string @var{try} and evaluate it as if it were an Octave
-program.
-
-If execution fails, evaluate the optional string @var{catch}.
-
-The string @var{try} is evaluated in the current context, so any results
-remain available after @code{eval} returns.
-
-The following example creates the variable @var{A} with the approximate
-value of 3.1416 in the current workspace.
-
-@example
-eval ("A = acos(-1);");
-@end example
-
-If an error occurs during the evaluation of @var{try} then the @var{catch}
-string is evaluated, as the following example shows:
-
-@example
-@group
-eval ('error ("This is a bad example");',
-      'printf ("This error occurred:\n%s\n", lasterr ());');
-     @print{} This error occurred:
-        This is a bad example
-@end group
-@end example
-
-Programming Note: if you are only using @code{eval} as an error-capturing
-mechanism, rather than for the execution of arbitrary code strings,
-Consider using try/catch blocks or unwind_protect/unwind_protect_cleanup
-blocks instead.  These techniques have higher performance and don't
-introduce the security considerations that the evaluation of arbitrary code
-does.
-@seealso{evalin, evalc, assignin, feval}
-@end deftypefn */)
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin == 0)
-    print_usage ();
-
-  octave::unwind_protect frame;
-
-  if (nargin > 1)
-    {
-      frame.protect_var (buffer_error_messages);
-      buffer_error_messages++;
-    }
-
-  int parse_status = 0;
-
-  bool execution_error = false;
-
-  octave_value_list tmp;
-
-  try
-    {
-      tmp = octave::eval_string (args(0), nargout > 0, parse_status, nargout);
-    }
-  catch (const octave::execution_exception&)
-    {
-      octave::interpreter::recover_from_exception ();
-
-      execution_error = true;
-    }
-
-  if (nargin > 1 && (parse_status != 0 || execution_error))
-    {
-      // Set up for letting the user print any messages from
-      // errors that occurred in the first part of this eval().
-
-      buffer_error_messages--;
-
-      tmp = octave::eval_string (args(1), nargout > 0, parse_status, nargout);
-
-      if (nargout > 0)
-        retval = tmp;
-    }
-  else
-    {
-      if (nargout > 0)
-        retval = tmp;
-
-      // FIXME: we should really be rethrowing whatever exception occurred,
-      // not just throwing an execution exception.
-      if (execution_error)
-        octave_throw_execution_exception ();
-    }
-
-  return retval;
-}
-
-/*
-
-%!shared x
-%! x = 1;
-
-%!assert (eval ("x"), 1)
-%!assert (eval ("x;"))
-%!assert (eval ("x;"), 1)
-
-%!test
-%! y = eval ("x");
-%! assert (y, 1);
-
-%!test
-%! y = eval ("x;");
-%! assert (y, 1);
-
-%!test
-%! eval ("x = 1;");
-%! assert (x,1);
-
-%!test
-%! eval ("flipud = 2;");
-%! assert (flipud, 2);
-
-%!function y = __f ()
-%!  eval ("flipud = 2;");
-%!  y = flipud;
-%!endfunction
-%!assert (__f(), 2)
-
-% bug #35645
-%!test
-%! [a,] = gcd (1,2);
-%! [a,b,] = gcd (1, 2);
-
-%!error eval ("switch = 13;")
-
-*/
-
-DEFMETHOD (assignin, interp, args, ,
-           doc: /* -*- texinfo -*-
-@deftypefn {} {} assignin (@var{context}, @var{varname}, @var{value})
-Assign @var{value} to @var{varname} in context @var{context}, which
-may be either @qcode{"base"} or @qcode{"caller"}.
-@seealso{evalin}
-@end deftypefn */)
-{
-  octave_value_list retval;
-
-  if (args.length () != 3)
-    print_usage ();
-
-  std::string context = args(0).xstring_value ("assignin: CONTEXT must be a string");
-
-  octave::unwind_protect frame;
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  if (context == "caller")
-    cs.goto_caller_frame ();
-  else if (context == "base")
-    cs.goto_base_frame ();
-  else
-    error ("assignin: CONTEXT must be \"caller\" or \"base\"");
-
-  frame.add_method (cs, &octave::call_stack::pop);
-
-  std::string nm = args(1).xstring_value ("assignin: VARNAME must be a string");
-
-  if (valid_identifier (nm))
-    {
-      // Put the check here so that we don't slow down assignments
-      // generally.  Any that go through Octave's parser should have
-      // already been checked.
-
-      if (octave::is_keyword (nm))
-        error ("assignin: invalid assignment to keyword '%s'", nm.c_str ());
-
-      octave::symbol_scope scope = interp.get_current_scope ();
-
-      if (scope)
-        scope.assign (nm, args(2));
-    }
-  else
-    error ("assignin: invalid variable name in argument VARNAME");
-
-  return retval;
-}
-
-/*
-
-%!error assignin ("base", "switch", "13")
-
-*/
-
-DEFMETHOD (evalin, interp, args, nargout,
-           doc: /* -*- texinfo -*-
-@deftypefn  {} {} evalin (@var{context}, @var{try})
-@deftypefnx {} {} evalin (@var{context}, @var{try}, @var{catch})
-Like @code{eval}, except that the expressions are evaluated in the context
-@var{context}, which may be either @qcode{"caller"} or @qcode{"base"}.
-@seealso{eval, assignin}
-@end deftypefn */)
-{
-  octave_value_list retval;
-
-  int nargin = args.length ();
-
-  if (nargin < 2)
-    print_usage ();
-
-  std::string context = args(0).xstring_value ("evalin: CONTEXT must be a string");
-
-  octave::unwind_protect frame;
-
-  octave::call_stack& cs = interp.get_call_stack ();
-
-  if (context == "caller")
-    cs.goto_caller_frame ();
-  else if (context == "base")
-    cs.goto_base_frame ();
-  else
-    error ("evalin: CONTEXT must be \"caller\" or \"base\"");
-
-  frame.add_method (cs, &octave::call_stack::pop);
-
-  if (nargin > 2)
-    {
-      frame.protect_var (buffer_error_messages);
-      buffer_error_messages++;
-    }
-
-  int parse_status = 0;
-
-  bool execution_error = false;
-
-  octave_value_list tmp;
-
-  try
-    {
-      tmp = octave::eval_string (args(1), nargout > 0,
-                                 parse_status, nargout);
-    }
-  catch (const octave::execution_exception&)
-    {
-      octave::interpreter::recover_from_exception ();
-
-      execution_error = true;
-    }
-
-  if (nargin > 2 && (parse_status != 0 || execution_error))
-    {
-      // Set up for letting the user print any messages from
-      // errors that occurred in the first part of this eval().
-
-      buffer_error_messages--;
-
-      tmp = octave::eval_string (args(2), nargout > 0,
-                                 parse_status, nargout);
-
-      retval = (nargout > 0) ? tmp : octave_value_list ();
-    }
-  else
-    {
-      if (nargout > 0)
-        retval = tmp;
-
-      // FIXME: we should really be rethrowing whatever
-      // exception occurred, not just throwing an
-      // execution exception.
-      if (execution_error)
-        octave_throw_execution_exception ();
-    }
-
-  return retval;
-}
-
-static void
-maybe_print_last_error_message (bool *doit)
-{
-  if (doit && *doit)
-    // Print error message again, which was lost because of the stderr buffer
-    // Note: this keeps error_state and last_error_stack intact
-    message_with_id ("error", last_error_id ().c_str (),
-                     last_error_message ().c_str ());
-}
-
-static void
-restore_octave_stdout (std::streambuf *buf)
-{
-  octave_stdout.flush ();
-  octave_stdout.rdbuf (buf);
-}
-
-static void
-restore_octave_stderr (std::streambuf *buf)
-{
-  std::cerr.flush ();
-  std::cerr.rdbuf (buf);
-}
-
-DEFUN (evalc, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{s} =} evalc (@var{try})
-@deftypefnx {} {@var{s} =} evalc (@var{try}, @var{catch})
-Parse and evaluate the string @var{try} as if it were an Octave program,
-while capturing the output into the return variable @var{s}.
-
-If execution fails, evaluate the optional string @var{catch}.
-
-This function behaves like @code{eval}, but any output or warning messages
-which would normally be written to the console are captured and returned in
-the string @var{s}.
-
-The @code{diary} is disabled during the execution of this function.  When
-@code{system} is used, any output produced by external programs is
-@emph{not} captured, unless their output is captured by the @code{system}
-function itself.
-
-@example
-@group
-s = evalc ("t = 42"), t
-  @result{} s = t =  42
-
-  @result{} t =  42
-@end group
-@end example
-@seealso{eval, diary}
-@end deftypefn */)
-{
-  int nargin = args.length ();
-
-  if (nargin == 0 || nargin > 2)
-    print_usage ();
-
-  // redirect stdout/stderr to capturing buffer
-  std::ostringstream buffer;
-
-  std::ostream& out_stream = octave_stdout;
-  std::ostream& err_stream = std::cerr;
-
-  out_stream.flush ();
-  err_stream.flush ();
-
-  std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ());
-  std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ());
-
-  bool eval_error_occurred = true;
-
-  octave::unwind_protect frame;
-
-  frame.add_fcn (maybe_print_last_error_message, &eval_error_occurred);
-  frame.add_fcn (restore_octave_stdout, old_out_buf);
-  frame.add_fcn (restore_octave_stderr, old_err_buf);
-
-  // call standard eval function
-  octave_value_list retval;
-  int eval_nargout = std::max (0, nargout - 1);
-
-  retval = Feval (args, eval_nargout);
-  eval_error_occurred = false;
-
-  retval.prepend (buffer.str ());
-  return retval;
-}
-
-/*
-
-%!assert (evalc ("1"), "ans =  1\n")
-%!assert (evalc ("1;"), "")
-
-%!test
-%! [s, y] = evalc ("1");
-%! assert (s, "");
-%! assert (y, 1);
-
-%!test
-%! [s, y] = evalc ("1;");
-%! assert (s, "");
-%! assert (y, 1);
-
-%!test
-%! assert (evalc ("y = 2"), "y =  2\n");
-%! assert (y, 2);
-
-%!test
-%! assert (evalc ("y = 3;"), "");
-%! assert (y, 3);
-
-%!test
-%! [s, a, b] = evalc ("deal (1, 2)");
-%! assert (s, "");
-%! assert (a, 1);
-%! assert (b, 2);
-
-%!function [a, b] = __f_evalc ()
-%!  printf ("foo");
-%!  fprintf (stdout, "bar");
-%!  disp (pi);
-%!  a = 1;
-%!  b = 2;
-%!endfunction
-%!test
-%! [s, a, b] = evalc ("__f_evalc ()");
-%! assert (s, "foobar 3.1416\n");
-%! assert (a, 1);
-%! assert (b, 2);
-
-%!error <foo> (evalc ("error ('foo')"))
-%!error <bar> (evalc ("error ('foo')", "error ('bar')"))
-
-%!test
-%! warning ("off", "quiet", "local");
-%! assert (evalc ("warning ('foo')"), "warning: foo\n");
-
-%!test
-%! warning ("off", "quiet", "local");
-%! assert (evalc ("error ('foo')", "warning ('bar')"), "warning: bar\n");
-
-%!error evalc ("switch = 13;")
-
-*/
-
-DEFUN (__parser_debug_flag__, args, nargout,
-       doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{val} =} __parser_debug_flag__ ()
-@deftypefnx {} {@var{old_val} =} __parser_debug_flag__ (@var{new_val})
-Query or set the internal flag that determines whether Octave's parser
-prints debug information as it processes an expression.
-@seealso{__lexer_debug_flag__}
-@end deftypefn */)
-{
-  octave_value retval;
-
-  bool debug_flag = octave_debug;
-
-  retval = set_internal_variable (debug_flag, args, nargout,
-                                  "__parser_debug_flag__");
-
-  octave_debug = debug_flag;
-
-  return retval;
-}
-
-DEFUN (__parse_file__, args, ,
-       doc: /* -*- texinfo -*-
-@deftypefn {} {} __parse_file__ (@var{file}, @var{verbose})
-Undocumented internal function.
-@end deftypefn */)
-{
-  octave_value retval;
-
-  int nargin = args.length ();
-
-  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);
-
-  full_file = octave::sys::env::make_absolute (full_file);
-
-  std::string dir_name;
-
-  size_t file_len = file.length ();
-
-  if ((file_len > 4 && file.substr (file_len-4) == ".oct")
-      || (file_len > 4 && file.substr (file_len-4) == ".mex")
-      || (file_len > 2 && file.substr (file_len-2) == ".m"))
-    {
-      file = octave::sys::env::base_pathname (file);
-      file = file.substr (0, file.find_last_of ('.'));
-
-      size_t pos = file.find_last_of (octave::sys::file_ops::dir_sep_str ());
-      if (pos != std::string::npos)
-        {
-          dir_name = file.substr (0, pos);
-          file = file.substr (pos+1);
-        }
-    }
-
-  if (nargin == 2)
-    octave_stdout << "parsing " << full_file << std::endl;
-
-  octave_value ov_fcn
-    = parse_fcn_file (full_file, file, dir_name, "", "", true, false,
-                      false, false, "__parse_file__");
-
-  return retval;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/oct-parse.yy	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,5895 @@
+/*
+
+Copyright (C) 1993-2018 John W. Eaton
+Copyright (C) 2009 David Grundberg
+Copyright (C) 2009-2010 VZLU Prague
+Copyright (C) 2016-2018 Oliver Heimlich
+
+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/>.
+
+*/
+
+// Parser for Octave.
+
+// C decarations.
+
+%{
+
+#define YYDEBUG 1
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+
+#include <iostream>
+#include <map>
+#include <sstream>
+
+#include "Matrix.h"
+#include "cmd-edit.h"
+#include "cmd-hist.h"
+#include "file-ops.h"
+#include "file-stat.h"
+#include "oct-env.h"
+#include "oct-time.h"
+#include "quit.h"
+
+#include "Cell.h"
+#include "builtin-defun-decls.h"
+#include "call-stack.h"
+#include "defun.h"
+#include "dirfns.h"
+#include "dynamic-ld.h"
+#include "error.h"
+#include "input.h"
+#include "interpreter-private.h"
+#include "interpreter.h"
+#include "lex.h"
+#include "load-path.h"
+#include "lo-sysdep.h"
+#include "oct-hist.h"
+#include "oct-map.h"
+#include "ov-classdef.h"
+#include "ov-fcn-handle.h"
+#include "ov-usr-fcn.h"
+#include "ov-null-mat.h"
+#include "pager.h"
+#include "parse.h"
+#include "pt-all.h"
+#include "pt-eval.h"
+#include "pt-funcall.h"
+#include "symtab.h"
+#include "token.h"
+#include "unwind-prot.h"
+#include "utils.h"
+#include "variables.h"
+
+// oct-parse.h must be included after pt-all.h
+#include "oct-parse.h"
+
+extern int octave_lex (YYSTYPE *, void *);
+
+// List of autoloads (function -> file mapping).
+static std::map<std::string, std::string> autoload_map;
+
+// Forward declarations for some functions defined at the bottom of
+// the file.
+
+static void yyerror (octave::base_parser& parser, const char *s);
+
+#define lexer parser.m_lexer
+#define scanner lexer.m_scanner
+
+#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+   // Disable this warning for code that is generated by Bison,
+   // including grammar rules.  Push the current state so we can
+   // restore the warning state prior to functions we define at
+   // the bottom of the file.
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+%}
+
+// Bison declarations.
+
+// The grammar currently has 9 shift/reduce conflicts.  Ensure that
+// we notice if that number changes.
+
+%expect 9
+
+// We are using the pure parser interface and the reentrant lexer
+// interface but the Octave parser and lexer are NOT properly
+// reentrant because both still use many global variables.  It should be
+// safe to create a parser object and call it while another parser
+// object is active (to parse a callback function while the main
+// interactive parser is waiting for input, for example) if you take
+// care to properly save and restore (typically with an unwind_protect
+// object) relevant global values before and after the nested call.
+
+%define api.pure
+// No spaces inside the braces for the prefix and push-pull definitions!
+%define api.prefix {octave_}
+%define api.push-pull both
+%parse-param { octave::base_parser& parser }
+%lex-param { void *lexer.scanner }
+
+%union
+{
+  int dummy_type;
+
+  // The type of the basic tokens returned by the lexer.
+  octave::token *tok_val;
+
+  // Comment strings that we need to deal with mid-rule.
+  octave::comment_list *comment_type;
+
+  // Types for the nonterminals we generate.
+  char punct_type;
+  octave::tree *tree_type;
+  octave::tree_matrix *tree_matrix_type;
+  octave::tree_cell *tree_cell_type;
+  octave::tree_expression *tree_expression_type;
+  octave::tree_constant *tree_constant_type;
+  octave::tree_fcn_handle *tree_fcn_handle_type;
+  octave::tree_funcall *tree_funcall_type;
+  octave::tree_function_def *tree_function_def_type;
+  octave::tree_anon_fcn_handle *tree_anon_fcn_handle_type;
+  octave::tree_identifier *tree_identifier_type;
+  octave::tree_index_expression *tree_index_expression_type;
+  octave::tree_colon_expression *tree_colon_expression_type;
+  octave::tree_argument_list *tree_argument_list_type;
+  octave::tree_parameter_list *tree_parameter_list_type;
+  octave::tree_command *tree_command_type;
+  octave::tree_if_command *tree_if_command_type;
+  octave::tree_if_clause *tree_if_clause_type;
+  octave::tree_if_command_list *tree_if_command_list_type;
+  octave::tree_switch_command *tree_switch_command_type;
+  octave::tree_switch_case *tree_switch_case_type;
+  octave::tree_switch_case_list *tree_switch_case_list_type;
+  octave::tree_decl_elt *tree_decl_elt_type;
+  octave::tree_decl_init_list *tree_decl_init_list_type;
+  octave::tree_decl_command *tree_decl_command_type;
+  octave::tree_statement *tree_statement_type;
+  octave::tree_statement_list *tree_statement_list_type;
+  octave_user_function *octave_user_function_type;
+
+  octave::tree_classdef *tree_classdef_type;
+  octave::tree_classdef_attribute* tree_classdef_attribute_type;
+  octave::tree_classdef_attribute_list* tree_classdef_attribute_list_type;
+  octave::tree_classdef_superclass* tree_classdef_superclass_type;
+  octave::tree_classdef_superclass_list* tree_classdef_superclass_list_type;
+  octave::tree_classdef_body* tree_classdef_body_type;
+  octave::tree_classdef_property* tree_classdef_property_type;
+  octave::tree_classdef_property_list* tree_classdef_property_list_type;
+  octave::tree_classdef_properties_block* tree_classdef_properties_block_type;
+  octave::tree_classdef_methods_list* tree_classdef_methods_list_type;
+  octave::tree_classdef_methods_block* tree_classdef_methods_block_type;
+  octave::tree_classdef_event* tree_classdef_event_type;
+  octave::tree_classdef_events_list* tree_classdef_events_list_type;
+  octave::tree_classdef_events_block* tree_classdef_events_block_type;
+  octave::tree_classdef_enum* tree_classdef_enum_type;
+  octave::tree_classdef_enum_list* tree_classdef_enum_list_type;
+  octave::tree_classdef_enum_block* tree_classdef_enum_block_type;
+}
+
+// Tokens with line and column information.
+%token <tok_val> '=' ':' '-' '+' '*' '/'
+%token <tok_val> ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ
+%token <tok_val> EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ AND_EQ OR_EQ
+%token <tok_val> EXPR_AND_AND EXPR_OR_OR
+%token <tok_val> EXPR_AND EXPR_OR EXPR_NOT
+%token <tok_val> EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT
+%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> 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> IF ELSEIF ELSE
+%token <tok_val> SWITCH CASE OTHERWISE
+%token <tok_val> BREAK CONTINUE FUNC_RET
+%token <tok_val> UNWIND CLEANUP
+%token <tok_val> TRY CATCH
+%token <tok_val> GLOBAL PERSISTENT
+%token <tok_val> FCN_HANDLE
+%token <tok_val> CLASSDEF
+%token <tok_val> PROPERTIES METHODS EVENTS ENUMERATION
+%token <tok_val> METAQUERY
+%token <tok_val> SUPERCLASSREF
+%token <tok_val> FQ_IDENT
+%token <tok_val> GET SET
+%token <tok_val> FCN
+%token <tok_val> LEXICAL_ERROR
+
+// Other tokens.
+%token<dummy_type> END_OF_INPUT
+%token<dummy_type> INPUT_FILE
+// %token VARARGIN VARARGOUT
+
+%token<dummy_type> '(' ')' '[' ']' '{' '}' '.' ',' ';' '@' '\n'
+
+// Nonterminals we construct.
+%type <dummy_type> indirect_ref_op decl_param_init
+%type <dummy_type> push_fcn_symtab push_script_symtab begin_file
+%type <dummy_type> param_list_beg param_list_end stmt_begin parse_error
+%type <dummy_type> parsing_local_fcns
+%type <comment_type> stash_comment
+%type <tok_val> function_beg classdef_beg
+%type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep
+%type <tree_type> input
+%type <tree_constant_type> string constant magic_colon
+%type <tree_anon_fcn_handle_type> anon_fcn_handle
+%type <tree_fcn_handle_type> fcn_handle
+%type <tree_matrix_type> matrix_rows
+%type <tree_cell_type> cell_rows
+%type <tree_expression_type> matrix cell
+%type <tree_expression_type> primary_expr oper_expr power_expr expr_no_assign
+%type <tree_expression_type> simple_expr colon_expr assign_expr expression
+%type <tree_identifier_type> identifier fcn_name magic_tilde
+%type <tree_funcall_type> superclass_identifier meta_identifier
+%type <tree_index_expression_type> word_list_cmd
+%type <tree_argument_list_type> arg_list word_list assign_lhs
+%type <tree_argument_list_type> cell_or_matrix_row
+%type <tree_parameter_list_type> opt_param_list param_list
+%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_function_def_type> function
+%type <tree_classdef_type> classdef
+%type <tree_command_type> file
+%type <tree_if_command_type> if_command
+%type <tree_if_clause_type> elseif_clause else_clause
+%type <tree_if_command_list_type> if_cmd_list1 if_cmd_list
+%type <tree_switch_command_type> switch_command
+%type <tree_switch_case_type> switch_case default_case
+%type <tree_switch_case_list_type> case_list1 case_list
+%type <tree_decl_elt_type> decl2 param_list_elt
+%type <tree_decl_init_list_type> decl1
+%type <tree_decl_command_type> declaration
+%type <tree_statement_type> statement function_end
+%type <tree_statement_list_type> simple_list simple_list1 list list1
+%type <tree_statement_list_type> opt_list
+%type <tree_statement_list_type> opt_fcn_list fcn_list fcn_list1
+%type <tree_classdef_attribute_type> attr
+%type <tree_classdef_attribute_list_type> attr_list opt_attr_list
+%type <tree_classdef_superclass_type> superclass
+%type <tree_classdef_superclass_list_type> superclass_list opt_superclass_list
+%type <tree_classdef_body_type> class_body
+%type <tree_classdef_property_type> class_property
+%type <tree_classdef_property_list_type> property_list
+%type <tree_classdef_properties_block_type> properties_block
+%type <tree_classdef_methods_list_type> methods_list
+%type <tree_classdef_methods_block_type> methods_block
+%type <tree_classdef_event_type> class_event
+%type <tree_classdef_events_list_type> events_list
+%type <tree_classdef_events_block_type> events_block
+%type <tree_classdef_enum_type> class_enum
+%type <tree_classdef_enum_list_type> enum_list
+%type <tree_classdef_enum_block_type> enum_block
+%type <tree_function_def_type> method_decl method
+%type <octave_user_function_type> method_decl1
+
+// Precedence and associativity.
+%right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ
+%left EXPR_OR_OR
+%left EXPR_AND_AND
+%left EXPR_OR
+%left EXPR_AND
+%left EXPR_LT EXPR_LE EXPR_EQ EXPR_NE EXPR_GE EXPR_GT
+%left ':'
+%left '-' '+' EPLUS EMINUS
+%left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV
+%right UNARY EXPR_NOT
+%left POW EPOW HERMITIAN TRANSPOSE
+%right PLUS_PLUS MINUS_MINUS
+%left '(' '.' '{'
+
+// How to clean up if there is a parse error.  We handle deleting tokens
+// and comments seperately and separators are just characters.  The
+// remaining items are dynamically allocated parse tree objects that
+// must be deleted.  Use the wildcard case (<*>) to detect unhandled
+// cases (for example, a new semantic type is added but not handled
+// here).
+
+%destructor { } <tok_val>
+%destructor { } <punct_type>
+%destructor { } <comment_type>
+%destructor { } <>
+
+%destructor { delete $$; } <tree_type>
+%destructor { delete $$; } <tree_matrix_type>
+%destructor { delete $$; } <tree_cell_type>
+%destructor { delete $$; } <tree_expression_type>
+%destructor { delete $$; } <tree_constant_type>
+%destructor { delete $$; } <tree_fcn_handle_type>
+%destructor { delete $$; } <tree_funcall_type>
+%destructor { delete $$; } <tree_function_def_type>
+%destructor { delete $$; } <tree_anon_fcn_handle_type>
+%destructor { delete $$; } <tree_identifier_type>
+%destructor { delete $$; } <tree_index_expression_type>
+%destructor { delete $$; } <tree_argument_list_type>
+%destructor { delete $$; } <tree_parameter_list_type>
+%destructor { delete $$; } <tree_command_type>
+%destructor { delete $$; } <tree_if_command_type>
+%destructor { delete $$; } <tree_if_clause_type>
+%destructor { delete $$; } <tree_if_command_list_type>
+%destructor { delete $$; } <tree_switch_command_type>
+%destructor { delete $$; } <tree_switch_case_type>
+%destructor { delete $$; } <tree_switch_case_list_type>
+%destructor { delete $$; } <tree_decl_elt_type>
+%destructor { delete $$; } <tree_decl_init_list_type>
+%destructor { delete $$; } <tree_decl_command_type>
+%destructor { delete $$; } <tree_statement_type>
+%destructor { delete $$; } <tree_statement_list_type>
+%destructor { delete $$; } <octave_user_function_type>
+
+%destructor { delete $$; } <tree_classdef_type>
+%destructor { delete $$; } <tree_classdef_attribute_type>
+%destructor { delete $$; } <tree_classdef_attribute_list_type>
+%destructor { delete $$; } <tree_classdef_superclass_type>
+%destructor { delete $$; } <tree_classdef_superclass_list_type>
+%destructor { delete $$; } <tree_classdef_body_type>
+%destructor { delete $$; } <tree_classdef_property_type>
+%destructor { delete $$; } <tree_classdef_property_list_type>
+%destructor { delete $$; } <tree_classdef_properties_block_type>
+%destructor { delete $$; } <tree_classdef_methods_list_type>
+%destructor { delete $$; } <tree_classdef_methods_block_type>
+%destructor { delete $$; } <tree_classdef_event_type>
+%destructor { delete $$; } <tree_classdef_events_list_type>
+%destructor { delete $$; } <tree_classdef_events_block_type>
+%destructor { delete $$; } <tree_classdef_enum_type>
+%destructor { delete $$; } <tree_classdef_enum_list_type>
+%destructor { delete $$; } <tree_classdef_enum_block_type>
+
+// Defining a generic destructor generates a warning if destructors are
+// already explicitly declared for all types.
+//
+// %destructor {
+//    warning_with_id
+//      ("Octave:parser-destructor",
+//       "possible memory leak in cleanup following parse error");
+// } <*>
+
+// Where to start.
+%start input
+
+%%
+
+// ==============================
+// Statements and statement lists
+// ==============================
+
+input           : simple_list '\n'
+                  {
+                    $$ = nullptr;
+                    parser.m_stmt_list = $1;
+                    YYACCEPT;
+                  }
+                | simple_list END_OF_INPUT
+                  {
+                    $$ = nullptr;
+                    lexer.m_end_of_input = true;
+                    parser.m_stmt_list = $1;
+                    YYACCEPT;
+                  }
+                | parse_error
+                  {
+                    $$ = nullptr;
+                    YYABORT;
+                  }
+                ;
+
+simple_list     : opt_sep_no_nl
+                  {
+                    YYUSE ($1);
+
+                    $$ = nullptr;
+                  }
+                | simple_list1 opt_sep_no_nl
+                  { $$ = parser.set_stmt_print_flag ($1, $2, false); }
+                ;
+
+simple_list1    : statement
+                  { $$ = parser.make_statement_list ($1); }
+                | simple_list1 sep_no_nl statement
+                  { $$ = parser.append_statement_list ($1, $2, $3, false); }
+                ;
+
+opt_list        : // empty
+                  { $$ = new octave::tree_statement_list (); }
+                | list
+                  { $$ = $1; }
+                ;
+
+list            : list1 opt_sep
+                  { $$ = parser.set_stmt_print_flag ($1, $2, true); }
+                ;
+
+list1           : statement
+                  { $$ = parser.make_statement_list ($1); }
+                | list1 sep statement
+                  { $$ = parser.append_statement_list ($1, $2, $3, true); }
+                ;
+
+opt_fcn_list    : // empty
+                  { $$ = new octave::tree_statement_list (); }
+                | fcn_list
+                  { $$ = $1; }
+                ;
+
+fcn_list        : fcn_list1 opt_sep
+                  {
+                    YYUSE ($2);
+
+                    $$ = $1;
+                  }
+                ;
+
+fcn_list1       : function
+                  {
+                    octave::tree_statement *stmt = parser.make_statement ($1);
+                    $$ = new octave::tree_statement_list (stmt);
+                  }
+                | fcn_list1 opt_sep function
+                  {
+                    octave::tree_statement *stmt = parser.make_statement ($3);
+                    $$ = parser.append_statement_list ($1, $2, stmt, false);
+                  }
+                ;
+
+statement       : expression
+                  { $$ = parser.make_statement ($1); }
+                | command
+                  { $$ = parser.make_statement ($1); }
+                | word_list_cmd
+                  { $$ = parser.make_statement ($1); }
+                ;
+
+// =================
+// Word-list command
+// =================
+
+// These are not really like expressions since they can't appear on
+// the RHS of an assignment.  But they are also not like commands (IF,
+// WHILE, etc.
+
+word_list_cmd   : identifier word_list
+                  {
+                    $$ = parser.make_index_expression ($1, $2, '(');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1 and $2.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+word_list       : string
+                  { $$ = new octave::tree_argument_list ($1); }
+                | word_list string
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+// ===========
+// Expressions
+// ===========
+
+identifier      : NAME
+                  {
+                    octave::symbol_record sr = $1->sym_rec ();
+                    $$ = new octave::tree_identifier (sr, $1->line (), $1->column ());
+                  }
+                ;
+
+superclass_identifier
+                : SUPERCLASSREF
+                  {
+                    std::string method_nm = $1->superclass_method_name ();
+                    std::string class_nm = $1->superclass_class_name ();
+
+                    $$ = parser.make_superclass_ref (method_nm, class_nm);
+                  }
+                ;
+
+meta_identifier : METAQUERY
+                  {
+                    std::string class_nm = $1->text ();
+
+                    $$ = parser.make_meta_class_query (class_nm);
+                  }
+                ;
+
+string          : DQ_STRING
+                  { $$ = parser.make_constant (DQ_STRING, $1); }
+                | SQ_STRING
+                  { $$ = parser.make_constant (SQ_STRING, $1); }
+                ;
+
+constant        : NUM
+                  { $$ = parser.make_constant (NUM, $1); }
+                | IMAG_NUM
+                  { $$ = parser.make_constant (IMAG_NUM, $1); }
+                | string
+                  { $$ = $1; }
+                ;
+
+matrix          : '[' matrix_rows ']'
+                  { $$ = parser.finish_matrix ($2); }
+                ;
+
+matrix_rows     : cell_or_matrix_row
+                  { $$ = $1 ? new octave::tree_matrix ($1) : nullptr; }
+                | matrix_rows ';' cell_or_matrix_row
+                  {
+                    if ($1)
+                      {
+                        if ($3)
+                          $1->append ($3);
+
+                        $$ = $1;
+                      }
+                    else
+                      $$ = $3 ? new octave::tree_matrix ($3) : nullptr;
+                  }
+                ;
+
+cell            : '{' cell_rows '}'
+                  { $$ = parser.finish_cell ($2); }
+                ;
+
+cell_rows       : cell_or_matrix_row
+                  { $$ = $1 ? new octave::tree_cell ($1) : nullptr; }
+                | cell_rows ';' cell_or_matrix_row
+                  {
+                    if ($1)
+                      {
+                        if ($3)
+                          $1->append ($3);
+
+                        $$ = $1;
+                      }
+                    else
+                      $$ = $3 ? new octave::tree_cell ($3) : nullptr;
+                  }
+                ;
+
+// tree_argument_list objects can't be empty or have leading or trailing
+// commas, but those are all allowed in matrix and cell array rows.
+
+cell_or_matrix_row
+                : // empty
+                  { $$ = nullptr; }
+                | ','
+                  { $$ = nullptr; }
+                | arg_list
+                  { $$ = $1; }
+                | arg_list ','
+                  { $$ = $1; }
+                | ',' arg_list
+                  { $$ = $2; }
+                | ',' arg_list ','
+                  { $$ = $2; }
+                ;
+
+fcn_handle      : '@' FCN_HANDLE
+                  {
+                    $$ = parser.make_fcn_handle ($2);
+                    lexer.m_looking_at_function_handle--;
+                  }
+                ;
+
+anon_fcn_handle : '@' param_list stmt_begin expr_no_assign
+                  {
+                    $$ = parser.make_anon_fcn_handle ($2, $4);
+                    lexer.m_nesting_level.remove ();
+                  }
+                | '@' param_list stmt_begin error
+                  {
+                    YYUSE ($2);
+
+                    $$ = nullptr;
+                    parser.bison_error ("anonymous function bodies must be single expressions");
+                    YYABORT;
+                  }
+                ;
+
+primary_expr    : identifier
+                  { $$ = $1; }
+                | constant
+                  { $$ = $1; }
+                | fcn_handle
+                  { $$ = $1; }
+                | matrix
+                  {
+                    lexer.m_looking_at_matrix_or_assign_lhs = false;
+                    $$ = $1;
+                  }
+                | cell
+                  { $$ = $1; }
+                | meta_identifier
+                  { $$ = $1; }
+                | superclass_identifier
+                  { $$ = $1; }
+                | '(' expression ')'
+                  { $$ = $2->mark_in_parens (); }
+                ;
+
+magic_colon     : ':'
+                  {
+                    YYUSE ($1);
+
+                    octave_value tmp (octave_value::magic_colon_t);
+                    $$ = new octave::tree_constant (tmp);
+                  }
+                ;
+
+magic_tilde     : EXPR_NOT
+                  {
+                    YYUSE ($1);
+
+                    $$ = new octave::tree_black_hole ();
+                  }
+                ;
+
+arg_list        : expression
+                  { $$ = new octave::tree_argument_list ($1); }
+                | magic_colon
+                  { $$ = new octave::tree_argument_list ($1); }
+                | magic_tilde
+                  { $$ = new octave::tree_argument_list ($1); }
+                | arg_list ',' magic_colon
+                  {
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                | arg_list ',' magic_tilde
+                  {
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                | arg_list ',' expression
+                  {
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+indirect_ref_op : '.'
+                  {
+                    $$ = 0;
+                    lexer.m_looking_at_indirect_ref = true;
+                  }
+                ;
+
+oper_expr       : primary_expr
+                  { $$ = $1; }
+                | oper_expr PLUS_PLUS
+                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
+                | oper_expr MINUS_MINUS
+                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
+                | oper_expr '(' ')'
+                  {
+                    $$ = parser.make_index_expression ($1, nullptr, '(');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1.
+                        YYABORT;
+                      }
+                  }
+                | oper_expr '(' arg_list ')'
+                  {
+                    $$ = parser.make_index_expression ($1, $3, '(');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1 and $3.
+                        YYABORT;
+                      }
+                  }
+                | oper_expr '{' '}'
+                  {
+                    $$ = parser.make_index_expression ($1, nullptr, '{');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1.
+                        YYABORT;
+                      }
+                  }
+                | oper_expr '{' arg_list '}'
+                  {
+                    $$ = parser.make_index_expression ($1, $3, '{');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1 and $3.
+                        YYABORT;
+                      }
+                  }
+                | oper_expr HERMITIAN
+                  { $$ = parser.make_postfix_op (HERMITIAN, $1, $2); }
+                | oper_expr TRANSPOSE
+                  { $$ = parser.make_postfix_op (TRANSPOSE, $1, $2); }
+                | oper_expr indirect_ref_op STRUCT_ELT
+                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
+                | oper_expr indirect_ref_op '(' expression ')'
+                  { $$ = parser.make_indirect_ref ($1, $4); }
+                | PLUS_PLUS oper_expr %prec UNARY
+                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
+                | MINUS_MINUS oper_expr %prec UNARY
+                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
+                | EXPR_NOT oper_expr %prec UNARY
+                  { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); }
+                | '+' oper_expr %prec UNARY
+                  { $$ = parser.make_prefix_op ('+', $2, $1); }
+                | '-' oper_expr %prec UNARY
+                  { $$ = parser.make_prefix_op ('-', $2, $1); }
+                | oper_expr POW power_expr
+                  { $$ = parser.make_binary_op (POW, $1, $2, $3); }
+                | oper_expr EPOW power_expr
+                  { $$ = parser.make_binary_op (EPOW, $1, $2, $3); }
+                | oper_expr '+' oper_expr
+                  { $$ = parser.make_binary_op ('+', $1, $2, $3); }
+                | oper_expr '-' oper_expr
+                  { $$ = parser.make_binary_op ('-', $1, $2, $3); }
+                | oper_expr '*' oper_expr
+                  { $$ = parser.make_binary_op ('*', $1, $2, $3); }
+                | oper_expr '/' oper_expr
+                  { $$ = parser.make_binary_op ('/', $1, $2, $3); }
+                | oper_expr EPLUS oper_expr
+                  { $$ = parser.make_binary_op ('+', $1, $2, $3); }
+                | oper_expr EMINUS oper_expr
+                  { $$ = parser.make_binary_op ('-', $1, $2, $3); }
+                | oper_expr EMUL oper_expr
+                  { $$ = parser.make_binary_op (EMUL, $1, $2, $3); }
+                | oper_expr EDIV oper_expr
+                  { $$ = parser.make_binary_op (EDIV, $1, $2, $3); }
+                | oper_expr LEFTDIV oper_expr
+                  { $$ = parser.make_binary_op (LEFTDIV, $1, $2, $3); }
+                | oper_expr ELEFTDIV oper_expr
+                  { $$ = parser.make_binary_op (ELEFTDIV, $1, $2, $3); }
+                ;
+
+power_expr      : primary_expr
+                  { $$ = $1; }
+                | power_expr PLUS_PLUS
+                  { $$ = parser.make_postfix_op (PLUS_PLUS, $1, $2); }
+                | power_expr MINUS_MINUS
+                  { $$ = parser.make_postfix_op (MINUS_MINUS, $1, $2); }
+                | power_expr '(' ')'
+                  {
+                    $$ = parser.make_index_expression ($1, nullptr, '(');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1.
+                        YYABORT;
+                      }
+                  }
+                | power_expr '(' arg_list ')'
+                  {
+                    $$ = parser.make_index_expression ($1, $3, '(');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1 and $3.
+                        YYABORT;
+                      }
+                  }
+                | power_expr '{' '}'
+                  {
+                    $$ = parser.make_index_expression ($1, nullptr, '{');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1.
+                        YYABORT;
+                      }
+                  }
+                | power_expr '{' arg_list '}'
+                  {
+                    $$ = parser.make_index_expression ($1, $3, '{');
+                    if (! $$)
+                      {
+                        // make_index_expression deleted $1 and $3.
+                        YYABORT;
+                      }
+                  }
+                | power_expr indirect_ref_op STRUCT_ELT
+                  { $$ = parser.make_indirect_ref ($1, $3->text ()); }
+                | power_expr indirect_ref_op '(' expression ')'
+                  { $$ = parser.make_indirect_ref ($1, $4); }
+                | PLUS_PLUS power_expr %prec POW
+                  { $$ = parser.make_prefix_op (PLUS_PLUS, $2, $1); }
+                | MINUS_MINUS power_expr %prec POW
+                  { $$ = parser.make_prefix_op (MINUS_MINUS, $2, $1); }
+                | EXPR_NOT power_expr %prec POW
+                  { $$ = parser.make_prefix_op (EXPR_NOT, $2, $1); }
+                | '+' power_expr %prec POW
+                  { $$ = parser.make_prefix_op ('+', $2, $1); }
+                | '-' power_expr %prec POW
+                  { $$ = parser.make_prefix_op ('-', $2, $1); }
+                ;
+
+colon_expr      : oper_expr ':' oper_expr
+                  {
+                    YYUSE ($2);
+
+                    $$ = parser.make_colon_expression ($1, $3);
+
+                    if (! $$)
+                      {
+                        // finish_colon_expression deleted $1 and $3.
+                        YYABORT;
+                      }
+                  }
+                | oper_expr ':' oper_expr ':' oper_expr
+                  {
+                    YYUSE ($2);
+                    YYUSE ($4);
+
+                    $$ = parser.make_colon_expression ($1, $5, $3);
+
+                    if (! $$)
+                      {
+                        // finish_colon_expression deleted $1, $3, and $5.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+simple_expr     : oper_expr
+                  { $$ = $1; }
+                | colon_expr
+                  { $$ = $1; }
+                | simple_expr EXPR_LT simple_expr
+                  { $$ = parser.make_binary_op (EXPR_LT, $1, $2, $3); }
+                | simple_expr EXPR_LE simple_expr
+                  { $$ = parser.make_binary_op (EXPR_LE, $1, $2, $3); }
+                | simple_expr EXPR_EQ simple_expr
+                  { $$ = parser.make_binary_op (EXPR_EQ, $1, $2, $3); }
+                | simple_expr EXPR_GE simple_expr
+                  { $$ = parser.make_binary_op (EXPR_GE, $1, $2, $3); }
+                | simple_expr EXPR_GT simple_expr
+                  { $$ = parser.make_binary_op (EXPR_GT, $1, $2, $3); }
+                | simple_expr EXPR_NE simple_expr
+                  { $$ = parser.make_binary_op (EXPR_NE, $1, $2, $3); }
+                | simple_expr EXPR_AND simple_expr
+                  { $$ = parser.make_binary_op (EXPR_AND, $1, $2, $3); }
+                | simple_expr EXPR_OR simple_expr
+                  { $$ = parser.make_binary_op (EXPR_OR, $1, $2, $3); }
+                | simple_expr EXPR_AND_AND simple_expr
+                  { $$ = parser.make_boolean_op (EXPR_AND_AND, $1, $2, $3); }
+                | simple_expr EXPR_OR_OR simple_expr
+                  { $$ = parser.make_boolean_op (EXPR_OR_OR, $1, $2, $3); }
+                ;
+
+assign_lhs      : simple_expr
+                  {
+                    $$ = parser.validate_matrix_for_assignment ($1);
+
+                    if ($$)
+                      { lexer.m_looking_at_matrix_or_assign_lhs = false; }
+                    else
+                      {
+                        // validate_matrix_for_assignment deleted $1.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+assign_expr     : assign_lhs '=' expression
+                  { $$ = parser.make_assign_op ('=', $1, $2, $3); }
+                | assign_lhs ADD_EQ expression
+                  { $$ = parser.make_assign_op (ADD_EQ, $1, $2, $3); }
+                | assign_lhs SUB_EQ expression
+                  { $$ = parser.make_assign_op (SUB_EQ, $1, $2, $3); }
+                | assign_lhs MUL_EQ expression
+                  { $$ = parser.make_assign_op (MUL_EQ, $1, $2, $3); }
+                | assign_lhs DIV_EQ expression
+                  { $$ = parser.make_assign_op (DIV_EQ, $1, $2, $3); }
+                | assign_lhs LEFTDIV_EQ expression
+                  { $$ = parser.make_assign_op (LEFTDIV_EQ, $1, $2, $3); }
+                | assign_lhs POW_EQ expression
+                  { $$ = parser.make_assign_op (POW_EQ, $1, $2, $3); }
+                | assign_lhs EMUL_EQ expression
+                  { $$ = parser.make_assign_op (EMUL_EQ, $1, $2, $3); }
+                | assign_lhs EDIV_EQ expression
+                  { $$ = parser.make_assign_op (EDIV_EQ, $1, $2, $3); }
+                | assign_lhs ELEFTDIV_EQ expression
+                  { $$ = parser.make_assign_op (ELEFTDIV_EQ, $1, $2, $3); }
+                | assign_lhs EPOW_EQ expression
+                  { $$ = parser.make_assign_op (EPOW_EQ, $1, $2, $3); }
+                | assign_lhs AND_EQ expression
+                  { $$ = parser.make_assign_op (AND_EQ, $1, $2, $3); }
+                | assign_lhs OR_EQ expression
+                  { $$ = parser.make_assign_op (OR_EQ, $1, $2, $3); }
+                ;
+
+expr_no_assign  : simple_expr
+                  {
+                    if ($1 && ($1->is_matrix () || $1->iscell ()))
+                      {
+                        if (parser.validate_array_list ($1))
+                          $$ = $1;
+                        else
+                          {
+                            delete $1;
+                            YYABORT;
+                          }
+                      }
+                    else
+                      $$ = $1;
+                  }
+                | anon_fcn_handle
+                  { $$ = $1; }
+                ;
+
+expression      : expr_no_assign
+                  { $$ = $1; }
+                | assign_expr
+                  {
+                    if (! $1)
+                      YYABORT;
+
+                    $$ = $1;
+                  }
+
+// ================================================
+// Commands, declarations, and function definitions
+// ================================================
+
+command         : declaration
+                  { $$ = $1; }
+                | select_command
+                  { $$ = $1; }
+                | loop_command
+                  { $$ = $1; }
+                | jump_command
+                  { $$ = $1; }
+                | except_command
+                  { $$ = $1; }
+                | function
+                  { $$ = $1; }
+                | file
+                  { $$ = $1; }
+                ;
+
+// =====================
+// Declaration statemnts
+// =====================
+
+declaration     : GLOBAL decl1
+                  {
+                    $$ = parser.make_decl_command (GLOBAL, $1, $2);
+                    lexer.m_looking_at_decl_list = false;
+                  }
+                | PERSISTENT decl1
+                  {
+                    $$ = parser.make_decl_command (PERSISTENT, $1, $2);
+                    lexer.m_looking_at_decl_list = false;
+                  }
+                ;
+
+decl1           : decl2
+                  { $$ = new octave::tree_decl_init_list ($1); }
+                | decl1 decl2
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+decl_param_init : // empty
+                  {
+                    $$ = 0;
+                    lexer.m_looking_at_initializer_expression = true;
+                  }
+
+decl2           : identifier
+                  { $$ = new octave::tree_decl_elt ($1); }
+                | identifier '=' decl_param_init expression
+                  {
+                    YYUSE ($2);
+
+                    lexer.m_looking_at_initializer_expression = false;
+                    $$ = new octave::tree_decl_elt ($1, $4);
+                  }
+                ;
+
+// ====================
+// Selection statements
+// ====================
+
+select_command  : if_command
+                  { $$ = $1; }
+                | switch_command
+                  { $$ = $1; }
+                ;
+
+// ============
+// If statement
+// ============
+
+if_command      : IF stash_comment if_cmd_list END
+                  {
+                    if (! ($$ = parser.finish_if_command ($1, $3, $4, $2)))
+                      {
+                        // finish_if_command deleted $3.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+if_cmd_list     : if_cmd_list1
+                  { $$ = $1; }
+                | if_cmd_list1 else_clause
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+if_cmd_list1    : expression stmt_begin opt_sep opt_list
+                  {
+                    YYUSE ($3);
+
+                    $1->mark_braindead_shortcircuit ();
+
+                    $$ = parser.start_if_command ($1, $4);
+                  }
+                | if_cmd_list1 elseif_clause
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+elseif_clause   : ELSEIF stash_comment opt_sep expression stmt_begin opt_sep opt_list
+                  {
+                    YYUSE ($3);
+                    YYUSE ($6);
+
+                    $4->mark_braindead_shortcircuit ();
+
+                    $$ = parser.make_elseif_clause ($1, $4, $7, $2);
+                  }
+                ;
+
+else_clause     : ELSE stash_comment opt_sep opt_list
+                  {
+                    YYUSE ($1);
+                    YYUSE ($3);
+
+                    $$ = new octave::tree_if_clause ($4, $2);
+                  }
+                ;
+
+// ================
+// Switch statement
+// ================
+
+switch_command  : SWITCH stash_comment expression opt_sep case_list END
+                  {
+                    YYUSE ($4);
+
+                    if (! ($$ = parser.finish_switch_command ($1, $3, $5, $6, $2)))
+                      {
+                        // finish_switch_command deleted $3 adn $5.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+case_list       : // empty
+                  { $$ = new octave::tree_switch_case_list (); }
+                | default_case
+                  { $$ = new octave::tree_switch_case_list ($1); }
+                | case_list1
+                  { $$ = $1; }
+                | case_list1 default_case
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+case_list1      : switch_case
+                  { $$ = new octave::tree_switch_case_list ($1); }
+                | case_list1 switch_case
+                  {
+                    $1->append ($2);
+                    $$ = $1;
+                  }
+                ;
+
+switch_case     : CASE stash_comment opt_sep expression stmt_begin opt_sep opt_list
+                  {
+                    YYUSE ($3);
+                    YYUSE ($6);
+
+                    $$ = parser.make_switch_case ($1, $4, $7, $2);
+                  }
+                ;
+
+default_case    : OTHERWISE stash_comment opt_sep opt_list
+                  {
+                    YYUSE ($1);
+                    YYUSE ($3);
+
+                    $$ = new octave::tree_switch_case ($4, $2);
+                  }
+                ;
+
+// =======
+// Looping
+// =======
+
+loop_command    : WHILE stash_comment expression stmt_begin opt_sep opt_list END
+                  {
+                    YYUSE ($5);
+
+                    $3->mark_braindead_shortcircuit ();
+
+                    if (! ($$ = parser.make_while_command ($1, $3, $6, $7, $2)))
+                      {
+                        // make_while_command deleted $3 and $6.
+                        YYABORT;
+                      }
+                  }
+                | DO stash_comment opt_sep opt_list UNTIL expression
+                  {
+                    YYUSE ($1);
+                    YYUSE ($3);
+
+                    $$ = parser.make_do_until_command ($5, $4, $6, $2);
+                  }
+                | FOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($7);
+
+                    if (! ($$ = parser.make_for_command (FOR, $1, $3, $5,
+                                                         nullptr, $8, $9, $2)))
+                      {
+                        // make_for_command deleted $3, $5, and $8.
+                        YYABORT;
+                      }
+                  }
+                | FOR stash_comment '(' assign_lhs '=' expression ')' opt_sep opt_list END
+                  {
+                    YYUSE ($5);
+                    YYUSE ($8);
+
+                    if (! ($$ = parser.make_for_command (FOR, $1, $4, $6,
+                                                         nullptr, $9, $10, $2)))
+                      {
+                        // make_for_command deleted $4, $6, and $9.
+                        YYABORT;
+                      }
+                  }
+                | PARFOR stash_comment assign_lhs '=' expression stmt_begin opt_sep opt_list END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($7);
+
+                    if (! ($$ = parser.make_for_command (PARFOR, $1, $3, $5,
+                                                         nullptr, $8, $9, $2)))
+                      {
+                        // make_for_command deleted $3, $5, and $8.
+                        YYABORT;
+                      }
+                  }
+                | PARFOR stash_comment '(' assign_lhs '=' expression ',' expression ')' opt_sep opt_list END
+                  {
+                    YYUSE ($5);
+                    YYUSE ($10);
+
+                    if (! ($$ = parser.make_for_command (PARFOR, $1, $4, $6,
+                                                         $8, $11, $12, $2)))
+                      {
+                        // make_for_command deleted $4, $6, $8, and $11.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+// =======
+// Jumping
+// =======
+
+jump_command    : BREAK
+                  {
+                    if (! ($$ = parser.make_break_command ($1)))
+                      YYABORT;
+                  }
+                | CONTINUE
+                  { $$ = parser.make_continue_command ($1); }
+                | FUNC_RET
+                  { $$ = parser.make_return_command ($1); }
+                ;
+
+// ==========
+// Exceptions
+// ==========
+
+except_command  : UNWIND stash_comment opt_sep opt_list CLEANUP
+                  stash_comment opt_sep opt_list END
+                  {
+                    YYUSE ($3);
+                    YYUSE ($5);
+                    YYUSE ($7);
+
+                    if (! ($$ = parser.make_unwind_command ($1, $4, $8, $9, $2, $6)))
+                      {
+                        // make_unwind_command deleted $4 and $8.
+                        YYABORT;
+                      }
+                  }
+                | TRY stash_comment opt_sep opt_list CATCH stash_comment
+                  opt_sep opt_list END
+                  {
+                    YYUSE ($3);
+                    YYUSE ($5);
+                    YYUSE ($7);
+
+                    if (! ($$ = parser.make_try_command ($1, $4, $7, $8, $9, $2, $6)))
+                      {
+                        // make_try_command deleted $4 and $8.
+                        YYABORT;
+                      }
+                  }
+                | TRY stash_comment opt_sep opt_list END
+                  {
+                    YYUSE ($3);
+
+                    if (! ($$ = parser.make_try_command ($1, $4, 0, nullptr,
+                                                         $5, $2, nullptr)))
+                      {
+                        // make_try_command deleted $4.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+// ===========================================
+// Some 'subroutines' for function definitions
+// ===========================================
+
+push_fcn_symtab : // empty
+                  {
+                    $$ = 0;
+
+                    parser.m_curr_fcn_depth++;
+
+                    if (parser.m_max_fcn_depth < parser.m_curr_fcn_depth)
+                      parser.m_max_fcn_depth = parser.m_curr_fcn_depth;
+
+                    // Will get a real name later.
+                    lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_fcn_symtab"));
+                    parser.m_function_scopes.push (lexer.m_symtab_context.curr_scope ());
+
+                    if (! lexer.m_reading_script_file
+                        && parser.m_curr_fcn_depth == 0
+                        && ! parser.m_parsing_subfunctions)
+                      parser.m_primary_fcn_scope
+                        = lexer.m_symtab_context.curr_scope ();
+
+                    if (lexer.m_reading_script_file
+                        && parser.m_curr_fcn_depth > 0)
+                      {
+                        parser.bison_error ("nested functions not implemented in this context");
+                        YYABORT;
+                      }
+                  }
+                ;
+
+// ===========================
+// List of function parameters
+// ===========================
+
+param_list_beg  : '('
+                  {
+                    $$ = 0;
+                    lexer.m_looking_at_parameter_list = true;
+
+                    if (lexer.m_looking_at_function_handle)
+                      {
+                        // Will get a real name later.
+                        lexer.m_symtab_context.push (octave::symbol_scope ("parser:param_lsit_beg"));
+                        lexer.m_looking_at_function_handle--;
+                        lexer.m_looking_at_anon_fcn_args = true;
+                      }
+                  }
+                ;
+
+param_list_end  : ')'
+                  {
+                    $$ = 0;
+                    lexer.m_looking_at_parameter_list = false;
+                    lexer.m_looking_for_object_index = false;
+                  }
+                ;
+
+opt_param_list  : // empty
+                  { $$ = nullptr; }
+                | param_list
+                  { $$ = $1; }
+                ;
+
+param_list      : param_list_beg param_list1 param_list_end
+                  {
+                    if ($2)
+                      lexer.mark_as_variables ($2->variable_names ());
+
+                    $$ = $2;
+                  }
+                | param_list_beg error
+                  {
+                    $$ = nullptr;
+                    parser.bison_error ("invalid parameter list");
+                    YYABORT;
+                  }
+                ;
+
+param_list1     : // empty
+                  { $$ = nullptr; }
+                | param_list2
+                  {
+                    $1->mark_as_formal_parameters ();
+
+                    if (parser.validate_param_list ($1, octave::tree_parameter_list::in))
+                      {
+                        lexer.mark_as_variables ($1->variable_names ());
+                        $$ = $1;
+                      }
+                    else
+                      {
+                        delete $1;
+                        YYABORT;
+                      }
+                  }
+                ;
+
+param_list2     : param_list_elt
+                  { $$ = new octave::tree_parameter_list ($1); }
+                | param_list2 ',' param_list_elt
+                  {
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+param_list_elt  : decl2
+                  { $$ = $1; }
+                | magic_tilde
+                  { $$ = new octave::tree_decl_elt ($1); }
+                ;
+
+// ===================================
+// List of function return value names
+// ===================================
+
+return_list     : '[' ']'
+                  {
+                    lexer.m_looking_at_return_list = false;
+
+                    $$ = new octave::tree_parameter_list ();
+                  }
+                | identifier
+                  {
+                    lexer.m_looking_at_return_list = false;
+
+                    octave::tree_parameter_list *tmp = new octave::tree_parameter_list ($1);
+
+                    // Even though this parameter list can contain only
+                    // a single identifier, we still need to validate it
+                    // to check for varargin or varargout.
+
+                    if (parser.validate_param_list (tmp, octave::tree_parameter_list::out))
+                      $$ = tmp;
+                    else
+                      {
+                        delete tmp;
+                        YYABORT;
+                      }
+                  }
+                | '[' return_list1 ']'
+                  {
+                    lexer.m_looking_at_return_list = false;
+
+                    // Check for duplicate parameter names, varargin,
+                    // or varargout.
+
+                    if (parser.validate_param_list ($2, octave::tree_parameter_list::out))
+                      $$ = $2;
+                    else
+                      {
+                        delete $2;
+                        YYABORT;
+                      }
+                  }
+                ;
+
+return_list1    : identifier
+                  { $$ = new octave::tree_parameter_list (new octave::tree_decl_elt ($1)); }
+                | return_list1 ',' identifier
+                  {
+                    $1->append (new octave::tree_decl_elt ($3));
+                    $$ = $1;
+                  }
+                ;
+
+// =======================
+// Script or function file
+// =======================
+
+parsing_local_fcns
+                : // empty
+                  { parser.m_parsing_local_functions = true; }
+                ;
+
+push_script_symtab : // empty
+                  {
+                    $$ = 0;
+
+                    // This scope may serve as the parent scope for local
+                    // functions in classdef files..
+                    lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_script_symtab"));
+                  }
+                ;
+
+begin_file      : push_script_symtab INPUT_FILE
+                  { $$ = 0; }
+                ;
+
+file            : begin_file opt_nl opt_list END_OF_INPUT
+                  {
+                    YYUSE ($2);
+
+                    if (lexer.m_reading_fcn_file)
+                      {
+                        // Delete the dummy statement_list we created
+                        // after parsing the function.  Any function
+                        // definitions found in the file have already
+                        // been stored in the symbol table or in
+                        // base_parser::m_primary_fcn_ptr.
+
+                        // Unused symbol table context.
+                        lexer.m_symtab_context.pop ();
+
+                        delete $3;
+                      }
+                    else
+                      {
+                        octave::tree_statement *end_of_script
+                          = parser.make_end ("endscript", true,
+                                             lexer.m_input_line_number,
+                                             lexer.m_current_input_column);
+
+                        parser.make_script ($3, end_of_script);
+                      }
+
+                    $$ = nullptr;
+                  }
+                | begin_file opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT
+                  {
+                    YYUSE ($2);
+                    YYUSE ($5);
+
+                    // Unused symbol table context.
+                    lexer.m_symtab_context.pop ();
+
+                    parser.finish_classdef_file ($3, $6);
+
+                    $$ = nullptr;
+                  }
+                ;
+
+// ===================
+// Function definition
+// ===================
+
+function_beg    : push_fcn_symtab FCN
+                  {
+                    $$ = $2;
+                    if (lexer.m_reading_classdef_file
+                        || lexer.m_parsing_classdef)
+                      lexer.m_maybe_classdef_get_set_method = true;
+                  }
+                ;
+
+fcn_name        : identifier
+                  {
+                    std::string id = $1->name ();
+
+                    // Make classdef local functions unique from
+                    // classdef methods.
+
+                    if (parser.m_parsing_local_functions
+                        && parser.m_curr_fcn_depth == 0)
+                      id = lexer.m_fcn_file_name + ">" + id;
+
+                    if (! parser.m_function_scopes.name_current_scope (id))
+                      {
+                        parser.bison_error ("duplicate subfunction or nested function name",
+                                            $1->line (), $1->column ());
+
+                        delete $1;
+
+                        YYABORT;
+                      }
+
+                    octave::symbol_scope curr_scope
+                      = lexer.m_symtab_context.curr_scope ();
+                    curr_scope.cache_name (id);
+
+                    lexer.m_parsed_function_name.top () = true;
+                    lexer.m_maybe_classdef_get_set_method = false;
+
+                    $$ = $1;
+                  }
+                | GET '.' identifier
+                  {
+                    YYUSE ($1);
+
+                    lexer.m_parsed_function_name.top () = true;
+                    lexer.m_maybe_classdef_get_set_method = false;
+                    lexer.m_parsing_classdef_get_method = true;
+                    $$ = $3;
+                  }
+                | SET '.' identifier
+                  {
+                    YYUSE ($1);
+
+                    lexer.m_parsed_function_name.top () = true;
+                    lexer.m_maybe_classdef_get_set_method = false;
+                    lexer.m_parsing_classdef_set_method = true;
+                    $$ = $3;
+                  }
+                ;
+
+function_end    : END
+                  {
+                    parser.m_endfunction_found = true;
+
+                    if (parser.end_token_ok ($1, octave::token::function_end))
+                      $$ = parser.make_end ("endfunction", false,
+                                            $1->line (), $1->column ());
+                    else
+                      {
+                        parser.end_token_error ($1, octave::token::function_end);
+                        YYABORT;
+                      }
+                  }
+                | END_OF_INPUT
+                  {
+// A lot of tests are based on the assumption that this is OK
+//                  if (lexer.m_reading_script_file)
+//                    {
+//                      parser.bison_error ("function body open at end of script");
+//                      YYABORT;
+//                    }
+
+                    if (parser.m_endfunction_found)
+                      {
+                        parser.bison_error ("inconsistent function endings -- "
+                                 "if one function is explicitly ended, "
+                                 "so must all the others");
+                        YYABORT;
+                      }
+
+                    if (! (lexer.m_reading_fcn_file || lexer.m_reading_script_file
+                           || lexer.input_from_eval_string ()))
+                      {
+                        parser.bison_error ("function body open at end of input");
+                        YYABORT;
+                      }
+
+                    if (lexer.m_reading_classdef_file)
+                      {
+                        parser.bison_error ("classdef body open at end of input");
+                        YYABORT;
+                      }
+
+                    $$ = parser.make_end ("endfunction", true,
+                                          lexer.m_input_line_number,
+                                          lexer.m_current_input_column);
+                  }
+                ;
+
+function        : function_beg stash_comment fcn_name
+                  opt_param_list opt_sep opt_list function_end
+                  {
+                    YYUSE ($5);
+
+                    $$ = parser.make_function ($1, nullptr, $3, $4, $6, $7, $2);
+                  }
+                | function_beg stash_comment return_list '=' fcn_name
+                  opt_param_list opt_sep opt_list function_end
+                  {
+                    YYUSE ($4);
+                    YYUSE ($7);
+
+                    $$ = parser.make_function ($1, $3, $5, $6, $8, $9, $2);
+                  }
+                ;
+
+// ========
+// Classdef
+// ========
+
+classdef_beg    : CLASSDEF
+                  {
+                    if (! lexer.m_reading_classdef_file)
+                      {
+                        parser.bison_error ("classdef must appear inside a file containing only a class definition");
+                        YYABORT;
+                      }
+
+                    // Create invalid parent scope.
+                    lexer.m_symtab_context.push (octave::symbol_scope ());
+                    lexer.m_parsing_classdef = true;
+                    $$ = $1;
+                  }
+                ;
+
+classdef        : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END
+                  {
+                    YYUSE ($6);
+                    YYUSE ($8);
+
+                    lexer.m_parsing_classdef = false;
+
+                    if (! ($$ = parser.make_classdef ($1, $3, $4, $5, $7, $9, $2)))
+                      {
+                        // make_classdef deleted $3, $4, $5, and $7.
+                        YYABORT;
+                      }
+                  }
+                | classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep END
+                  {
+                    YYUSE ($6);
+
+                    lexer.m_parsing_classdef = false;
+
+                    if (! ($$ = parser.make_classdef ($1, $3, $4, $5, nullptr,
+                                                      $7, $2)))
+                      {
+                        // make_classdef deleted $3, $4, and $5.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+opt_attr_list   : // empty
+                  { $$ = nullptr; }
+                | '(' attr_list ')'
+                  { $$ = $2; }
+                ;
+
+attr_list       : attr
+                  { $$ = new octave::tree_classdef_attribute_list ($1); }
+                | attr_list ',' attr
+                  {
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+attr            : identifier
+                  { $$ = new octave::tree_classdef_attribute ($1); }
+                | identifier '=' decl_param_init expression
+                  {
+                    YYUSE ($2);
+
+                    lexer.m_looking_at_initializer_expression = false;
+                    $$ = new octave::tree_classdef_attribute ($1, $4);
+                  }
+                | EXPR_NOT identifier
+                  {
+                    YYUSE ($1);
+
+                    $$ = new octave::tree_classdef_attribute ($2, false);
+                  }
+                ;
+
+opt_superclass_list
+                : // empty
+                  { $$ = nullptr; }
+                | superclass_list
+                  { $$ = $1; }
+                ;
+
+superclass_list : EXPR_LT
+                  {
+                    YYUSE ($1);
+
+                    lexer.enable_fq_identifier ();
+                  }
+                  superclass
+                  { $$ = new octave::tree_classdef_superclass_list ($3); }
+                | superclass_list EXPR_AND
+                  {
+                    YYUSE ($2);
+
+                    lexer.enable_fq_identifier ();
+                  }
+                  superclass
+                  {
+                    $1->append ($4);
+                    $$ = $1;
+                  }
+                ;
+
+superclass      : FQ_IDENT
+                  { $$ = new octave::tree_classdef_superclass ($1->text ()); }
+                ;
+
+class_body      : properties_block
+                  { $$ = new octave::tree_classdef_body ($1); }
+                | methods_block
+                  { $$ = new octave::tree_classdef_body ($1); }
+                | events_block
+                  { $$ = new octave::tree_classdef_body ($1); }
+                | enum_block
+                  { $$ = new octave::tree_classdef_body ($1); }
+                | class_body opt_sep properties_block
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                | class_body opt_sep methods_block
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                | class_body opt_sep events_block
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                | class_body opt_sep enum_block
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+properties_block
+                : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($6);
+
+                    if (! ($$ = parser.make_classdef_properties_block
+                           ($1, $3, $5, $7, $2)))
+                      {
+                        // make_classdef_properties_block delete $3 and $5.
+                        YYABORT;
+                      }
+                  }
+                | PROPERTIES stash_comment opt_attr_list opt_sep END
+                  {
+                    YYUSE ($4);
+
+                    if (! ($$ = parser.make_classdef_properties_block
+                           ($1, $3, nullptr, $5, $2)))
+                      {
+                        // make_classdef_properties_block delete $3.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+property_list
+                : class_property
+                  { $$ = new octave::tree_classdef_property_list ($1); }
+                | property_list sep class_property
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+class_property  : identifier
+                  { $$ = new octave::tree_classdef_property ($1); }
+                | identifier '=' decl_param_init expression
+                  {
+                    YYUSE ($2);
+
+                    lexer.m_looking_at_initializer_expression = false;
+                    $$ = new octave::tree_classdef_property ($1, $4);
+                  }
+                ;
+
+methods_block   : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($6);
+
+                    if (! ($$ = parser.make_classdef_methods_block
+                           ($1, $3, $5, $7, $2)))
+                      {
+                        // make_classdef_methods_block deleted $3 and $5.
+                        YYABORT;
+                      }
+                  }
+                | METHODS stash_comment opt_attr_list opt_sep END
+                  {
+                    YYUSE ($4);
+
+                    if (! ($$ = parser.make_classdef_methods_block
+                           ($1, $3, nullptr, $5, $2)))
+                      {
+                        // make_classdef_methods_block deleted $3.
+                        YYABORT;
+                      }
+                  }
+                ;
+                ;
+
+method_decl1    : identifier
+                  {
+                    if (! ($$ = parser.start_classdef_external_method ($1, nullptr)))
+                      YYABORT;
+                  }
+                | identifier param_list
+                  {
+                    if (! ($$ = parser.start_classdef_external_method ($1, $2)))
+                      YYABORT;
+                  }
+                ;
+
+method_decl     : stash_comment method_decl1
+                  { $$ = parser.finish_classdef_external_method ($2, nullptr, $1); }
+                | stash_comment return_list '='
+                  {
+                    YYUSE ($3);
+
+                    lexer.m_defining_func++;
+                    lexer.m_parsed_function_name.push (false);
+                  }
+                  method_decl1
+                  {
+                    lexer.m_defining_func--;
+                    lexer.m_parsed_function_name.pop ();
+                    $$ = parser.finish_classdef_external_method ($5, $2, $1);
+                  }
+                ;
+
+method          : method_decl
+                  { $$ = $1; }
+                | function
+                  { $$ = $1; }
+                ;
+
+methods_list    : method
+                  {
+                    octave_value fcn;
+                    if ($1)
+                      fcn = $1->function ();
+                    delete $1;
+                    $$ = new octave::tree_classdef_methods_list (fcn);
+                  }
+                | methods_list opt_sep method
+                  {
+                    YYUSE ($2);
+
+                    octave_value fcn;
+                    if ($3)
+                      fcn = $3->function ();
+                    delete $3;
+
+                    $1->append (fcn);
+                    $$ = $1;
+                  }
+                ;
+
+events_block    : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($6);
+
+                    if (! ($$ = parser.make_classdef_events_block
+                           ($1, $3, $5, $7, $2)))
+                      {
+                        // make_classdef_events_block deleted $3 and $5.
+                        YYABORT;
+                      }
+                  }
+                | EVENTS stash_comment opt_attr_list opt_sep END
+                  {
+                    YYUSE ($4);
+
+                    if (! ($$ = parser.make_classdef_events_block
+                           ($1, $3, nullptr, $5, $2)))
+                      {
+                        // make_classdef_events_block deleted $3.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+events_list     : class_event
+                  { $$ = new octave::tree_classdef_events_list ($1); }
+                | events_list opt_sep class_event
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+class_event     : identifier
+                  { $$ = new octave::tree_classdef_event ($1); }
+                ;
+
+enum_block      : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END
+                  {
+                    YYUSE ($4);
+                    YYUSE ($6);
+
+                    if (! ($$ = parser.make_classdef_enum_block
+                           ($1, $3, $5, $7, $2)))
+                      {
+                        // make_classdef_enum_block deleted $3 and $5.
+                        YYABORT;
+                      }
+                  }
+                | ENUMERATION stash_comment opt_attr_list opt_sep END
+                  {
+                    YYUSE ($4);
+
+                    if (! ($$ = parser.make_classdef_enum_block
+                           ($1, $3, nullptr, $5, $2)))
+                      {
+                        // make_classdef_enum_block deleted $3.
+                        YYABORT;
+                      }
+                  }
+                ;
+
+enum_list       : class_enum
+                  { $$ = new octave::tree_classdef_enum_list ($1); }
+                | enum_list opt_sep class_enum
+                  {
+                    YYUSE ($2);
+
+                    $1->append ($3);
+                    $$ = $1;
+                  }
+                ;
+
+class_enum      : identifier '(' expression ')'
+                  { $$ = new octave::tree_classdef_enum ($1, $3); }
+                ;
+
+// =============
+// Miscellaneous
+// =============
+
+stmt_begin      : // empty
+                  {
+                    $$ = 0;
+                    lexer.m_at_beginning_of_statement = true;
+                  }
+                ;
+
+stash_comment   : // empty
+                  { $$ = lexer.get_comment (); }
+                ;
+
+parse_error     : LEXICAL_ERROR
+                  {
+                    $$ = 0;
+                    std::string msg = $1->text ();
+                    parser.bison_error (msg.c_str ());
+                  }
+                | error
+                  { $$ = 0; }
+                ;
+
+sep_no_nl       : ','
+                  { $$ = ','; }
+                | ';'
+                  { $$ = ';'; }
+                | sep_no_nl ','
+                  { $$ = $1; }
+                | sep_no_nl ';'
+                  { $$ = $1; }
+                ;
+
+opt_sep_no_nl   : // empty
+                  { $$ = 0; }
+                | sep_no_nl
+                  { $$ = $1; }
+                ;
+
+opt_nl          : // empty
+                  { $$ = 0; }
+                | nl
+                  { $$ = $1; }
+                ;
+
+nl              : '\n'
+                  { $$ = '\n'; }
+                | nl '\n'
+                  { $$ = $1; }
+                ;
+
+sep             : ','
+                  { $$ = ','; }
+                | ';'
+                  { $$ = ';'; }
+                | '\n'
+                  { $$ = '\n'; }
+                | sep ','
+                  { $$ = $1; }
+                | sep ';'
+                  { $$ = $1; }
+                | sep '\n'
+                  { $$ = $1; }
+                ;
+
+opt_sep         : // empty
+                  { $$ = 0; }
+                | sep
+                  { $$ = $1; }
+                ;
+
+%%
+
+#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+   // Restore prevailing warning state for remainder of the file.
+#  pragma GCC diagnostic pop
+#endif
+
+// Generic error messages.
+
+#undef lexer
+#undef scanner
+
+static void
+yyerror (octave::base_parser& parser, const char *s)
+{
+  parser.bison_error (s);
+}
+
+namespace octave
+{
+  size_t
+  base_parser::parent_scope_info::size (void) const
+  {
+    return m_info.size ();
+  }
+
+  void
+  base_parser::parent_scope_info::push (const value_type& elt)
+  {
+    m_info.push_back (elt);
+  }
+
+  void
+  base_parser::parent_scope_info::push (const symbol_scope& scope)
+  {
+    push (value_type (scope, ""));
+  }
+
+  void
+  base_parser::parent_scope_info::pop (void)
+  {
+    m_info.pop_back ();
+  }
+
+  bool
+  base_parser::parent_scope_info::name_ok (const std::string& name)
+  {
+    // Name can't be the same as any parent function or any other
+    // function we've already seen.  We could maintain a complex
+    // tree structure of names, or we can just store the set of
+    // full names of all the functions, which must be unique.
+
+    std::string full_name;
+
+    for (size_t i = 0; i < size()-1; i++)
+      {
+        const value_type& elt = m_info[i];
+
+        if (name == elt.second)
+          return false;
+
+        full_name += elt.second + ">";
+      }
+
+    full_name += name;
+
+    if (m_all_names.find (full_name) != m_all_names.end ())
+      return false;
+
+    m_all_names.insert (full_name);
+
+    return true;
+  }
+
+  bool
+  base_parser::parent_scope_info::name_current_scope (const std::string& name)
+  {
+    if (! name_ok (name))
+      return false;
+
+    if (size () > 0)
+      m_info.back().second = name;
+
+    return true;
+  }
+
+  symbol_scope
+  base_parser::parent_scope_info::parent_scope (void) const
+  {
+    return size () > 1 ? m_info[size()-2].first : symbol_scope ();
+  }
+
+  std::string
+  base_parser::parent_scope_info::parent_name (void) const
+  {
+    return m_info[size()-2].second;
+  }
+
+  void base_parser::parent_scope_info::clear (void)
+  {
+    m_info.clear ();
+    m_all_names.clear ();
+  }
+
+  base_parser::base_parser (base_lexer& lxr)
+    : m_endfunction_found (false), m_autoloading (false),
+      m_fcn_file_from_relative_lookup (false),
+      m_parsing_subfunctions (false), m_parsing_local_functions (false),
+      m_max_fcn_depth (-1), m_curr_fcn_depth (-1), m_primary_fcn_scope (),
+      m_curr_class_name (), m_curr_package_name (), m_function_scopes (),
+      m_primary_fcn_ptr (nullptr), m_subfunction_names (),
+      m_classdef_object (nullptr), m_stmt_list (nullptr), m_lexer (lxr),
+      m_parser_state (yypstate_new ())
+  { }
+
+  base_parser::~base_parser (void)
+  {
+    delete m_stmt_list;
+
+    delete &m_lexer;
+
+    // FIXME: Deleting the internal Bison parser state structure does
+    // not clean up any partial parse trees in the event of an interrupt or
+    // error.  It's not clear how to safely do that with the C language
+    // parser that Bison generates.  The C++ language parser that Bison
+    // generates would do it for us automatically whenever an exception
+    // is thrown while parsing input, but there is currently no C++
+    // interface for a push parser.
+
+    yypstate_delete (static_cast<yypstate *> (m_parser_state));
+  }
+
+  void
+  base_parser::reset (void)
+  {
+    m_endfunction_found = false;
+    m_autoloading = false;
+    m_fcn_file_from_relative_lookup = false;
+    m_parsing_subfunctions = false;
+    m_parsing_local_functions = false;
+    m_max_fcn_depth = -1;
+    m_curr_fcn_depth = -1;
+    m_primary_fcn_scope = symbol_scope ();
+    m_curr_class_name = "";
+    m_curr_package_name = "";
+    m_function_scopes.clear ();
+    m_primary_fcn_ptr  = nullptr;
+    m_subfunction_names.clear ();
+    m_classdef_object = nullptr;
+
+    delete m_stmt_list;
+    m_stmt_list = nullptr;
+
+    m_lexer.reset ();
+
+    yypstate_delete (static_cast<yypstate *> (m_parser_state));
+    m_parser_state = yypstate_new ();
+  }
+
+  // Error mesages for mismatched end tokens.
+
+  static std::string
+  end_token_as_string (token::end_tok_type ettype)
+  {
+    std::string retval = "<unknown>";
+
+    switch (ettype)
+      {
+      case token::simple_end:
+        retval = "end";
+        break;
+
+      case token::classdef_end:
+        retval = "endclassdef";
+        break;
+
+      case token::enumeration_end:
+        retval = "endenumeration";
+        break;
+
+      case token::events_end:
+        retval = "endevents";
+        break;
+
+      case token::for_end:
+        retval = "endfor";
+        break;
+
+      case token::function_end:
+        retval = "endfunction";
+        break;
+
+      case token::if_end:
+        retval = "endif";
+        break;
+
+      case token::methods_end:
+        retval = "endmethods";
+        break;
+
+      case token::parfor_end:
+        retval = "endparfor";
+        break;
+
+      case token::properties_end:
+        retval = "endproperties";
+        break;
+
+      case token::switch_end:
+        retval = "endswitch";
+        break;
+
+      case token::try_catch_end:
+        retval = "end_try_catch";
+        break;
+
+      case token::unwind_protect_end:
+        retval = "end_unwind_protect";
+        break;
+
+      case token::while_end:
+        retval = "endwhile";
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    return retval;
+  }
+
+  void
+  base_parser::end_token_error (token *tok, token::end_tok_type expected)
+  {
+    std::string msg = ("'" + end_token_as_string (expected)
+                       + "' command matched by '"
+                       + end_token_as_string (tok->ettype ()) + "'");
+
+    bison_error (msg, tok->line (), tok->column ());
+  }
+
+  // Check to see that end tokens are properly matched.
+
+  bool
+  base_parser::end_token_ok (token *tok, token::end_tok_type expected)
+  {
+    token::end_tok_type ettype = tok->ettype ();
+
+    return ettype == expected || ettype == token::simple_end;
+  }
+
+  // Maybe print a warning if an assignment expression is used as the
+  // test in a logical expression.
+
+  void
+  base_parser::maybe_warn_assign_as_truth_value (tree_expression *expr)
+  {
+    if (expr->is_assignment_expression ()
+        && expr->paren_count () < 2)
+      {
+        if (m_lexer.m_fcn_file_full_name.empty ())
+          warning_with_id
+            ("Octave:assign-as-truth-value",
+             "suggest parenthesis around assignment used as truth value");
+        else
+          warning_with_id
+            ("Octave:assign-as-truth-value",
+             "suggest parenthesis around assignment used as truth value near line %d, column %d in file '%s'",
+             expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ());
+      }
+  }
+
+  // Maybe print a warning about switch labels that aren't constants.
+
+  void
+  base_parser::maybe_warn_variable_switch_label (tree_expression *expr)
+  {
+    if (! expr->is_constant ())
+      {
+        if (m_lexer.m_fcn_file_full_name.empty ())
+          warning_with_id ("Octave:variable-switch-label",
+                           "variable switch label");
+        else
+          warning_with_id
+            ("Octave:variable-switch-label",
+             "variable switch label near line %d, column %d in file '%s'",
+             expr->line (), expr->column (), m_lexer.m_fcn_file_full_name.c_str ());
+      }
+  }
+
+  // Make a constant.
+
+  tree_constant *
+  base_parser::make_constant (int op, token *tok_val)
+  {
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    tree_constant *retval = nullptr;
+
+    switch (op)
+      {
+      case NUM:
+        {
+          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->stash_original_text (tok_val->text_rep ());
+        }
+        break;
+
+      case DQ_STRING:
+      case SQ_STRING:
+        {
+          std::string txt = tok_val->text ();
+
+          char delim = op == DQ_STRING ? '"' : '\'';
+          octave_value tmp (txt, delim);
+
+          if (txt.empty ())
+            {
+              if (op == DQ_STRING)
+                tmp = octave_null_str::instance;
+              else
+                tmp = octave_null_sq_str::instance;
+            }
+
+          retval = new tree_constant (tmp, l, c);
+
+          if (op == DQ_STRING)
+            txt = undo_string_escapes (txt);
+
+          // FIXME: maybe this should also be handled by
+          // tok_val->text_rep () for character strings?
+          retval->stash_original_text (delim + txt + delim);
+        }
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    return retval;
+  }
+
+  // Make a function handle.
+
+  tree_fcn_handle *
+  base_parser::make_fcn_handle (token *tok_val)
+  {
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    tree_fcn_handle *retval = new tree_fcn_handle (tok_val->text (), l, c);
+
+    return retval;
+  }
+
+  // Make an anonymous function handle.
+
+  tree_anon_fcn_handle *
+  base_parser::make_anon_fcn_handle (tree_parameter_list *param_list,
+                                     tree_expression *expr)
+  {
+    // FIXME: need to get these from the location of the @ symbol.
+    int l = m_lexer.m_input_line_number;
+    int c = m_lexer.m_current_input_column;
+
+    symbol_scope fcn_scope = m_lexer.m_symtab_context.curr_scope ();
+    symbol_scope parent_scope = m_lexer.m_symtab_context.parent_scope ();
+
+    m_lexer.m_symtab_context.pop ();
+
+    expr->set_print_flag (false);
+
+    fcn_scope.mark_static ();
+
+    tree_anon_fcn_handle *retval
+      = new tree_anon_fcn_handle (param_list, expr, fcn_scope,
+                                  parent_scope, l, c);
+
+    std::ostringstream buf;
+
+    tree_print_code tpc (buf);
+
+    retval->accept (tpc);
+
+    std::string file = m_lexer.m_fcn_file_full_name;
+    if (! file.empty ())
+      buf << ": file: " << file;
+    else if (m_lexer.input_from_terminal ())
+      buf << ": *terminal input*";
+    else if (m_lexer.input_from_eval_string ())
+      buf << ": *eval string*";
+    buf << ": line: " << l << " column: " << c;
+
+    std::string scope_name = buf.str ();
+
+    fcn_scope.cache_name (scope_name);
+
+    // FIXME: Stash the filename.  This does not work and produces
+    // errors when executed.
+    //retval->stash_file_name (m_lexer.m_fcn_file_name);
+
+    return retval;
+  }
+
+  // Build a colon expression.
+
+  tree_expression *
+  base_parser::make_colon_expression (tree_expression *base,
+                                      tree_expression *limit,
+                                      tree_expression *incr)
+  {
+    tree_expression *retval = nullptr;
+
+    unwind_protect frame;
+
+    frame.protect_var (discard_error_messages);
+    frame.protect_var (discard_warning_messages);
+
+    discard_error_messages = true;
+    discard_warning_messages = true;
+
+    if (! base || ! limit)
+      {
+        delete base;
+        delete limit;
+        delete incr;
+
+        return retval;
+      }
+
+    int l = base->line ();
+    int c = base->column ();
+
+    tree_colon_expression *e
+      = new tree_colon_expression (base, limit, incr, l, c);
+
+    if (base->is_constant () && limit->is_constant ()
+        && (! incr || (incr && incr->is_constant ())))
+      {
+        try
+          {
+            tree_evaluator& tw
+              = __get_evaluator__ ("finish_colon_expression");
+
+            octave_value tmp = tw.evaluate (e);
+
+            tree_constant *tc_retval
+              = new tree_constant (tmp, e->line (), e->column ());
+
+            std::ostringstream buf;
+
+            tree_print_code tpc (buf);
+
+            e->accept (tpc);
+
+            tc_retval->stash_original_text (buf.str ());
+
+            delete e;
+
+            retval = tc_retval;
+          }
+        catch (const execution_exception&)
+          {
+            interpreter::recover_from_exception ();
+          }
+      }
+    else
+      retval = e;
+
+    return retval;
+  }
+
+  // Build a binary expression.
+
+  tree_expression *
+  base_parser::make_binary_op (int op, tree_expression *op1,
+                               token *tok_val, tree_expression *op2)
+  {
+    octave_value::binary_op t = octave_value::unknown_binary_op;
+
+    switch (op)
+      {
+      case POW:
+        t = octave_value::op_pow;
+        break;
+
+      case EPOW:
+        t = octave_value::op_el_pow;
+        break;
+
+      case '+':
+        t = octave_value::op_add;
+        break;
+
+      case '-':
+        t = octave_value::op_sub;
+        break;
+
+      case '*':
+        t = octave_value::op_mul;
+        break;
+
+      case '/':
+        t = octave_value::op_div;
+        break;
+
+      case EMUL:
+        t = octave_value::op_el_mul;
+        break;
+
+      case EDIV:
+        t = octave_value::op_el_div;
+        break;
+
+      case LEFTDIV:
+        t = octave_value::op_ldiv;
+        break;
+
+      case ELEFTDIV:
+        t = octave_value::op_el_ldiv;
+        break;
+
+      case EXPR_LT:
+        t = octave_value::op_lt;
+        break;
+
+      case EXPR_LE:
+        t = octave_value::op_le;
+        break;
+
+      case EXPR_EQ:
+        t = octave_value::op_eq;
+        break;
+
+      case EXPR_GE:
+        t = octave_value::op_ge;
+        break;
+
+      case EXPR_GT:
+        t = octave_value::op_gt;
+        break;
+
+      case EXPR_NE:
+        t = octave_value::op_ne;
+        break;
+
+      case EXPR_AND:
+        t = octave_value::op_el_and;
+        break;
+
+      case EXPR_OR:
+        t = octave_value::op_el_or;
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    return maybe_compound_binary_expression (op1, op2, l, c, t);
+  }
+
+  // Build a boolean expression.
+
+  tree_expression *
+  base_parser::make_boolean_op (int op, tree_expression *op1,
+                                token *tok_val, tree_expression *op2)
+  {
+    tree_boolean_expression::type t;
+
+    switch (op)
+      {
+      case EXPR_AND_AND:
+        t = tree_boolean_expression::bool_and;
+        break;
+
+      case EXPR_OR_OR:
+        t = tree_boolean_expression::bool_or;
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    return new tree_boolean_expression (op1, op2, l, c, t);
+  }
+
+  // Build a prefix expression.
+
+  tree_expression *
+  base_parser::make_prefix_op (int op, tree_expression *op1, token *tok_val)
+  {
+    octave_value::unary_op t = octave_value::unknown_unary_op;
+
+    switch (op)
+      {
+      case EXPR_NOT:
+        t = octave_value::op_not;
+        break;
+
+      case '+':
+        t = octave_value::op_uplus;
+        break;
+
+      case '-':
+        t = octave_value::op_uminus;
+        break;
+
+      case PLUS_PLUS:
+        t = octave_value::op_incr;
+        break;
+
+      case MINUS_MINUS:
+        t = octave_value::op_decr;
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    return new tree_prefix_expression (op1, l, c, t);
+  }
+
+  // Build a postfix expression.
+
+  tree_expression *
+  base_parser::make_postfix_op (int op, tree_expression *op1, token *tok_val)
+  {
+    octave_value::unary_op t = octave_value::unknown_unary_op;
+
+    switch (op)
+      {
+      case HERMITIAN:
+        t = octave_value::op_hermitian;
+        break;
+
+      case TRANSPOSE:
+        t = octave_value::op_transpose;
+        break;
+
+      case PLUS_PLUS:
+        t = octave_value::op_incr;
+        break;
+
+      case MINUS_MINUS:
+        t = octave_value::op_decr;
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    return new tree_postfix_expression (op1, l, c, t);
+  }
+
+  // Build an unwind-protect command.
+
+  tree_command *
+  base_parser::make_unwind_command (token *unwind_tok,
+                                    tree_statement_list *body,
+                                    tree_statement_list *cleanup_stmts,
+                                    token *end_tok,
+                                    comment_list *lc,
+                                    comment_list *mc)
+  {
+    tree_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::unwind_protect_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = unwind_tok->line ();
+        int c = unwind_tok->column ();
+
+        retval = new tree_unwind_protect_command (body, cleanup_stmts,
+                                                  lc, mc, tc, l, c);
+      }
+    else
+      {
+        delete body;
+        delete cleanup_stmts;
+
+        end_token_error (end_tok, token::unwind_protect_end);
+      }
+
+    return retval;
+  }
+
+  // Build a try-catch command.
+
+  tree_command *
+  base_parser::make_try_command (token *try_tok,
+                                 tree_statement_list *body,
+                                 char catch_sep,
+                                 tree_statement_list *cleanup_stmts,
+                                 token *end_tok,
+                                 comment_list *lc,
+                                 comment_list *mc)
+  {
+    tree_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::try_catch_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = try_tok->line ();
+        int c = try_tok->column ();
+
+        tree_identifier *id = nullptr;
+
+        if (! catch_sep && cleanup_stmts && ! cleanup_stmts->empty ())
+          {
+            tree_statement *stmt = cleanup_stmts->front ();
+
+            if (stmt)
+              {
+                tree_expression *expr = stmt->expression ();
+
+                if (expr && expr->is_identifier ())
+                  {
+                    id = dynamic_cast<tree_identifier *> (expr);
+
+                    cleanup_stmts->pop_front ();
+
+                    stmt->set_expression (nullptr);
+                    delete stmt;
+                  }
+              }
+          }
+
+        retval = new tree_try_catch_command (body, cleanup_stmts, id,
+                                             lc, mc, tc, l, c);
+      }
+    else
+      {
+        delete body;
+        delete cleanup_stmts;
+
+        end_token_error (end_tok, token::try_catch_end);
+      }
+
+    return retval;
+  }
+
+  // Build a while command.
+
+  tree_command *
+  base_parser::make_while_command (token *while_tok,
+                                   tree_expression *expr,
+                                   tree_statement_list *body,
+                                   token *end_tok,
+                                   comment_list *lc)
+  {
+    tree_command *retval = nullptr;
+
+    maybe_warn_assign_as_truth_value (expr);
+
+    if (end_token_ok (end_tok, token::while_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        m_lexer.m_looping--;
+
+        int l = while_tok->line ();
+        int c = while_tok->column ();
+
+        retval = new tree_while_command (expr, body, lc, tc, l, c);
+      }
+    else
+      {
+        delete expr;
+        delete body;
+
+        end_token_error (end_tok, token::while_end);
+      }
+
+    return retval;
+  }
+
+  // Build a do-until command.
+
+  tree_command *
+  base_parser::make_do_until_command (token *until_tok,
+                                      tree_statement_list *body,
+                                      tree_expression *expr,
+                                      comment_list *lc)
+  {
+    maybe_warn_assign_as_truth_value (expr);
+
+    comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+    m_lexer.m_looping--;
+
+    int l = until_tok->line ();
+    int c = until_tok->column ();
+
+    return new tree_do_until_command (expr, body, lc, tc, l, c);
+  }
+
+  // Build a for command.
+
+  tree_command *
+  base_parser::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)
+  {
+    tree_command *retval = nullptr;
+
+    bool parfor = tok_id == PARFOR;
+
+    if (end_token_ok (end_tok, parfor ? token::parfor_end : token::for_end))
+      {
+        expr->mark_as_for_cmd_expr ();
+
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        m_lexer.m_looping--;
+
+        int l = for_tok->line ();
+        int c = for_tok->column ();
+
+        if (lhs->length () == 1)
+          {
+            tree_expression *tmp = lhs->remove_front ();
+
+            retval = new tree_simple_for_command (parfor, tmp, expr, maxproc,
+                                                  body, lc, tc, l, c);
+
+            delete lhs;
+          }
+        else
+          {
+            if (parfor)
+              {
+                delete lhs;
+                delete expr;
+                delete maxproc;
+                delete body;
+
+                bison_error ("invalid syntax for parfor statement");
+              }
+            else
+              retval = new tree_complex_for_command (lhs, expr, body,
+                                                     lc, tc, l, c);
+          }
+      }
+    else
+      {
+        delete lhs;
+        delete expr;
+        delete maxproc;
+        delete body;
+
+        end_token_error (end_tok, parfor ? token::parfor_end : token::for_end);
+      }
+
+    return retval;
+  }
+
+  // Build a break command.
+
+  tree_command *
+  base_parser::make_break_command (token *break_tok)
+  {
+    int l = break_tok->line ();
+    int c = break_tok->column ();
+
+    if (! m_lexer.m_looping)
+      {
+        bison_error ("break must appear in a loop in the same file as loop command");
+        return nullptr;
+      }
+    else
+      return new tree_break_command (l, c);
+  }
+
+  // Build a continue command.
+
+  tree_command *
+  base_parser::make_continue_command (token *continue_tok)
+  {
+    int l = continue_tok->line ();
+    int c = continue_tok->column ();
+
+    return new tree_continue_command (l, c);
+  }
+
+  // Build a return command.
+
+  tree_command *
+  base_parser::make_return_command (token *return_tok)
+  {
+    int l = return_tok->line ();
+    int c = return_tok->column ();
+
+    return new tree_return_command (l, c);
+  }
+
+  // Start an if command.
+
+  tree_if_command_list *
+  base_parser::start_if_command (tree_expression *expr,
+                                 tree_statement_list *list)
+  {
+    maybe_warn_assign_as_truth_value (expr);
+
+    tree_if_clause *t = new tree_if_clause (expr, list);
+
+    return new tree_if_command_list (t);
+  }
+
+  // Finish an if command.
+
+  tree_if_command *
+  base_parser::finish_if_command (token *if_tok,
+                                  tree_if_command_list *list,
+                                  token *end_tok,
+                                  comment_list *lc)
+  {
+    tree_if_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::if_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = if_tok->line ();
+        int c = if_tok->column ();
+
+        if (list && ! list->empty ())
+          {
+            tree_if_clause *elt = list->front ();
+
+            if (elt)
+              {
+                elt->line (l);
+                elt->column (c);
+              }
+          }
+
+        retval = new tree_if_command (list, lc, tc, l, c);
+      }
+    else
+      {
+        delete list;
+
+        end_token_error (end_tok, token::if_end);
+      }
+
+    return retval;
+  }
+
+  // Build an elseif clause.
+
+  tree_if_clause *
+  base_parser::make_elseif_clause (token *elseif_tok,
+                                   tree_expression *expr,
+                                   tree_statement_list *list,
+                                   comment_list *lc)
+  {
+    maybe_warn_assign_as_truth_value (expr);
+
+    int l = elseif_tok->line ();
+    int c = elseif_tok->column ();
+
+    return new tree_if_clause (expr, list, lc, l, c);
+  }
+
+  // Finish a switch command.
+
+  tree_switch_command *
+  base_parser::finish_switch_command (token *switch_tok,
+                                      tree_expression *expr,
+                                      tree_switch_case_list *list,
+                                      token *end_tok,
+                                      comment_list *lc)
+  {
+    tree_switch_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::switch_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = switch_tok->line ();
+        int c = switch_tok->column ();
+
+        if (list && ! list->empty ())
+          {
+            tree_switch_case *elt = list->front ();
+
+            if (elt)
+              {
+                elt->line (l);
+                elt->column (c);
+              }
+          }
+
+        retval = new tree_switch_command (expr, list, lc, tc, l, c);
+      }
+    else
+      {
+        delete expr;
+        delete list;
+
+        end_token_error (end_tok, token::switch_end);
+      }
+
+    return retval;
+  }
+
+  // Build a switch case.
+
+  tree_switch_case *
+  base_parser::make_switch_case (token *case_tok,
+                                 tree_expression *expr,
+                                 tree_statement_list *list,
+                                 comment_list *lc)
+  {
+    maybe_warn_variable_switch_label (expr);
+
+    int l = case_tok->line ();
+    int c = case_tok->column ();
+
+    return new tree_switch_case (expr, list, lc, l, c);
+  }
+
+  // Build an assignment to a variable.
+
+  tree_expression *
+  base_parser::make_assign_op (int op, tree_argument_list *lhs,
+                               token *eq_tok, tree_expression *rhs)
+  {
+    octave_value::assign_op t = octave_value::unknown_assign_op;
+
+    switch (op)
+      {
+      case '=':
+        t = octave_value::op_asn_eq;
+        break;
+
+      case ADD_EQ:
+        t = octave_value::op_add_eq;
+        break;
+
+      case SUB_EQ:
+        t = octave_value::op_sub_eq;
+        break;
+
+      case MUL_EQ:
+        t = octave_value::op_mul_eq;
+        break;
+
+      case DIV_EQ:
+        t = octave_value::op_div_eq;
+        break;
+
+      case LEFTDIV_EQ:
+        t = octave_value::op_ldiv_eq;
+        break;
+
+      case POW_EQ:
+        t = octave_value::op_pow_eq;
+        break;
+
+      case EMUL_EQ:
+        t = octave_value::op_el_mul_eq;
+        break;
+
+      case EDIV_EQ:
+        t = octave_value::op_el_div_eq;
+        break;
+
+      case ELEFTDIV_EQ:
+        t = octave_value::op_el_ldiv_eq;
+        break;
+
+      case EPOW_EQ:
+        t = octave_value::op_el_pow_eq;
+        break;
+
+      case AND_EQ:
+        t = octave_value::op_el_and_eq;
+        break;
+
+      case OR_EQ:
+        t = octave_value::op_el_or_eq;
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    int l = eq_tok->line ();
+    int c = eq_tok->column ();
+
+    if (! lhs->is_simple_assign_lhs () && t != octave_value::op_asn_eq)
+      {
+        // Multiple assignments like [x,y] OP= rhs are only valid for
+        // '=', not '+=', etc.
+
+        delete lhs;
+        delete rhs;
+
+        bison_error ("computed multiple assignment not allowed", l, c);
+
+        return nullptr;
+      }
+
+    if (lhs->is_simple_assign_lhs ())
+      {
+        // We are looking at a simple assignment statement like x = rhs;
+
+        tree_expression *tmp = lhs->remove_front ();
+
+        if ((tmp->is_identifier () || tmp->is_index_expression ())
+            && iskeyword (tmp->name ()))
+          {
+            std::string kw = tmp->name ();
+
+            delete tmp;
+            delete lhs;
+            delete rhs;
+
+            bison_error ("invalid assignment to keyword \"" + kw + "\"", l, c);
+
+            return nullptr;
+          }
+
+        delete lhs;
+
+        return new tree_simple_assignment (tmp, rhs, false, l, c, t);
+      }
+    else
+      {
+        std::list<std::string> names = lhs->variable_names ();
+
+        for (const auto& kw : names)
+          {
+            if (iskeyword (kw))
+              {
+                delete lhs;
+                delete rhs;
+
+                bison_error ("invalid assignment to keyword \"" + kw + "\"",
+                             l, c);
+
+                return nullptr;
+              }
+          }
+
+        return new tree_multi_assignment (lhs, rhs, false, l, c);
+      }
+  }
+
+  // Define a script.
+
+  void
+  base_parser::make_script (tree_statement_list *cmds,
+                            tree_statement *end_script)
+  {
+    if (! cmds)
+      cmds = new tree_statement_list ();
+
+    cmds->append (end_script);
+
+    symbol_scope script_scope = m_lexer.m_symtab_context.curr_scope ();
+
+    script_scope.cache_name (m_lexer.m_fcn_file_full_name);
+
+    octave_user_script *script
+      = new octave_user_script (m_lexer.m_fcn_file_full_name,
+                                m_lexer.m_fcn_file_name, script_scope,
+                                cmds, m_lexer.m_help_text);
+
+    m_lexer.m_symtab_context.pop ();
+    m_lexer.m_help_text = "";
+
+    sys::time now;
+
+    script->stash_fcn_file_time (now);
+
+    m_primary_fcn_ptr = script;
+  }
+
+  // Define a function.
+
+  // FIXME: combining start_function, finish_function, and
+  // recover_from_parsing_function should be possible, but it makes
+  // for a large mess.  Maybe this could be a bit better organized?
+
+  tree_function_def *
+  base_parser::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)
+  {
+    tree_function_def *retval = nullptr;
+
+    int l = fcn_tok->line ();
+    int c = fcn_tok->column ();
+
+    octave_user_function *tmp_fcn
+      = start_function (id, param_list, body, end_fcn_stmt);
+
+    retval = finish_function (ret_list, tmp_fcn, lc, l, c);
+
+    recover_from_parsing_function ();
+
+    return retval;
+  }
+
+  // Begin defining a function.
+
+  octave_user_function *
+  base_parser::start_function (tree_identifier *id,
+                               tree_parameter_list *param_list,
+                               tree_statement_list *body,
+                               tree_statement *end_fcn_stmt)
+  {
+    // We'll fill in the return list later.
+
+    std::string id_name = id->name ();
+
+    delete id;
+
+    if (m_lexer.m_parsing_classdef_get_method)
+      id_name.insert (0, "get.");
+    else if (m_lexer.m_parsing_classdef_set_method)
+      id_name.insert (0, "set.");
+
+    m_lexer.m_parsing_classdef_get_method = false;
+    m_lexer.m_parsing_classdef_set_method = false;
+
+    if (! body)
+      body = new tree_statement_list ();
+
+    body->append (end_fcn_stmt);
+
+    octave_user_function *fcn
+      = new octave_user_function (m_lexer.m_symtab_context.curr_scope (),
+                                  param_list, nullptr, body);
+
+    if (fcn)
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        fcn->stash_trailing_comment (tc);
+        fcn->stash_fcn_end_location (end_fcn_stmt->line (),
+                                     end_fcn_stmt->column ());
+      }
+
+    // If input is coming from a file, issue a warning if the name of
+    // the file does not match the name of the function stated in the
+    // file.  Matlab doesn't provide a diagnostic (it ignores the stated
+    // name).
+    if (! m_autoloading && m_lexer.m_reading_fcn_file
+        && m_curr_fcn_depth == 0 && ! m_parsing_subfunctions)
+      {
+        // FIXME: should m_lexer.m_fcn_file_name already be
+        // preprocessed when we get here?  It seems to only be a
+        // problem with relative filenames.
+
+        std::string nm = m_lexer.m_fcn_file_name;
+
+        size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ());
+
+        if (pos != std::string::npos)
+          nm = m_lexer.m_fcn_file_name.substr (pos+1);
+
+        if (nm != id_name)
+          {
+            warning_with_id
+              ("Octave:function-name-clash",
+               "function name '%s' does not agree with function filename '%s'",
+               id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ());
+
+            id_name = nm;
+          }
+      }
+
+    if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_classdef_file || m_autoloading)
+      {
+        sys::time now;
+
+        fcn->stash_fcn_file_name (m_lexer.m_fcn_file_full_name);
+        fcn->stash_fcn_file_time (now);
+        fcn->stash_dir_name (m_lexer.m_dir_name);
+        fcn->stash_package_name (m_lexer.m_package_name);
+        fcn->mark_as_system_fcn_file ();
+
+        if (m_fcn_file_from_relative_lookup)
+          fcn->mark_relative ();
+
+        if (m_lexer.m_parsing_class_method)
+          {
+            if (m_curr_class_name == id_name)
+              fcn->mark_as_class_constructor ();
+            else
+              fcn->mark_as_class_method ();
+
+            fcn->stash_dispatch_class (m_curr_class_name);
+          }
+
+        std::string nm = fcn->fcn_file_name ();
+
+        sys::file_stat fs (nm);
+
+        if (fs && fs.is_newer (now))
+          warning_with_id ("Octave:future-time-stamp",
+                           "time stamp for '%s' is in the future", nm.c_str ());
+      }
+    else if (! m_lexer.input_from_tmp_history_file ()
+             && ! m_lexer.m_force_script
+             && m_lexer.m_reading_script_file
+             && m_lexer.m_fcn_file_name == id_name)
+      {
+        warning ("function '%s' defined within script file '%s'",
+                 id_name.c_str (), m_lexer.m_fcn_file_full_name.c_str ());
+      }
+
+    fcn->stash_function_name (id_name);
+
+    // Record help text for functions other than nested functions.
+    // We cannot currently record help for nested functions (bug #46008)
+    // because the doc_string of the outermost function is read first,
+    // whereas this function is called for the innermost function first.
+    // We could have a stack of help_text in lexer.
+    if (! m_lexer.m_help_text.empty () && m_curr_fcn_depth == 0)
+      {
+        fcn->document (m_lexer.m_help_text);
+
+        m_lexer.m_help_text = "";
+      }
+
+    if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0
+        && ! m_parsing_subfunctions)
+      m_primary_fcn_ptr = fcn;
+
+    return fcn;
+  }
+
+  tree_statement *
+  base_parser::make_end (const std::string& type, bool eof, int l, int c)
+  {
+    return make_statement (new tree_no_op_command (type, eof, l, c));
+  }
+
+  tree_function_def *
+  base_parser::finish_function (tree_parameter_list *ret_list,
+                                octave_user_function *fcn,
+                                comment_list *lc,
+                                int l, int c)
+  {
+    tree_function_def *retval = nullptr;
+
+    if (ret_list)
+      ret_list->mark_as_formal_parameters ();
+
+    if (fcn)
+      {
+        std::string nm = fcn->name ();
+        std::string file = fcn->fcn_file_name ();
+
+        std::string tmp = nm;
+        if (! file.empty ())
+          tmp += ": " + file;
+
+        symbol_scope fcn_scope = fcn->scope ();
+        fcn_scope.cache_name (tmp);
+        fcn_scope.install_auto_fcn_vars ();
+
+        if (lc)
+          fcn->stash_leading_comment (lc);
+
+        fcn->define_ret_list (ret_list);
+
+        if (m_curr_fcn_depth > 0 || m_parsing_subfunctions)
+          {
+            fcn->stash_fcn_location (l, c);
+            fcn->stash_parent_fcn_name (m_lexer.m_fcn_file_name);
+
+            octave_value ov_fcn (fcn);
+
+            if (m_endfunction_found && m_function_scopes.size () > 1)
+              {
+                fcn->mark_as_nested_function ();
+                fcn_scope.set_nesting_depth (m_curr_fcn_depth);
+
+                symbol_scope pscope = m_function_scopes.parent_scope ();
+                fcn_scope.set_parent (pscope);
+                fcn_scope.set_primary_parent (m_primary_fcn_scope);
+                pscope.install_nestfunction (nm, ov_fcn, fcn_scope);
+              }
+            else
+              {
+                fcn->mark_as_subfunction ();
+                m_subfunction_names.push_back (nm);
+                fcn_scope.set_parent (m_primary_fcn_scope);
+                m_primary_fcn_scope.install_subfunction (nm, ov_fcn);
+              }
+          }
+
+        if (m_curr_fcn_depth == 0)
+          fcn_scope.update_nest ();
+
+        if (! m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0)
+          {
+            // We are either reading a script file or defining a function
+            // at the command line, so this definition creates a
+            // tree_function object that is placed in the parse tree.
+            // Otherwise, it is just inserted in the symbol table,
+            // either as a subfunction or nested function (see above),
+            // or as the primary function for the file, via
+            // m_primary_fcn_ptr (see also load_fcn_from_file,,
+            // parse_fcn_file, and
+            // fcn_info::fcn_info_rep::find_user_function).
+
+            if (m_lexer.m_buffer_function_text)
+              {
+                fcn->cache_function_text (m_lexer.m_function_text,
+                                          fcn->time_parsed ());
+                m_lexer.m_buffer_function_text = false;
+              }
+
+            retval = new tree_function_def (fcn);
+          }
+      }
+
+    return retval;
+  }
+
+  void
+  base_parser::recover_from_parsing_function (void)
+  {
+    m_lexer.m_symtab_context.pop ();
+
+    if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0
+        && ! m_parsing_subfunctions)
+      m_parsing_subfunctions = true;
+
+    m_curr_fcn_depth--;
+    m_function_scopes.pop ();
+
+    m_lexer.m_defining_func--;
+    m_lexer.m_parsed_function_name.pop ();
+    m_lexer.m_looking_at_return_list = false;
+    m_lexer.m_looking_at_parameter_list = false;
+  }
+
+  tree_funcall *
+  base_parser::make_superclass_ref (const std::string& method_nm,
+                                    const std::string& class_nm)
+  {
+    octave_value_list args;
+
+    args(1) = class_nm;
+    args(0) = method_nm;
+
+    symbol_table& symtab
+      = __get_symbol_table__ ("base_parser::make_superclass_ref");
+
+    octave_value fcn
+      = symtab.find_built_in_function ("__superclass_reference__");
+
+    return new tree_funcall (fcn, args);
+  }
+
+  tree_funcall *
+  base_parser::make_meta_class_query (const std::string& class_nm)
+  {
+    octave_value_list args;
+
+    args(0) = class_nm;
+
+    symbol_table& symtab
+      = __get_symbol_table__ ("base_parser::make_meta_class_query");
+
+    octave_value fcn
+      = symtab.find_built_in_function ("__meta_class_query__");
+
+    return new tree_funcall (fcn, args);
+  }
+
+  // A CLASSDEF block defines a class that has a constructor and other
+  // methods, but it is not an executable command.  Parsing the block
+  // makes some changes in the symbol table (inserting the constructor
+  // and methods, and adding to the list of known objects) and creates
+  // a parse tree containing meta information about the class.
+
+  tree_classdef *
+  base_parser::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)
+  {
+    tree_classdef *retval = nullptr;
+
+    m_lexer.m_symtab_context.pop ();
+
+    std::string cls_name = id->name ();
+
+    std::string nm = m_lexer.m_fcn_file_name;
+
+    size_t pos = nm.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    if (pos != std::string::npos)
+      nm = m_lexer.m_fcn_file_name.substr (pos+1);
+
+    if (nm != cls_name)
+      {
+        delete a;
+        delete id;
+        delete sc;
+        delete body;
+
+        bison_error ("invalid classdef definition, the class name must match the filename");
+
+      }
+    else
+      {
+        if (end_token_ok (end_tok, token::classdef_end))
+          {
+            comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+            int l = tok_val->line ();
+            int c = tok_val->column ();
+
+            if (! body)
+              body = new tree_classdef_body ();
+
+            retval = new tree_classdef (a, id, sc, body, lc, tc,
+                                        m_curr_package_name, l, c);
+          }
+        else
+          {
+            delete a;
+            delete id;
+            delete sc;
+            delete body;
+
+            end_token_error (end_tok, token::switch_end);
+          }
+      }
+
+    return retval;
+  }
+
+  tree_classdef_properties_block *
+  base_parser::make_classdef_properties_block (token *tok_val,
+                                               tree_classdef_attribute_list *a,
+                                               tree_classdef_property_list *plist,
+                                               token *end_tok,
+                                               comment_list *lc)
+  {
+    tree_classdef_properties_block *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::properties_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = tok_val->line ();
+        int c = tok_val->column ();
+
+        if (! plist)
+          plist = new tree_classdef_property_list ();
+
+        retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c);
+      }
+    else
+      {
+        delete a;
+        delete plist;
+
+        end_token_error (end_tok, token::properties_end);
+      }
+
+    return retval;
+  }
+
+  tree_classdef_methods_block *
+  base_parser::make_classdef_methods_block (token *tok_val,
+                                            tree_classdef_attribute_list *a,
+                                            tree_classdef_methods_list *mlist,
+                                            token *end_tok,
+                                            comment_list *lc)
+  {
+    tree_classdef_methods_block *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::methods_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = tok_val->line ();
+        int c = tok_val->column ();
+
+        if (! mlist)
+          mlist = new tree_classdef_methods_list ();
+
+        retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c);
+      }
+    else
+      {
+        delete a;
+        delete mlist;
+
+        end_token_error (end_tok, token::methods_end);
+      }
+
+    return retval;
+  }
+
+  tree_classdef_events_block *
+  base_parser::make_classdef_events_block (token *tok_val,
+                                           tree_classdef_attribute_list *a,
+                                           tree_classdef_events_list *elist,
+                                           token *end_tok,
+                                           comment_list *lc)
+  {
+    tree_classdef_events_block *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::events_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = tok_val->line ();
+        int c = tok_val->column ();
+
+        if (! elist)
+          elist = new tree_classdef_events_list ();
+
+        retval = new tree_classdef_events_block (a, elist, lc, tc, l, c);
+      }
+    else
+      {
+        delete a;
+        delete elist;
+
+        end_token_error (end_tok, token::events_end);
+      }
+
+    return retval;
+  }
+
+  tree_classdef_enum_block *
+  base_parser::make_classdef_enum_block (token *tok_val,
+                                         tree_classdef_attribute_list *a,
+                                         tree_classdef_enum_list *elist,
+                                         token *end_tok,
+                                         comment_list *lc)
+  {
+    tree_classdef_enum_block *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::enumeration_end))
+      {
+        comment_list *tc = m_lexer.m_comment_buf.get_comment ();
+
+        int l = tok_val->line ();
+        int c = tok_val->column ();
+
+        if (! elist)
+          elist = new tree_classdef_enum_list ();
+
+        retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c);
+      }
+    else
+      {
+        delete a;
+        delete elist;
+
+        end_token_error (end_tok, token::enumeration_end);
+      }
+
+    return retval;
+  }
+
+  octave_user_function*
+  base_parser::start_classdef_external_method (tree_identifier *id,
+                                               tree_parameter_list *pl)
+  {
+    octave_user_function* retval = nullptr;
+
+    // External methods are only allowed within @-folders. In this case,
+    // m_curr_class_name will be non-empty.
+
+    if (! m_curr_class_name.empty ())
+      {
+
+        std::string mname = id->name ();
+
+        // Methods that cannot be declared outside the classdef file:
+        // - methods with '.' character (e.g. property accessors)
+        // - class constructor
+        // - `delete'
+
+        if (mname.find_first_of (".") == std::string::npos
+            && mname != "delete"
+            && mname != m_curr_class_name)
+          {
+            // Create a dummy function that is used until the real method
+            // is loaded.
+
+            retval = new octave_user_function (symbol_scope (), pl);
+
+            retval->stash_function_name (mname);
+
+            int l = id->line ();
+            int c = id->column ();
+
+            retval->stash_fcn_location (l, c);
+          }
+        else
+          bison_error ("invalid external method declaration, an external "
+                       "method cannot be the class constructor, `delete' "
+                       "or have a dot (.) character in its name");
+      }
+    else
+      bison_error ("external methods are only allowed in @-folders");
+
+    if (! retval)
+      delete id;
+
+    return retval;
+  }
+
+  tree_function_def *
+  base_parser::finish_classdef_external_method (octave_user_function *fcn,
+                                                tree_parameter_list *ret_list,
+                                                comment_list *cl)
+  {
+    if (ret_list)
+      fcn->define_ret_list (ret_list);
+
+    if (cl)
+      fcn->stash_leading_comment (cl);
+
+    int l = fcn->beginning_line ();
+    int c = fcn->beginning_column ();
+
+    return new tree_function_def (fcn, l, c);
+  }
+
+  void
+  base_parser::finish_classdef_file (tree_classdef *cls,
+                                     tree_statement_list *local_fcns)
+  {
+    if (m_lexer.m_reading_classdef_file)
+      m_classdef_object = cls;
+
+    if (local_fcns)
+      {
+        symbol_table& symtab
+          = __get_symbol_table__ ("base_parser::finish_classdef_file");
+
+        for (tree_statement *elt : *local_fcns)
+          {
+            tree_command *cmd = elt->command ();
+
+            tree_function_def *fcn_def
+              = dynamic_cast<tree_function_def *> (cmd);
+
+            octave_value ov_fcn = fcn_def->function ();
+            octave_function *fcn = ov_fcn.function_value ();
+            std::string nm = fcn->name ();
+            std::string file = fcn->fcn_file_name ();
+
+            symtab.install_local_function (nm, ov_fcn, file);
+          }
+
+        delete local_fcns;
+      }
+  }
+
+  // Make an index expression.
+
+  tree_index_expression *
+  base_parser::make_index_expression (tree_expression *expr,
+                                      tree_argument_list *args,
+                                      char type)
+  {
+    tree_index_expression *retval = nullptr;
+
+    if (args && args->has_magic_tilde ())
+      {
+        delete expr;
+        delete args;
+
+        bison_error ("invalid use of empty argument (~) in index expression");
+      }
+    else
+      {
+        int l = expr->line ();
+        int c = expr->column ();
+
+        if (! expr->is_postfix_indexed ())
+          expr->set_postfix_index (type);
+
+        if (expr->is_index_expression ())
+          {
+            tree_index_expression *tmp =
+              static_cast<tree_index_expression *> (expr);
+
+            tmp->append (args, type);
+
+            retval = tmp;
+          }
+        else
+          retval = new tree_index_expression (expr, args, l, c, type);
+      }
+
+    return retval;
+  }
+
+  // Make an indirect reference expression.
+
+  tree_index_expression *
+  base_parser::make_indirect_ref (tree_expression *expr,
+                                  const std::string& elt)
+  {
+    tree_index_expression *retval = nullptr;
+
+    int l = expr->line ();
+    int c = expr->column ();
+
+    if (! expr->is_postfix_indexed ())
+      expr->set_postfix_index ('.');
+
+    if (expr->is_index_expression ())
+      {
+        tree_index_expression *tmp = static_cast<tree_index_expression *> (expr);
+
+        tmp->append (elt);
+
+        retval = tmp;
+      }
+    else
+      retval = new tree_index_expression (expr, elt, l, c);
+
+    m_lexer.m_looking_at_indirect_ref = false;
+
+    return retval;
+  }
+
+  // Make an indirect reference expression with dynamic field name.
+
+  tree_index_expression *
+  base_parser::make_indirect_ref (tree_expression *expr,
+                                  tree_expression *elt)
+  {
+    tree_index_expression *retval = nullptr;
+
+    int l = expr->line ();
+    int c = expr->column ();
+
+    if (! expr->is_postfix_indexed ())
+      expr->set_postfix_index ('.');
+
+    if (expr->is_index_expression ())
+      {
+        tree_index_expression *tmp = static_cast<tree_index_expression *> (expr);
+
+        tmp->append (elt);
+
+        retval = tmp;
+      }
+    else
+      retval = new tree_index_expression (expr, elt, l, c);
+
+    m_lexer.m_looking_at_indirect_ref = false;
+
+    return retval;
+  }
+
+  // Make a declaration command.
+
+  tree_decl_command *
+  base_parser::make_decl_command (int tok, token *tok_val,
+                                  tree_decl_init_list *lst)
+  {
+    tree_decl_command *retval = nullptr;
+
+    int l = tok_val->line ();
+    int c = tok_val->column ();
+
+    if (lst)
+      m_lexer.mark_as_variables (lst->variable_names ());
+
+    switch (tok)
+      {
+      case GLOBAL:
+        {
+          retval = new tree_decl_command ("global", lst, l, c);
+          retval->mark_global ();
+        }
+        break;
+
+      case PERSISTENT:
+        if (m_curr_fcn_depth >= 0)
+          {
+            retval = new tree_decl_command ("persistent", lst, l, c);
+            retval->mark_persistent ();
+          }
+        else
+          {
+            if (m_lexer.m_reading_script_file)
+              warning ("ignoring persistent declaration near line %d of file '%s'",
+                       l, m_lexer.m_fcn_file_full_name.c_str ());
+            else
+              warning ("ignoring persistent declaration near line %d", l);
+          }
+        break;
+
+      default:
+        panic_impossible ();
+        break;
+      }
+
+    return retval;
+  }
+
+  bool
+  base_parser::validate_param_list (tree_parameter_list *lst,
+                                    tree_parameter_list::in_or_out type)
+  {
+    std::set<std::string> dict;
+
+    for (tree_decl_elt *elt : *lst)
+      {
+        tree_identifier *id = elt->ident ();
+
+        if (id)
+          {
+            std::string name = id->name ();
+
+            if (id->is_black_hole ())
+              {
+                if (type != tree_parameter_list::in)
+                  {
+                    bison_error ("invalid use of ~ in output list");
+                    return false;
+                  }
+              }
+            else if (dict.find (name) != dict.end ())
+              {
+                bison_error ("'" + name
+                             + "' appears more than once in parameter list");
+                return false;
+              }
+            else
+              dict.insert (name);
+          }
+      }
+
+    std::string va_type = (type == tree_parameter_list::in
+                           ? "varargin" : "varargout");
+
+    size_t len = lst->length ();
+
+    if (len > 0)
+      {
+        tree_decl_elt *elt = lst->back ();
+
+        tree_identifier *id = elt->ident ();
+
+        if (id && id->name () == va_type)
+          {
+            if (len == 1)
+              lst->mark_varargs_only ();
+            else
+              lst->mark_varargs ();
+
+            tree_parameter_list::iterator p = lst->end ();
+            --p;
+            delete *p;
+            lst->erase (p);
+          }
+      }
+
+    return true;
+  }
+
+  bool
+  base_parser::validate_array_list (tree_expression *e)
+  {
+    bool retval = true;
+
+    tree_array_list *al = dynamic_cast<tree_array_list *> (e);
+
+    for (tree_argument_list* row : *al)
+      {
+        if (row && row->has_magic_tilde ())
+          {
+            retval = false;
+
+            if (e->is_matrix ())
+              bison_error ("invalid use of tilde (~) in matrix expression");
+            else
+              bison_error ("invalid use of tilde (~) in cell expression");
+
+            break;
+          }
+      }
+
+    return retval;
+  }
+
+  tree_argument_list *
+  base_parser::validate_matrix_for_assignment (tree_expression *e)
+  {
+    tree_argument_list *retval = nullptr;
+
+    if (e->is_constant ())
+      {
+        tree_evaluator& tw
+          = __get_evaluator__ ("validate_matrix_for_assignment");
+
+        octave_value ov = tw.evaluate (e);
+
+        delete e;
+
+        if (ov.isempty ())
+          bison_error ("invalid empty left hand side of assignment");
+        else
+          bison_error ("invalid constant left hand side of assignment");
+      }
+    else
+      {
+        bool is_simple_assign = true;
+
+        tree_argument_list *tmp = nullptr;
+
+        if (e->is_matrix ())
+          {
+            tree_matrix *mat = dynamic_cast<tree_matrix *> (e);
+
+            if (mat && mat->size () == 1)
+              {
+                tmp = mat->front ();
+                mat->pop_front ();
+                delete e;
+                is_simple_assign = false;
+              }
+          }
+        else
+          tmp = new tree_argument_list (e);
+
+        if (tmp && tmp->is_valid_lvalue_list ())
+          {
+            m_lexer.mark_as_variables (tmp->variable_names ());
+            retval = tmp;
+          }
+        else
+          {
+            delete tmp;
+
+            bison_error ("invalid left hand side of assignment");
+          }
+
+        if (retval && is_simple_assign)
+          retval->mark_as_simple_assign_lhs ();
+      }
+
+    return retval;
+  }
+
+  // Finish building an array_list.
+
+  tree_expression *
+  base_parser::finish_array_list (tree_array_list *array_list)
+  {
+    tree_expression *retval = array_list;
+
+    unwind_protect frame;
+
+    frame.protect_var (discard_error_messages);
+    frame.protect_var (discard_warning_messages);
+
+    discard_error_messages = true;
+    discard_warning_messages = true;
+
+    if (array_list->all_elements_are_constant ())
+      {
+        try
+          {
+            tree_evaluator& tw
+              = __get_evaluator__ ("finish_array_list");
+
+            octave_value tmp = tw.evaluate (array_list);
+
+            tree_constant *tc_retval
+              = new tree_constant (tmp, array_list->line (),
+                                   array_list->column ());
+
+            std::ostringstream buf;
+
+            tree_print_code tpc (buf);
+
+            array_list->accept (tpc);
+
+            tc_retval->stash_original_text (buf.str ());
+
+            delete array_list;
+
+            retval = tc_retval;
+          }
+        catch (const execution_exception&)
+          {
+            interpreter::recover_from_exception ();
+          }
+      }
+
+    return retval;
+  }
+
+  // Finish building a matrix list.
+
+  tree_expression *
+  base_parser::finish_matrix (tree_matrix *m)
+  {
+    return (m
+            ? finish_array_list (m)
+            : new tree_constant (octave_null_matrix::instance));
+  }
+
+  // Finish building a cell list.
+
+  tree_expression *
+  base_parser::finish_cell (tree_cell *c)
+  {
+    return (c
+            ? finish_array_list (c)
+            : new tree_constant (octave_value (Cell ())));
+  }
+
+  void
+  base_parser::maybe_warn_missing_semi (tree_statement_list *t)
+  {
+    if (m_curr_fcn_depth >= 0)
+      {
+        tree_statement *tmp = t->back ();
+
+        if (tmp->is_expression ())
+          warning_with_id
+            ("Octave:missing-semicolon",
+             "missing semicolon near line %d, column %d in file '%s'",
+             tmp->line (), tmp->column (), m_lexer.m_fcn_file_full_name.c_str ());
+      }
+  }
+
+  tree_statement_list *
+  base_parser::set_stmt_print_flag (tree_statement_list *list,
+                                    char sep, bool warn_missing_semi)
+  {
+    tree_statement *tmp = list->back ();
+
+    switch (sep)
+      {
+      case ';':
+        tmp->set_print_flag (false);
+        break;
+
+      case 0:
+      case ',':
+      case '\n':
+        tmp->set_print_flag (true);
+        if (warn_missing_semi)
+          maybe_warn_missing_semi (list);
+        break;
+
+      default:
+        warning ("unrecognized separator type!");
+        break;
+      }
+
+    // Even if a statement is null, we add it to the list then remove it
+    // here so that the print flag is applied to the correct statement.
+
+    if (tmp->is_null_statement ())
+      {
+        list->pop_back ();
+        delete tmp;
+      }
+
+    return list;
+  }
+
+  // Finish building a statement.
+  template <typename T>
+  tree_statement *
+  base_parser::make_statement (T *arg)
+  {
+    comment_list *comment = m_lexer.get_comment ();
+
+    return new tree_statement (arg, comment);
+  }
+
+  tree_statement_list *
+  base_parser::make_statement_list (tree_statement *stmt)
+  {
+    return new tree_statement_list (stmt);
+  }
+
+  tree_statement_list *
+  base_parser::append_statement_list (tree_statement_list *list,
+                                      char sep, tree_statement *stmt,
+                                      bool warn_missing_semi)
+  {
+    set_stmt_print_flag (list, sep, warn_missing_semi);
+
+    list->append (stmt);
+
+    return list;
+  }
+
+  void
+  base_parser::bison_error (const std::string& str, int l, int c)
+  {
+    int err_line = l < 0 ? m_lexer.m_input_line_number : l;
+    int err_col = c < 0 ? m_lexer.m_current_input_column - 1 : c;
+
+    std::ostringstream output_buf;
+
+    if (m_lexer.m_reading_fcn_file || m_lexer.m_reading_script_file
+        || m_lexer.m_reading_classdef_file)
+      output_buf << "parse error near line " << err_line
+                 << " of file " << m_lexer.m_fcn_file_full_name;
+    else
+      output_buf << "parse error:";
+
+    if (str != "parse error")
+      output_buf << "\n\n  " << str;
+
+    output_buf << "\n\n";
+
+    std::string curr_line = m_lexer.m_current_input_line;
+
+    if (! curr_line.empty ())
+      {
+        size_t len = curr_line.length ();
+
+        if (curr_line[len-1] == '\n')
+          curr_line.resize (len-1);
+
+        // Print the line, maybe with a pointer near the error token.
+
+        output_buf << ">>> " << curr_line << "\n";
+
+        if (err_col == 0)
+          err_col = len;
+
+        for (int i = 0; i < err_col + 3; i++)
+          output_buf << " ";
+
+        output_buf << "^";
+      }
+
+    output_buf << "\n";
+
+    m_parse_error_msg = output_buf.str ();
+  }
+
+  int
+  parser::run (void)
+  {
+    int status = -1;
+
+    yypstate *pstate = static_cast<yypstate *> (m_parser_state);
+
+    try
+      {
+        status = octave_pull_parse (pstate, *this);
+      }
+    catch (execution_exception& e)
+      {
+        std::string file = m_lexer.m_fcn_file_full_name;
+
+        if (file.empty ())
+          error (e, "parse error");
+        else
+          error (e, "parse error in %s", file.c_str ());
+      }
+    catch (const exit_exception&)
+      {
+        throw;
+      }
+    catch (interrupt_exception &)
+      {
+        throw;
+      }
+    catch (...)
+      {
+        std::string file = m_lexer.m_fcn_file_full_name;
+
+        if (file.empty ())
+          error ("unexpected exception while parsing input");
+        else
+          error ("unexpected exception while parsing %s", file.c_str ());
+      }
+
+    if (status != 0)
+      parse_error ("%s", m_parse_error_msg.c_str ());
+
+    return status;
+  }
+
+  // Parse input from INPUT.  Pass TRUE for EOF if the end of INPUT should
+  // finish the parse.
+
+  int
+  push_parser::run (const std::string& input, bool eof)
+  {
+    int status = -1;
+
+    dynamic_cast<push_lexer&> (m_lexer).append_input (input, eof);
+
+    do
+      {
+        YYSTYPE lval;
+
+        int token = octave_lex (&lval, m_lexer.m_scanner);
+
+        if (token < 0)
+          {
+            if (! eof && m_lexer.at_end_of_buffer ())
+              {
+                status = -1;
+                break;
+              }
+          }
+
+        yypstate *pstate = static_cast<yypstate *> (m_parser_state);
+
+        try
+          {
+            status = octave_push_parse (pstate, token, &lval, *this);
+          }
+        catch (execution_exception& e)
+          {
+            std::string file = m_lexer.m_fcn_file_full_name;
+
+            if (file.empty ())
+              error (e, "parse error");
+            else
+              error (e, "parse error in %s", file.c_str ());
+          }
+        catch (const exit_exception&)
+          {
+            throw;
+          }
+        catch (interrupt_exception &)
+          {
+            throw;
+          }
+        catch (...)
+          {
+            std::string file = m_lexer.m_fcn_file_full_name;
+
+            if (file.empty ())
+              error ("unexpected exception while parsing input");
+            else
+              error ("unexpected exception while parsing %s", file.c_str ());
+          }
+      }
+    while (status == YYPUSH_MORE);
+
+    if (status != 0)
+      parse_error ("%s", m_parse_error_msg.c_str ());
+
+    return status;
+  }
+
+  static void
+  safe_fclose (FILE *f)
+  {
+    if (f)
+      fclose (static_cast<FILE *> (f));
+  }
+
+  static octave_value
+  parse_fcn_file (const std::string& full_file, const std::string& file,
+                  const std::string& dir_name, const std::string& dispatch_type,
+                  const std::string& package_name, bool require_file,
+                  bool force_script, bool autoload, bool relative_lookup,
+                  const std::string& warn_for)
+  {
+    octave_value retval;
+
+    unwind_protect frame;
+
+    octave_function *fcn_ptr = nullptr;
+
+    // Open function file and parse.
+
+    FILE *in_stream = command_editor::get_input_stream ();
+
+    frame.add_fcn (command_editor::set_input_stream, in_stream);
+
+    frame.add_fcn (command_history::ignore_entries,
+                   command_history::ignoring_entries ());
+
+    command_history::ignore_entries ();
+
+    FILE *ffile = nullptr;
+
+    if (! full_file.empty ())
+      ffile = octave::sys::fopen (full_file, "rb");
+
+    if (ffile)
+      {
+        frame.add_fcn (safe_fclose, ffile);
+
+        interpreter& interp = __get_interpreter__ ("parse_fcn_file");
+
+        parser parser (ffile, interp);
+
+        parser.m_curr_class_name = dispatch_type;
+        parser.m_curr_package_name = package_name;
+        parser.m_autoloading = autoload;
+        parser.m_fcn_file_from_relative_lookup = relative_lookup;
+
+        parser.m_lexer.m_force_script = force_script;
+        parser.m_lexer.prep_for_file ();
+        parser.m_lexer.m_parsing_class_method = ! dispatch_type.empty ();
+
+        parser.m_lexer.m_fcn_file_name = file;
+        parser.m_lexer.m_fcn_file_full_name = full_file;
+        parser.m_lexer.m_dir_name = dir_name;
+        parser.m_lexer.m_package_name = package_name;
+
+        int status = parser.run ();
+
+        fcn_ptr = parser.m_primary_fcn_ptr;
+
+        if (status == 0)
+          {
+            if (parser.m_lexer.m_reading_classdef_file
+                && parser.m_classdef_object)
+              {
+                // Convert parse tree for classdef object to
+                // meta.class info (and stash it in the symbol
+                // table?).  Return pointer to constructor?
+
+                if (fcn_ptr)
+                  panic_impossible ();
+
+                bool is_at_folder = ! dispatch_type.empty ();
+
+                try
+                  {
+                    fcn_ptr = parser.m_classdef_object->make_meta_class (interp, is_at_folder);
+                  }
+                catch (const execution_exception&)
+                  {
+                    delete parser.m_classdef_object;
+                    throw;
+                  }
+
+                if (fcn_ptr)
+                  retval = octave_value (fcn_ptr);
+
+                delete parser.m_classdef_object;
+
+                parser.m_classdef_object = nullptr;
+              }
+            else if (fcn_ptr)
+              {
+                retval = octave_value (fcn_ptr);
+
+                fcn_ptr->maybe_relocate_end ();
+
+                if (parser.m_parsing_subfunctions)
+                  {
+                    if (! parser.m_endfunction_found)
+                      parser.m_subfunction_names.reverse ();
+
+                    fcn_ptr->stash_subfunction_names (parser.m_subfunction_names);
+                  }
+              }
+          }
+        else
+          error ("parse error while reading file %s", full_file.c_str ());
+      }
+    else if (require_file)
+      error ("no such file, '%s'", full_file.c_str ());
+    else if (! warn_for.empty ())
+      error ("%s: unable to open file '%s'", warn_for.c_str (),
+             full_file.c_str ());
+
+    return retval;
+  }
+
+  std::string
+  get_help_from_file (const std::string& nm, bool& symbol_found,
+                      std::string& full_file)
+  {
+    std::string retval;
+
+    full_file = fcn_file_in_path (nm);
+
+    std::string file = full_file;
+
+    size_t file_len = file.length ();
+
+    if ((file_len > 4 && file.substr (file_len-4) == ".oct")
+        || (file_len > 4 && file.substr (file_len-4) == ".mex")
+        || (file_len > 2 && file.substr (file_len-2) == ".m"))
+      {
+        file = sys::env::base_pathname (file);
+        file = file.substr (0, file.find_last_of ('.'));
+
+        size_t pos = file.find_last_of (sys::file_ops::dir_sep_str ());
+        if (pos != std::string::npos)
+          file = file.substr (pos+1);
+      }
+
+    if (! file.empty ())
+      {
+        symbol_found = true;
+
+        octave_value ov_fcn
+          = parse_fcn_file (full_file, file, "", "", "", true,
+                            false, false, false, "");
+
+        if (ov_fcn.is_defined ())
+          {
+            octave_function *fcn = ov_fcn.function_value ();
+
+            if (fcn)
+              retval = fcn->doc_string ();
+          }
+      }
+
+    return retval;
+  }
+
+  std::string
+  get_help_from_file (const std::string& nm, bool& symbol_found)
+  {
+    std::string file;
+    return get_help_from_file (nm, symbol_found, file);
+  }
+
+  std::string
+  lookup_autoload (const std::string& nm)
+  {
+    std::string retval;
+
+    typedef std::map<std::string, std::string>::const_iterator am_iter;
+
+    am_iter p = autoload_map.find (nm);
+
+    if (p != autoload_map.end ())
+      {
+        load_path& lp = __get_load_path__ ("lookup_autoload");
+
+        retval = lp.find_file (p->second);
+      }
+
+    return retval;
+  }
+
+  string_vector
+  autoloaded_functions (void)
+  {
+    string_vector names (autoload_map.size ());
+
+    octave_idx_type i = 0;
+    for (const auto& fcn_fname : autoload_map)
+      names[i++] = fcn_fname.first;
+
+    return names;
+  }
+
+  string_vector
+  reverse_lookup_autoload (const std::string& nm)
+  {
+    string_vector names;
+
+    for (const auto& fcn_fname : autoload_map)
+      if (nm == fcn_fname.second)
+        names.append (fcn_fname.first);
+
+    return names;
+  }
+
+  octave_value
+  load_fcn_from_file (const std::string& file_name,
+                      const std::string& dir_name,
+                      const std::string& dispatch_type,
+                      const std::string& package_name,
+                      const std::string& fcn_name, bool autoload)
+  {
+    octave_value retval;
+
+    unwind_protect frame;
+
+    std::string nm = file_name;
+
+    size_t nm_len = nm.length ();
+
+    std::string file;
+
+    bool relative_lookup = false;
+
+    file = nm;
+
+    if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
+        || (nm_len > 4 && nm.substr (nm_len-4) == ".mex")
+        || (nm_len > 2 && nm.substr (nm_len-2) == ".m"))
+      {
+        nm = sys::env::base_pathname (file);
+        nm = nm.substr (0, nm.find_last_of ('.'));
+
+        size_t pos = nm.find_last_of (sys::file_ops::dir_sep_str ());
+        if (pos != std::string::npos)
+          nm = nm.substr (pos+1);
+      }
+
+    relative_lookup = ! sys::env::absolute_pathname (file);
+
+    file = sys::env::make_absolute (file);
+
+    int len = file.length ();
+
+      dynamic_loader& dyn_loader
+        = __get_dynamic_loader__ ("~octave_mex_function");
+
+    if (len > 4 && file.substr (len-4, len-1) == ".oct")
+      {
+        if (autoload && ! fcn_name.empty ())
+          nm = fcn_name;
+
+        octave_function *tmpfcn
+          = dyn_loader.load_oct (nm, file, relative_lookup);
+
+        if (tmpfcn)
+          {
+            tmpfcn->stash_package_name (package_name);
+            retval = octave_value (tmpfcn);
+          }
+      }
+    else if (len > 4 && file.substr (len-4, len-1) == ".mex")
+      {
+        // Temporarily load m-file version of mex-file, if it exists,
+        // to get the help-string to use.
+
+        std::string doc_string;
+
+        octave_value ov_fcn
+          = parse_fcn_file (file.substr (0, len - 2), nm, dir_name,
+                            dispatch_type, package_name, false,
+                            autoload, autoload, relative_lookup, "");
+
+        if (ov_fcn.is_defined ())
+          {
+            octave_function *tmpfcn = ov_fcn.function_value ();
+
+            if (tmpfcn)
+              doc_string = tmpfcn->doc_string ();
+          }
+
+        octave_function *tmpfcn
+          = dyn_loader.load_mex (nm, file, relative_lookup);
+
+        if (tmpfcn)
+          {
+            tmpfcn->document (doc_string);
+            tmpfcn->stash_package_name (package_name);
+
+            retval = octave_value (tmpfcn);
+          }
+      }
+    else if (len > 2)
+      {
+        retval = parse_fcn_file (file, nm, dir_name, dispatch_type,
+                                 package_name, true, autoload, autoload,
+                                 relative_lookup, "");
+      }
+
+    return retval;
+  }
+}
+
+DEFMETHOD (autoload, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{autoload_map} =} autoload ()
+@deftypefnx {} {} autoload (@var{function}, @var{file})
+@deftypefnx {} {} autoload (@dots{}, "remove")
+Define @var{function} to autoload from @var{file}.
+
+The second argument, @var{file}, should be an absolute filename or a file
+name in the same directory as the function or script from which the autoload
+command was run.  @var{file} @emph{should not} depend on the Octave load
+path.
+
+Normally, calls to @code{autoload} appear in PKG_ADD script files that are
+evaluated when a directory is added to Octave's load path.  To avoid having
+to hardcode directory names in @var{file}, if @var{file} is in the same
+directory as the PKG_ADD script then
+
+@example
+autoload ("foo", "bar.oct");
+@end example
+
+@noindent
+will load the function @code{foo} from the file @code{bar.oct}.  The above
+usage when @code{bar.oct} is not in the same directory, or usages such as
+
+@example
+autoload ("foo", file_in_loadpath ("bar.oct"))
+@end example
+
+@noindent
+are strongly discouraged, as their behavior may be unpredictable.
+
+With no arguments, return a structure containing the current autoload map.
+
+If a third argument @qcode{"remove"} is given, the function is cleared and
+not loaded anymore during the current Octave session.
+
+@seealso{PKG_ADD}
+@end deftypefn */)
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1 || nargin > 3)
+    print_usage ();
+
+  if (nargin == 0)
+    {
+      Cell func_names (dim_vector (autoload_map.size (), 1));
+      Cell file_names (dim_vector (autoload_map.size (), 1));
+
+      octave_idx_type i = 0;
+      for (const auto& fcn_fname : autoload_map)
+        {
+          func_names(i) = fcn_fname.first;
+          file_names(i) = fcn_fname.second;
+
+          i++;
+        }
+
+      octave_map m;
+
+      m.assign ("function", func_names);
+      m.assign ("file", file_names);
+
+      retval = m;
+    }
+  else
+    {
+      string_vector argv = args.make_argv ("autoload");
+
+      std::string nm = argv[2];
+
+      if (! octave::sys::env::absolute_pathname (nm))
+        {
+          octave::call_stack& cs = interp.get_call_stack ();
+
+          octave_user_code *fcn = cs.caller_user_code ();
+
+          bool found = false;
+
+          if (fcn)
+            {
+              std::string fname = fcn->fcn_file_name ();
+
+              if (! fname.empty ())
+                {
+                  fname = octave::sys::env::make_absolute (fname);
+                  fname = fname.substr (0, fname.find_last_of (octave::sys::file_ops::dir_sep_str ()) + 1);
+
+                  octave::sys::file_stat fs (fname + nm);
+
+                  if (fs.exists ())
+                    {
+                      nm = fname + nm;
+                      found = true;
+                    }
+                }
+            }
+          if (! found)
+            warning_with_id ("Octave:autoload-relative-file-name",
+                             "autoload: '%s' is not an absolute filename",
+                             nm.c_str ());
+        }
+      if (nargin == 2)
+        autoload_map[argv[1]] = nm;
+      else if (nargin == 3)
+        {
+          if (argv[3] != "remove")
+            error_with_id ("Octave:invalid-input-arg",
+                           "autoload: third argument can only be 'remove'");
+
+          // Remove function from symbol table and autoload map.
+          octave::symbol_table& symtab = interp.get_symbol_table ();
+          symtab.clear_dld_function (argv[1]);
+          autoload_map.erase (argv[1]);
+        }
+    }
+
+  return retval;
+}
+
+namespace octave
+{
+  // Execute the contents of a script file.  For compatibility with
+  // Matlab, also execute a function file by calling the function it
+  // defines with no arguments and nargout = 0.
+
+  void
+  source_file (const std::string& file_name, const std::string& context,
+               bool verbose, bool require_file, const std::string& warn_for)
+  {
+    // Map from absolute name of script file to recursion level.  We
+    // use a map instead of simply placing a limit on recursion in the
+    // source_file function so that two mutually recursive scripts
+    // written as
+    //
+    //   foo1.m:
+    //   ------
+    //   foo2
+    //
+    //   foo2.m:
+    //   ------
+    //   foo1
+    //
+    // and called with
+    //
+    //   foo1
+    //
+    // (for example) will behave the same if they are written as
+    //
+    //   foo1.m:
+    //   ------
+    //   source ("foo2.m")
+    //
+    //   foo2.m:
+    //   ------
+    //   source ("foo1.m")
+    //
+    // and called with
+    //
+    //   source ("foo1.m")
+    //
+    // (for example).
+
+    static std::map<std::string, int> source_call_depth;
+
+    std::string file_full_name
+      = sys::file_ops::tilde_expand (file_name);
+
+    size_t pos
+      = file_full_name.find_last_of (sys::file_ops::dir_sep_str ());
+
+    std::string dir_name = file_full_name.substr (0, pos);
+
+    file_full_name = sys::env::make_absolute (file_full_name);
+
+    unwind_protect frame;
+
+    if (source_call_depth.find (file_full_name) == source_call_depth.end ())
+      source_call_depth[file_full_name] = -1;
+
+    frame.protect_var (source_call_depth[file_full_name]);
+
+    source_call_depth[file_full_name]++;
+
+    tree_evaluator& tw = __get_evaluator__ ("source_file");
+
+    if (source_call_depth[file_full_name] >= tw.max_recursion_depth ())
+      error ("max_recursion_depth exceeded");
+
+    if (! context.empty ())
+      {
+        call_stack& cs = __get_call_stack__ ("source_file");
+
+        if (context == "caller")
+          cs.goto_caller_frame ();
+        else if (context == "base")
+          cs.goto_base_frame ();
+        else
+          error ("source: context must be \"caller\" or \"base\"");
+
+        frame.add_method (cs, &call_stack::pop);
+      }
+
+    // Find symbol name that would be in symbol_table, if it were loaded.
+    size_t dir_end
+      = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
+    dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
+
+    size_t extension = file_name.find_last_of ('.');
+    if (extension == std::string::npos)
+      extension = file_name.length ();
+
+    std::string symbol = file_name.substr (dir_end, extension - dir_end);
+    std::string full_name = sys::canonicalize_file_name (file_name);
+
+    // Check if this file is already loaded (or in the path)
+    symbol_scope curr_scope = __get_current_scope__ ("source_file");
+    octave_value ov_code = curr_scope.find (symbol);
+
+    // For compatibility with Matlab, accept both scripts and
+    // functions.
+
+    if (ov_code.is_user_code ())
+      {
+        octave_user_code *code = ov_code.user_code_value ();
+
+        if (! code
+            || (sys::canonicalize_file_name (code->fcn_file_name ())
+                != full_name))
+          {
+            // Wrong file, so load it below.
+            ov_code = octave_value ();
+          }
+      }
+    else
+      {
+        // Not a script, so load it below.
+        ov_code = octave_value ();
+      }
+
+    // If no symbol of this name, or the symbol is for a different
+    // file, load.
+
+    if (ov_code.is_undefined ())
+      {
+        try
+          {
+            ov_code = parse_fcn_file (file_full_name, file_name, dir_name,
+                                      "", "", require_file, true, false,
+                                      false, warn_for);
+          }
+        catch (execution_exception& e)
+          {
+            error (e, "source: error sourcing file '%s'",
+                   file_full_name.c_str ());
+          }
+      }
+
+    // Return or error if we don't have a valid script or function.
+
+    if (ov_code.is_undefined ())
+      return;
+
+    if (! ov_code.is_user_code ())
+      error ("source: %s is not a script", full_name.c_str ());
+
+    if (verbose)
+      {
+        octave_stdout << "executing commands from " << full_name << " ... ";
+        octave_stdout.flush ();
+      }
+
+    octave_user_code *code = ov_code.user_code_value ();
+
+    code->call (tw, 0, octave_value_list ());
+
+    if (verbose)
+      octave_stdout << "done." << std::endl;
+  }
+}
+
+DEFMETHOD (mfilename, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {} mfilename ()
+@deftypefnx {} {} mfilename ("fullpath")
+@deftypefnx {} {} mfilename ("fullpathext")
+Return the name of the currently executing file.
+
+The base name of the currently executing script or function is returned without
+any extension.  If called from outside an m-file, such as the command line,
+return the empty string.
+
+Given the argument @qcode{"fullpath"}, include the directory part of the
+filename, but not the extension.
+
+Given the argument @qcode{"fullpathext"}, include the directory part of
+the filename and the extension.
+@seealso{inputname, dbstack}
+@end deftypefn */)
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin > 1)
+    print_usage ();
+
+  std::string arg;
+
+  if (nargin == 1)
+    arg = args(0).xstring_value ("mfilename: argument must be a string");
+
+  std::string fname;
+
+  octave::call_stack& cs = interp.get_call_stack ();
+
+  octave_user_code *fcn = cs.caller_user_code ();
+
+  if (fcn)
+    {
+      fname = fcn->fcn_file_name ();
+
+      if (fname.empty ())
+        fname = fcn->name ();
+    }
+
+  if (arg == "fullpathext")
+    retval = fname;
+  else
+    {
+      size_t dpos = fname.rfind (octave::sys::file_ops::dir_sep_char ());
+      size_t epos = fname.rfind ('.');
+
+      if (epos <= dpos+1)
+        epos = std::string::npos;
+
+      fname = (epos != std::string::npos) ? fname.substr (0, epos) : fname;
+
+      if (arg == "fullpath")
+        retval = fname;
+      else
+        retval = (dpos != std::string::npos) ? fname.substr (dpos+1) : fname;
+    }
+
+  return retval;
+}
+
+DEFUN (source, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {} source (@var{file})
+@deftypefnx {} {} source (@var{file}, @var{context})
+Parse and execute the contents of @var{file}.
+
+Without specifying @var{context}, this is equivalent to executing commands
+from a script file, but without requiring the file to be named
+@file{@var{file}.m} or to be on the execution path.
+
+Instead of the current context, the script may be executed in either the
+context of the function that called the present function
+(@qcode{"caller"}), or the top-level context (@qcode{"base"}).
+@seealso{run}
+@end deftypefn */)
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+
+  std::string file_name = args(0).xstring_value ("source: FILE must be a string");
+
+  std::string context;
+
+  if (nargin == 2)
+    context = args(1).xstring_value ("source: CONTEXT must be a string");
+
+  octave::source_file (file_name, context);
+
+  return retval;
+}
+
+namespace octave
+{
+  //! Evaluate an Octave function (built-in or interpreted) and return
+  //! the list of result values.
+  //!
+  //! @param name The name of the function to call.
+  //! @param args The arguments to the function.
+  //! @param nargout The number of output arguments expected.
+  //! @return A list of output values.  The length of the list is not
+  //!         necessarily the same as @c nargout.
+
+  octave_value_list
+  feval (const std::string& name, const octave_value_list& args, int nargout)
+  {
+    octave_value_list retval;
+
+    symbol_table& symtab = __get_symbol_table__ ("feval");
+
+    octave_value fcn = symtab.find_function (name, args);
+
+    if (fcn.is_defined ())
+      {
+        tree_evaluator& tw = __get_evaluator__ ("feval");
+
+        octave_function *of = fcn.function_value ();
+
+        retval = of->call (tw, nargout, args);
+      }
+    else
+      error ("feval: function '%s' not found", name.c_str ());
+
+    return retval;
+  }
+
+  octave_value_list
+  feval (octave_function *fcn, const octave_value_list& args, int nargout)
+  {
+    octave_value_list retval;
+
+    if (fcn)
+      {
+        tree_evaluator& tw = __get_evaluator__ ("feval");
+
+        retval = fcn->call (tw, nargout, args);
+      }
+
+    return retval;
+  }
+
+  octave_value_list
+  feval (octave_value& val, const octave_value_list& args, int nargout)
+  {
+    if (val.is_function ())
+      {
+        return feval (val.function_value (), args, nargout);
+      }
+    else if (val.is_function_handle ())
+      {
+        // This covers function handles, inline functions, and anonymous
+        //  functions.
+
+        std::list<octave_value_list> arg_list;
+        arg_list.push_back (args);
+
+        return val.subsref ("(", arg_list, nargout);
+      }
+    else if (val.is_string ())
+      {
+        return feval (val.string_value (), args, nargout);
+      }
+    else
+      error ("feval: first argument must be a string, inline function, or a function handle");
+
+    return ovl ();
+  }
+
+  static octave_value_list
+  get_feval_args (const octave_value_list& args)
+  {
+    return args.slice (1, args.length () - 1, true);
+  }
+
+  //! Evaluate an Octave function (built-in or interpreted) and return
+  //! the list of result values.
+  //!
+  //! @param args The first element of @c args is the function to call.
+  //!             It may be the name of the function as a string, a function
+  //!             handle, or an inline function.  The remaining arguments are
+  //!             passed to the function.
+  //! @param nargout The number of output arguments expected.
+  //! @return A list of output values.  The length of the list is not
+  //!         necessarily the same as @c nargout.
+
+  octave_value_list
+  feval (const octave_value_list& args, int nargout)
+  {
+    if (args.length () > 0)
+      {
+        octave_value f_arg = args(0);
+
+        octave_value_list tmp_args = get_feval_args (args);
+
+        return feval (f_arg, tmp_args, nargout);
+      }
+    else
+      error ("feval: first argument must be a string, inline function, or a function handle");
+
+    return ovl ();
+  }
+}
+
+DEFUN (feval, args, nargout,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} feval (@var{name}, @dots{})
+Evaluate the function named @var{name}.
+
+Any arguments after the first are passed as inputs to the named function.
+For example,
+
+@example
+@group
+feval ("acos", -1)
+     @result{} 3.1416
+@end group
+@end example
+
+@noindent
+calls the function @code{acos} with the argument @samp{-1}.
+
+The function @code{feval} can also be used with function handles of any sort
+(@pxref{Function Handles}).  Historically, @code{feval} was the only way to
+call user-supplied functions in strings, but function handles are now
+preferred due to the cleaner syntax they offer.  For example,
+
+@example
+@group
+@var{f} = @@exp;
+feval (@var{f}, 1)
+    @result{} 2.7183
+@var{f} (1)
+    @result{} 2.7183
+@end group
+@end example
+
+@noindent
+are equivalent ways to call the function referred to by @var{f}.  If it
+cannot be predicted beforehand whether @var{f} is a function handle,
+function name in a string, or inline function then @code{feval} can be used
+instead.
+@end deftypefn */)
+{
+  if (args.length () == 0)
+    print_usage ();
+
+  return octave::feval (args, nargout);
+}
+
+DEFMETHOD (builtin, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {[@dots{}] =} builtin (@var{f}, @dots{})
+Call the base function @var{f} even if @var{f} is overloaded to another
+function for the given type signature.
+
+This is normally useful when doing object-oriented programming and there is
+a requirement to call one of Octave's base functions rather than the
+overloaded one of a new class.
+
+A trivial example which redefines the @code{sin} function to be the
+@code{cos} function shows how @code{builtin} works.
+
+@example
+@group
+sin (0)
+  @result{} 0
+function y = sin (x), y = cos (x); endfunction
+sin (0)
+  @result{} 1
+builtin ("sin", 0)
+  @result{} 0
+@end group
+@end example
+@end deftypefn */)
+{
+  octave_value_list retval;
+
+  if (args.length () == 0)
+    print_usage ();
+
+  const std::string name (args(0).xstring_value ("builtin: function name (F) must be a string"));
+
+  octave::symbol_table& symtab = interp.get_symbol_table ();
+
+  octave_value fcn = symtab.builtin_find (name);
+
+  if (fcn.is_defined ())
+    retval = octave::feval (fcn.function_value (), args.splice (0, 1), nargout);
+  else
+    error ("builtin: lookup for symbol '%s' failed", name.c_str ());
+
+  return retval;
+}
+
+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)
+  {
+    if (*lst)
+      {
+        delete *lst;
+        *lst = nullptr;
+      }
+  }
+}
+
+DEFMETHOD (eval, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {} eval (@var{try})
+@deftypefnx {} {} eval (@var{try}, @var{catch})
+Parse the string @var{try} and evaluate it as if it were an Octave
+program.
+
+If execution fails, evaluate the optional string @var{catch}.
+
+The string @var{try} is evaluated in the current context, so any results
+remain available after @code{eval} returns.
+
+The following example creates the variable @var{A} with the approximate
+value of 3.1416 in the current workspace.
+
+@example
+eval ("A = acos(-1);");
+@end example
+
+If an error occurs during the evaluation of @var{try} then the @var{catch}
+string is evaluated, as the following example shows:
+
+@example
+@group
+eval ('error ("This is a bad example");',
+      'printf ("This error occurred:\n%s\n", lasterr ());');
+     @print{} This error occurred:
+        This is a bad example
+@end group
+@end example
+
+Programming Note: if you are only using @code{eval} as an error-capturing
+mechanism, rather than for the execution of arbitrary code strings,
+Consider using try/catch blocks or unwind_protect/unwind_protect_cleanup
+blocks instead.  These techniques have higher performance and don't
+introduce the security considerations that the evaluation of arbitrary code
+does.
+@seealso{evalin, evalc, assignin, feval}
+@end deftypefn */)
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 0)
+    print_usage ();
+
+  octave::unwind_protect frame;
+
+  if (nargin > 1)
+    {
+      frame.protect_var (buffer_error_messages);
+      buffer_error_messages++;
+    }
+
+  int parse_status = 0;
+
+  bool execution_error = false;
+
+  octave_value_list tmp;
+
+  try
+    {
+      tmp = interp.eval_string (args(0), nargout > 0, parse_status, nargout);
+    }
+  catch (const octave::execution_exception&)
+    {
+      octave::interpreter::recover_from_exception ();
+
+      execution_error = true;
+    }
+
+  if (nargin > 1 && (parse_status != 0 || execution_error))
+    {
+      // Set up for letting the user print any messages from
+      // errors that occurred in the first part of this eval().
+
+      buffer_error_messages--;
+
+      tmp = interp.eval_string (args(1), nargout > 0, parse_status, nargout);
+
+      if (nargout > 0)
+        retval = tmp;
+    }
+  else
+    {
+      if (nargout > 0)
+        retval = tmp;
+
+      // FIXME: we should really be rethrowing whatever exception occurred,
+      // not just throwing an execution exception.
+      if (execution_error)
+        octave_throw_execution_exception ();
+    }
+
+  return retval;
+}
+
+/*
+
+%!shared x
+%! x = 1;
+
+%!assert (eval ("x"), 1)
+%!assert (eval ("x;"))
+%!assert (eval ("x;"), 1)
+
+%!test
+%! y = eval ("x");
+%! assert (y, 1);
+
+%!test
+%! y = eval ("x;");
+%! assert (y, 1);
+
+%!test
+%! eval ("x = 1;");
+%! assert (x,1);
+
+%!test
+%! eval ("flipud = 2;");
+%! assert (flipud, 2);
+
+%!function y = __f ()
+%!  eval ("flipud = 2;");
+%!  y = flipud;
+%!endfunction
+%!assert (__f(), 2)
+
+% bug #35645
+%!test
+%! [a,] = gcd (1,2);
+%! [a,b,] = gcd (1, 2);
+
+%!error eval ("switch = 13;")
+
+*/
+
+DEFMETHOD (assignin, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} assignin (@var{context}, @var{varname}, @var{value})
+Assign @var{value} to @var{varname} in context @var{context}, which
+may be either @qcode{"base"} or @qcode{"caller"}.
+@seealso{evalin}
+@end deftypefn */)
+{
+  octave_value_list retval;
+
+  if (args.length () != 3)
+    print_usage ();
+
+  std::string context = args(0).xstring_value ("assignin: CONTEXT must be a string");
+
+  octave::unwind_protect frame;
+
+  octave::call_stack& cs = interp.get_call_stack ();
+
+  if (context == "caller")
+    cs.goto_caller_frame ();
+  else if (context == "base")
+    cs.goto_base_frame ();
+  else
+    error ("assignin: CONTEXT must be \"caller\" or \"base\"");
+
+  frame.add_method (cs, &octave::call_stack::pop);
+
+  std::string nm = args(1).xstring_value ("assignin: VARNAME must be a string");
+
+  if (octave::valid_identifier (nm))
+    {
+      // Put the check here so that we don't slow down assignments
+      // generally.  Any that go through Octave's parser should have
+      // already been checked.
+
+      if (octave::iskeyword (nm))
+        error ("assignin: invalid assignment to keyword '%s'", nm.c_str ());
+
+      octave::symbol_scope scope = interp.get_current_scope ();
+
+      if (scope)
+        scope.assign (nm, args(2));
+    }
+  else
+    error ("assignin: invalid variable name in argument VARNAME");
+
+  return retval;
+}
+
+/*
+
+%!error assignin ("base", "switch", "13")
+
+*/
+
+DEFMETHOD (evalin, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {} evalin (@var{context}, @var{try})
+@deftypefnx {} {} evalin (@var{context}, @var{try}, @var{catch})
+Like @code{eval}, except that the expressions are evaluated in the context
+@var{context}, which may be either @qcode{"caller"} or @qcode{"base"}.
+@seealso{eval, assignin}
+@end deftypefn */)
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin < 2)
+    print_usage ();
+
+  std::string context = args(0).xstring_value ("evalin: CONTEXT must be a string");
+
+  octave::unwind_protect frame;
+
+  octave::call_stack& cs = interp.get_call_stack ();
+
+  if (context == "caller")
+    cs.goto_caller_frame ();
+  else if (context == "base")
+    cs.goto_base_frame ();
+  else
+    error ("evalin: CONTEXT must be \"caller\" or \"base\"");
+
+  frame.add_method (cs, &octave::call_stack::pop);
+
+  if (nargin > 2)
+    {
+      frame.protect_var (buffer_error_messages);
+      buffer_error_messages++;
+    }
+
+  int parse_status = 0;
+
+  bool execution_error = false;
+
+  octave_value_list tmp;
+
+  try
+    {
+      tmp = interp.eval_string (args(1), nargout > 0, parse_status, nargout);
+    }
+  catch (const octave::execution_exception&)
+    {
+      octave::interpreter::recover_from_exception ();
+
+      execution_error = true;
+    }
+
+  if (nargin > 2 && (parse_status != 0 || execution_error))
+    {
+      // Set up for letting the user print any messages from
+      // errors that occurred in the first part of this eval().
+
+      buffer_error_messages--;
+
+      tmp = interp.eval_string (args(2), nargout > 0, parse_status, nargout);
+
+      retval = (nargout > 0) ? tmp : octave_value_list ();
+    }
+  else
+    {
+      if (nargout > 0)
+        retval = tmp;
+
+      // FIXME: we should really be rethrowing whatever
+      // exception occurred, not just throwing an
+      // execution exception.
+      if (execution_error)
+        octave_throw_execution_exception ();
+    }
+
+  return retval;
+}
+
+static void
+maybe_print_last_error_message (bool *doit)
+{
+  if (doit && *doit)
+    // Print error message again, which was lost because of the stderr buffer
+    // Note: this keeps error_state and last_error_stack intact
+    message_with_id ("error", last_error_id ().c_str (),
+                     "%s", last_error_message ().c_str ());
+}
+
+static void
+restore_octave_stdout (std::streambuf *buf)
+{
+  octave_stdout.flush ();
+  octave_stdout.rdbuf (buf);
+}
+
+static void
+restore_octave_stderr (std::streambuf *buf)
+{
+  std::cerr.flush ();
+  std::cerr.rdbuf (buf);
+}
+
+DEFMETHOD (evalc, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{s} =} evalc (@var{try})
+@deftypefnx {} {@var{s} =} evalc (@var{try}, @var{catch})
+Parse and evaluate the string @var{try} as if it were an Octave program,
+while capturing the output into the return variable @var{s}.
+
+If execution fails, evaluate the optional string @var{catch}.
+
+This function behaves like @code{eval}, but any output or warning messages
+which would normally be written to the console are captured and returned in
+the string @var{s}.
+
+The @code{diary} is disabled during the execution of this function.  When
+@code{system} is used, any output produced by external programs is
+@emph{not} captured, unless their output is captured by the @code{system}
+function itself.
+
+@example
+@group
+s = evalc ("t = 42"), t
+  @result{} s = t =  42
+
+  @result{} t =  42
+@end group
+@end example
+@seealso{eval, diary}
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin == 0 || nargin > 2)
+    print_usage ();
+
+  // redirect stdout/stderr to capturing buffer
+  std::ostringstream buffer;
+
+  std::ostream& out_stream = octave_stdout;
+  std::ostream& err_stream = std::cerr;
+
+  out_stream.flush ();
+  err_stream.flush ();
+
+  std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ());
+  std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ());
+
+  bool eval_error_occurred = true;
+
+  octave::unwind_protect frame;
+
+  frame.add_fcn (maybe_print_last_error_message, &eval_error_occurred);
+  frame.add_fcn (restore_octave_stdout, old_out_buf);
+  frame.add_fcn (restore_octave_stderr, old_err_buf);
+
+  // call standard eval function
+  octave_value_list retval;
+  int eval_nargout = std::max (0, nargout - 1);
+
+  retval = Feval (interp, args, eval_nargout);
+  eval_error_occurred = false;
+
+  retval.prepend (buffer.str ());
+  return retval;
+}
+
+/*
+
+%!assert (evalc ("1"), "ans =  1\n")
+%!assert (evalc ("1;"), "")
+
+%!test
+%! [s, y] = evalc ("1");
+%! assert (s, "");
+%! assert (y, 1);
+
+%!test
+%! [s, y] = evalc ("1;");
+%! assert (s, "");
+%! assert (y, 1);
+
+%!test
+%! assert (evalc ("y = 2"), "y =  2\n");
+%! assert (y, 2);
+
+%!test
+%! assert (evalc ("y = 3;"), "");
+%! assert (y, 3);
+
+%!test
+%! [s, a, b] = evalc ("deal (1, 2)");
+%! assert (s, "");
+%! assert (a, 1);
+%! assert (b, 2);
+
+%!function [a, b] = __f_evalc ()
+%!  printf ("foo");
+%!  fprintf (stdout, "bar");
+%!  disp (pi);
+%!  a = 1;
+%!  b = 2;
+%!endfunction
+%!test
+%! [s, a, b] = evalc ("__f_evalc ()");
+%! assert (s, "foobar 3.1416\n");
+%! assert (a, 1);
+%! assert (b, 2);
+
+%!error <foo> (evalc ("error ('foo')"))
+%!error <bar> (evalc ("error ('foo')", "error ('bar')"))
+
+%!test
+%! warning ("off", "quiet", "local");
+%! assert (evalc ("warning ('foo')"), "warning: foo\n");
+
+%!test
+%! warning ("off", "quiet", "local");
+%! assert (evalc ("error ('foo')", "warning ('bar')"), "warning: bar\n");
+
+%!error evalc ("switch = 13;")
+
+*/
+
+DEFUN (__parser_debug_flag__, args, nargout,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{val} =} __parser_debug_flag__ ()
+@deftypefnx {} {@var{old_val} =} __parser_debug_flag__ (@var{new_val})
+Query or set the internal flag that determines whether Octave's parser
+prints debug information as it processes an expression.
+@seealso{__lexer_debug_flag__}
+@end deftypefn */)
+{
+  octave_value retval;
+
+  bool debug_flag = octave_debug;
+
+  retval = set_internal_variable (debug_flag, args, nargout,
+                                  "__parser_debug_flag__");
+
+  octave_debug = debug_flag;
+
+  return retval;
+}
+
+DEFUN (__parse_file__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __parse_file__ (@var{file}, @var{verbose})
+Undocumented internal function.
+@end deftypefn */)
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  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);
+
+  full_file = octave::sys::env::make_absolute (full_file);
+
+  std::string dir_name;
+
+  size_t file_len = file.length ();
+
+  if ((file_len > 4 && file.substr (file_len-4) == ".oct")
+      || (file_len > 4 && file.substr (file_len-4) == ".mex")
+      || (file_len > 2 && file.substr (file_len-2) == ".m"))
+    {
+      file = octave::sys::env::base_pathname (file);
+      file = file.substr (0, file.find_last_of ('.'));
+
+      size_t pos = file.find_last_of (octave::sys::file_ops::dir_sep_str ());
+      if (pos != std::string::npos)
+        {
+          dir_name = file.substr (0, pos);
+          file = file.substr (pos+1);
+        }
+    }
+
+  if (nargin == 2)
+    octave_stdout << "parsing " << full_file << std::endl;
+
+  octave_value ov_fcn
+    = octave::parse_fcn_file (full_file, file, dir_name, "", "", true, false,
+                              false, false, "__parse_file__");
+
+  return retval;
+}
--- a/libinterp/parse-tree/parse.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/parse.h	Thu Dec 20 17:18:56 2018 -0500
@@ -486,16 +486,16 @@
   {
   public:
 
-    parser (void)
-      : base_parser (*(new lexer ()))
+    parser (interpreter& interp)
+      : base_parser (*(new lexer (interp)))
     { }
 
-    parser (FILE *file)
-      : base_parser (*(new lexer (file)))
+    parser (FILE *file, interpreter& interp)
+      : base_parser (*(new lexer (file, interp)))
     { }
 
-    parser (const std::string& eval_string)
-      : base_parser (*(new lexer (eval_string)))
+    parser (const std::string& eval_string, interpreter& interp)
+      : base_parser (*(new lexer (eval_string, interp)))
     { }
 
     parser (lexer& lxr)
@@ -517,8 +517,8 @@
   {
   public:
 
-    push_parser (void)
-      : base_parser (*(new push_lexer ()))
+    push_parser (interpreter& interp)
+      : base_parser (*(new push_lexer (interp)))
     { }
 
     // No copying!
@@ -580,9 +580,11 @@
   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);
 
--- a/libinterp/parse-tree/profiler.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/profiler.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-
 #include "defun.h"
 #include "interpreter.h"
 #include "oct-time.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-anon-scopes.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,433 @@
+/*
+
+Copyright (C) 1996-2018 John W. Eaton
+Copyright (C) 2015-2018 Olaf Till
+
+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 "error.h"
+#include "pt-all.h"
+#include "pt-anon-scopes.h"
+
+// TODO: make sure that if(f->scope()) is checked if necessary
+
+namespace octave
+{
+  tree_anon_scopes::tree_anon_scopes (octave_user_function *f)
+    : scopes (), merged_tables ()
+  {
+    if (f)
+      {
+        if (! f->is_anonymous_function ())
+          panic_impossible ();
+
+        // Collect the scope of the outer anonymous function.
+
+        stash_scope_if_valid (f->scope ());
+
+        // Further walk the tree to find nested definitions of further
+        // anonymous functions.
+
+        tree_statement_list *cmd_list = f->body ();
+
+        if (cmd_list)
+          cmd_list->accept (*this);
+
+        // Collect symbol records of all collected scopes.
+
+        merge_tables ();
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_anon_fcn_handle (tree_anon_fcn_handle& afh)
+  {
+    // Collect the scope of this anonymous function.
+
+    stash_scope_if_valid (afh.scope ());
+
+    // Further walk the tree to find nested definitions of further
+    // anonymous functions.
+
+    tree_expression *e = afh.expression ();
+
+    if (e)
+      e->accept (*this);
+  }
+
+  // The rest of visit_... methods is only for walking the tree. Many of
+  // them, in particular all methods for commands, are not applicable to
+  // anonymous functions. Only parts of the tree are walked which could
+  // contain further (nested) anonymous function definitions (so
+  // e.g. identifiers and left hand sides of assignments are ignored).
+
+  void
+  tree_anon_scopes::visit_argument_list (tree_argument_list& lst)
+  {
+    tree_argument_list::iterator p = lst.begin ();
+
+    while (p != lst.end ())
+      {
+        tree_expression *elt = *p++;
+
+        if (elt)
+          {
+            elt->accept (*this);
+          }
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_binary_expression (tree_binary_expression& expr)
+  {
+    tree_expression *op1 = expr.lhs ();
+
+    if (op1)
+      op1->accept (*this);
+
+    tree_expression *op2 = expr.rhs ();
+
+    if (op2)
+      op2->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_break_command (tree_break_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_colon_expression (tree_colon_expression& expr)
+  {
+    tree_expression *op1 = expr.base ();
+
+    if (op1)
+      op1->accept (*this);
+
+    tree_expression *op3 = expr.increment ();
+
+    if (op3)
+      op3->accept (*this);
+
+    tree_expression *op2 = expr.limit ();
+
+    if (op2)
+      op2->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_continue_command (tree_continue_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_decl_command (tree_decl_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_decl_elt (tree_decl_elt&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_decl_init_list (tree_decl_init_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_simple_for_command (tree_simple_for_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_complex_for_command (tree_complex_for_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_octave_user_script (octave_user_script&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_octave_user_function (octave_user_function&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_function_def (tree_function_def&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_identifier (tree_identifier& /* id */)
+  {
+  }
+
+  void
+  tree_anon_scopes::visit_if_clause (tree_if_clause&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_if_command (tree_if_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_if_command_list (tree_if_command_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_switch_case (tree_switch_case&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_switch_case_list (tree_switch_case_list&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_switch_command (tree_switch_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_index_expression (tree_index_expression& expr)
+  {
+    tree_expression *e = expr.expression ();
+
+    if (e)
+      e->accept (*this);
+
+    std::list<tree_argument_list *> lst = expr.arg_lists ();
+
+    std::list<tree_argument_list *>::iterator p = lst.begin ();
+
+    while (p != lst.end ())
+      {
+        tree_argument_list *elt = *p++;
+
+        if (elt)
+          elt->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_matrix (tree_matrix& lst)
+  {
+    tree_matrix::iterator p = lst.begin ();
+
+    while (p != lst.end ())
+      {
+        tree_argument_list *elt = *p++;
+
+        if (elt)
+          elt->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_cell (tree_cell& lst)
+  {
+    tree_matrix::iterator p = lst.begin ();
+
+    while (p != lst.end ())
+      {
+        tree_argument_list *elt = *p++;
+
+        if (elt)
+          elt->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_multi_assignment (tree_multi_assignment& expr)
+  {
+    tree_expression *rhs = expr.right_hand_side ();
+
+    if (rhs)
+      rhs->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_no_op_command (tree_no_op_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_constant (tree_constant& /* val */)
+  {
+  }
+
+  void
+  tree_anon_scopes::visit_fcn_handle (tree_fcn_handle& /* fh */)
+  {
+  }
+
+  void
+  tree_anon_scopes::visit_funcall (tree_funcall& /* fc */)
+  {
+  }
+
+  void
+  tree_anon_scopes::visit_parameter_list (tree_parameter_list&)
+  {
+    // In visit_anon_fcn_handle we only accept/visit the body of
+    // anonymous function definitions, not the parameter list.
+
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_postfix_expression (tree_postfix_expression& expr)
+  {
+    tree_expression *e = expr.operand ();
+
+    if (e)
+      e->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_prefix_expression (tree_prefix_expression& expr)
+  {
+    tree_expression *e = expr.operand ();
+
+    if (e)
+      e->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_return_command (tree_return_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_return_list (tree_return_list& lst)
+  {
+    tree_return_list::iterator p = lst.begin ();
+
+    while (p != lst.end ())
+      {
+        tree_index_expression *elt = *p++;
+
+        if (elt)
+          elt->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_simple_assignment (tree_simple_assignment& expr)
+  {
+    tree_expression *rhs = expr.right_hand_side ();
+
+    if (rhs)
+      rhs->accept (*this);
+  }
+
+  void
+  tree_anon_scopes::visit_statement (tree_statement& stmt)
+  {
+    tree_command *cmd = stmt.command ();
+
+    if (cmd)
+      panic_impossible ();
+    else
+      {
+        tree_expression *expr = stmt.expression ();
+
+        if (expr)
+          expr->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_statement_list (tree_statement_list& lst)
+  {
+    for (auto& p : lst)
+      {
+        tree_statement *elt = p;
+
+        if (elt)
+          elt->accept (*this);
+      }
+  }
+
+  void
+  tree_anon_scopes::visit_try_catch_command (tree_try_catch_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_unwind_protect_command (tree_unwind_protect_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_while_command (tree_while_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::visit_do_until_command (tree_do_until_command&)
+  {
+    panic_impossible ();
+  }
+
+  void
+  tree_anon_scopes::merge_tables (void)
+  {
+    for (const auto& sc : scopes)
+      {
+        symrec_list vars = sc.all_variables ();
+
+        for (const auto& symrec : vars)
+          merged_tables[symrec.name ()] = symrec;
+      }
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-anon-scopes.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,187 @@
+/*
+
+Copyright (C) 1996-2018 John W. Eaton
+Copyright (C) 2015-2018 Olaf Till
+
+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_anon_scopes_h)
+#define octave_pt_anon_scopes_h 1
+
+#include "pt-walk.h"
+#include "ov-usr-fcn.h"
+
+namespace octave
+{
+  // In possibly nested definitions of anonymous functions, collect
+  // their scopes and the symbol records therein.
+
+  class
+  tree_anon_scopes : public tree_walker
+  {
+  public:
+
+    tree_anon_scopes (void) : scopes (), merged_tables () { }
+
+    tree_anon_scopes (octave_user_function *);
+
+    tree_anon_scopes& operator = (tree_anon_scopes&& tas)
+    {
+      scopes = std::move (tas.scopes);
+      merged_tables = std::move (tas.merged_tables);
+      return *this;
+    }
+
+    typedef std::map<std::string, symbol_record> symrec_map;
+
+    symrec_map::const_iterator begin (void)
+    {
+      return merged_tables.cbegin ();
+    }
+
+    symrec_map::const_iterator end (void)
+    {
+      return merged_tables.cend ();
+    }
+
+    unsigned int symrec_map_size (void)
+    {
+      return merged_tables.size ();
+    }
+
+    // No copying!
+
+    tree_anon_scopes (const tree_anon_scopes&) = delete;
+
+    tree_anon_scopes& operator = (const tree_anon_scopes&) = delete;
+
+    ~tree_anon_scopes (void) { }
+
+    // The following methods, though public, don't belong to the
+    // intended user interface of this class.
+
+    void visit_anon_fcn_handle (tree_anon_fcn_handle&);
+
+    void visit_argument_list (tree_argument_list&);
+
+    void visit_binary_expression (tree_binary_expression&);
+
+    void visit_break_command (tree_break_command&);
+
+    void visit_colon_expression (tree_colon_expression&);
+
+    void visit_continue_command(tree_continue_command&);
+
+    void visit_decl_command (tree_decl_command&);
+
+    void visit_decl_elt (tree_decl_elt&);
+
+    void visit_decl_init_list (tree_decl_init_list&);
+
+    void visit_simple_for_command (tree_simple_for_command&);
+
+    void visit_complex_for_command (tree_complex_for_command&);
+
+    void visit_octave_user_script (octave_user_script&);
+
+    void visit_octave_user_function (octave_user_function&);
+
+    void visit_function_def (tree_function_def&);
+
+    void visit_identifier (tree_identifier&);
+
+    void visit_if_clause (tree_if_clause&);
+
+    void visit_if_command (tree_if_command&);
+
+    void visit_if_command_list (tree_if_command_list&);
+
+    void visit_switch_case (tree_switch_case&);
+
+    void visit_switch_case_list (tree_switch_case_list&);
+
+    void visit_switch_command (tree_switch_command&);
+
+    void visit_index_expression (tree_index_expression&);
+
+    void visit_matrix (tree_matrix&);
+
+    void visit_cell (tree_cell&);
+
+    void visit_multi_assignment (tree_multi_assignment&);
+
+    void visit_no_op_command (tree_no_op_command&);
+
+    void visit_constant (tree_constant&);
+
+    void visit_fcn_handle (tree_fcn_handle&);
+
+    void visit_funcall (tree_funcall&);
+
+    void visit_parameter_list (tree_parameter_list&);
+
+    void visit_postfix_expression (tree_postfix_expression&);
+
+    void visit_prefix_expression (tree_prefix_expression&);
+
+    void visit_return_command (tree_return_command&);
+
+    void visit_return_list (tree_return_list&);
+
+    void visit_simple_assignment (tree_simple_assignment&);
+
+    void visit_statement (tree_statement&);
+
+    void visit_statement_list (tree_statement_list&);
+
+    void visit_try_catch_command (tree_try_catch_command&);
+
+    void visit_unwind_protect_command (tree_unwind_protect_command&);
+
+    void visit_while_command (tree_while_command&);
+
+    void visit_do_until_command (tree_do_until_command&);
+
+  private:
+
+    void stash_scope_if_valid (const symbol_scope& sc)
+    {
+      if (sc)
+        scopes.push_back (sc);
+      else
+        error ("internal error, invalid scope");
+    }
+
+    // The scope of this anonymous function and the collected scopes
+    // of all anonymous functions whose definitions are nested in the
+    // current anonymous function definition.
+
+    std::vector<symbol_scope> scopes;
+
+    // Symbol records of all collected scopes are merged over variable names.
+
+    typedef std::list<symbol_record> symrec_list;
+
+    void merge_tables (void);
+
+    symrec_map merged_tables;
+  };
+}
+
+#endif
--- a/libinterp/parse-tree/pt-arg-list.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-arg-list.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,26 +24,17 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <string>
 
 #include "str-vec.h"
 
-#include "defun.h"
-#include "error.h"
 #include "ovl.h"
 #include "ov.h"
-#include "ov-usr-fcn.h"
-#include "parse.h"
 #include "pt-arg-list.h"
-#include "pt-eval.h"
 #include "pt-exp.h"
 #include "pt-id.h"
 #include "pt-idx.h"
 #include "pt-pr-code.h"
-#include "pt-walk.h"
-#include "interpreter.h"
-#include "unwind-prot.h"
 
 namespace octave
 {
@@ -53,7 +44,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -117,152 +108,6 @@
 
     return retval;
   }
-}
-
-// FIXME: Is there a way to do this job without global data?
-
-static const octave_value *indexed_object = nullptr;
-static int index_position = 0;
-static int num_indices = 0;
-
-// END is documented in op-kw-docs.
-DEFCONSTMETHOD (end, interp, , ,
-                doc: /* -*- texinfo -*-
-@deftypefn {} {} end
-Last element of an array or the end of any @code{for}, @code{parfor},
-@code{if}, @code{do}, @code{while}, @code{function}, @code{switch},
-@code{try}, or @code{unwind_protect} block.
-
-As an index of an array, the magic index @qcode{"end"} refers to the
-last valid entry in an indexing operation.
-
-Example:
-
-@example
-@group
-@var{x} = [ 1 2 3; 4 5 6 ];
-@var{x}(1,end)
-   @result{} 3
-@var{x}(end,1)
-   @result{} 4
-@var{x}(end,end)
-   @result{} 6
-@end group
-@end example
-@seealso{for, parfor, if, do, while, function, switch, try, unwind_protect}
-@end deftypefn */)
-{
-  octave_value retval;
-
-  if (! indexed_object)
-    error ("invalid use of end");
-
-  if (indexed_object->isobject ())
-    {
-      octave_value_list args;
-
-      args(2) = num_indices;
-      args(1) = index_position + 1;
-      args(0) = *indexed_object;
-
-      std::string class_name = indexed_object->class_name ();
-
-      octave::symbol_table& symtab = interp.get_symbol_table ();
-
-      octave_value meth = symtab.find_method ("end", class_name);
-
-      if (meth.is_defined ())
-        return octave::feval (meth.function_value (), args, 1);
-    }
-
-  dim_vector dv = indexed_object->dims ();
-  int ndims = dv.ndims ();
-
-  if (num_indices < ndims)
-    {
-      for (int i = num_indices; i < ndims; i++)
-        dv(num_indices-1) *= dv(i);
-
-      if (num_indices == 1)
-        {
-          ndims = 2;
-          dv.resize (ndims);
-          dv(1) = 1;
-        }
-      else
-        {
-          ndims = num_indices;
-          dv.resize (ndims);
-        }
-    }
-
-  if (index_position < ndims)
-    retval = dv(index_position);
-  else
-    retval = 1;
-
-  return retval;
-}
-
-namespace octave
-{
-  octave_value_list
-  tree_argument_list::convert_to_const_vector (tree_evaluator *tw,
-                                               const octave_value *object)
-  {
-    // END doesn't make sense for functions.  Maybe we need a different
-    // way of asking an octave_value object this question?
-
-    bool stash_object = (m_list_includes_magic_end
-                         && object
-                         && ! (object->is_function ()
-                               || object->is_function_handle ()));
-
-    unwind_protect frame;
-
-    if (stash_object)
-      {
-        frame.protect_var (indexed_object);
-
-        indexed_object = object;
-      }
-
-    int len = length ();
-
-    std::list<octave_value_list> args;
-
-    iterator p = begin ();
-    for (int k = 0; k < len; k++)
-      {
-        if (stash_object)
-          {
-            frame.protect_var (index_position);
-            frame.protect_var (num_indices);
-
-            index_position = k;
-            num_indices = len;
-          }
-
-        tree_expression *elt = *p++;
-
-        if (elt)
-          {
-            octave_value tmp = tw->evaluate (elt);
-
-            if (tmp.is_cs_list ())
-              args.push_back (tmp.list_value ());
-            else if (tmp.is_defined ())
-              args.push_back (tmp);
-          }
-        else
-          {
-            args.push_back (octave_value ());
-            break;
-          }
-      }
-
-    return args;
-  }
 
   string_vector
   tree_argument_list::get_arg_names (void) const
--- a/libinterp/parse-tree/pt-arg-list.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-arg-list.h	Thu Dec 20 17:18:56 2018 -0500
@@ -67,14 +67,28 @@
 
     ~tree_argument_list (void);
 
+    // FIXME: This does not recursively check elements of the list
+    // that are also index expressions.
     bool has_magic_end (void) const;
 
+    bool includes_magic_end (void) const
+    {
+      return m_list_includes_magic_end;
+    }
+
     bool has_magic_tilde (void) const
-    { return m_list_includes_magic_tilde; }
+    {
+      return m_list_includes_magic_tilde;
+    }
+
+    bool includes_magic_tilde (void) const
+    {
+      return m_list_includes_magic_tilde;
+    }
 
     tree_expression * remove_front (void)
     {
-      iterator p = begin ();
+      auto p = begin ();
       tree_expression *retval = *p;
       erase (p);
       return retval;
@@ -90,10 +104,6 @@
 
     bool is_valid_lvalue_list (void) const;
 
-    octave_value_list
-    convert_to_const_vector (tree_evaluator *tw,
-                             const octave_value *object = nullptr);
-
     string_vector get_arg_names (void) const;
 
     std::list<std::string> variable_names (void) const;
--- a/libinterp/parse-tree/pt-array-list.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-array-list.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-
 #include "quit.h"
 
 #include "error.h"
@@ -37,7 +35,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
--- a/libinterp/parse-tree/pt-assign.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-assign.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <string>
 
 #include "error.h"
--- a/libinterp/parse-tree/pt-bp.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-bp.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -30,10 +30,6 @@
 
 namespace octave
 {
-  // TRUE means SIGINT should put us in the debugger at the next
-  // available breakpoint.
-  bool octave_debug_on_interrupt_state = false;
-
   void
   tree_breakpoint::visit_while_command (tree_while_command& cmd)
   {
--- a/libinterp/parse-tree/pt-bp.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-bp.h	Thu Dec 20 17:18:56 2018 -0500
@@ -173,10 +173,6 @@
     // List of breakpoint conditions.
     octave_value_list m_bp_cond_list;
   };
-
-  // TRUE means SIGINT should put us in the debugger at the next
-  // available breakpoint.
-  extern bool octave_debug_on_interrupt_state;
 }
 
 #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
--- a/libinterp/parse-tree/pt-cbinop.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-cbinop.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,12 +36,12 @@
   // the argument and corresponding operator.
 
   static octave_value::unary_op
-  strip_trans_herm (octave::tree_expression_ptr_t& exp)
+  strip_trans_herm (tree_expression_ptr_t& exp)
   {
     if (exp->is_unary_expression ())
       {
-        octave::tree_unary_expression *uexp =
-          dynamic_cast<octave::tree_unary_expression *> (exp);
+        tree_unary_expression *uexp =
+          dynamic_cast<tree_unary_expression *> (exp);
 
         octave_value::unary_op op = uexp->op_type ();
 
@@ -62,12 +62,12 @@
   // See bug #54465.
 
   static octave_value::unary_op
-  strip_not (octave::tree_expression_ptr_t& exp)
+  strip_not (tree_expression_ptr_t& exp)
   {
     if (exp->is_unary_expression ())
       {
-        octave::tree_unary_expression *uexp =
-          dynamic_cast<octave::tree_unary_expression *> (exp);
+        tree_unary_expression *uexp =
+          dynamic_cast<tree_unary_expression *> (exp);
 
         octave_value::unary_op op = uexp->op_type ();
 
@@ -87,8 +87,7 @@
   // or mul_herm.
 
   static octave_value::compound_binary_op
-  simplify_mul_op (octave::tree_expression_ptr_t& a,
-                   octave::tree_expression_ptr_t& b)
+  simplify_mul_op (tree_expression_ptr_t& a, tree_expression_ptr_t& b)
   {
     octave_value::compound_binary_op retop
       = octave_value::unknown_compound_binary_op;
@@ -115,8 +114,7 @@
   // Possibly convert left division to trans_ldiv or herm_ldiv.
 
   static octave_value::compound_binary_op
-  simplify_ldiv_op (octave::tree_expression_ptr_t& a,
-                    octave::tree_expression_ptr_t&)
+  simplify_ldiv_op (tree_expression_ptr_t& a, tree_expression_ptr_t&)
   {
     octave_value::compound_binary_op retop
       = octave_value::unknown_compound_binary_op;
@@ -137,8 +135,7 @@
   // Restore this code if short-circuit behavior can be preserved when needed.
   // See bug #54465.
   static octave_value::compound_binary_op
-  simplify_and_or_op (octave::tree_expression_ptr_t& a,
-                      octave::tree_expression_ptr_t& b,
+  simplify_and_or_op (tree_expression_ptr_t& a, tree_expression_ptr_t& b,
                       octave_value::binary_op op)
   {
     octave_value::compound_binary_op retop
--- a/libinterp/parse-tree/pt-cell.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-cell.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-
 #include "Cell.h"
 #include "ovl.h"
 #include "pt-arg-list.h"
--- a/libinterp/parse-tree/pt-check.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-check.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -34,7 +34,7 @@
   void
   tree_checker::visit_argument_list (tree_argument_list& lst)
   {
-    tree_argument_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -101,7 +101,7 @@
   void
   tree_checker::visit_decl_init_list (tree_decl_init_list& lst)
   {
-    tree_decl_init_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -243,7 +243,7 @@
   void
   tree_checker::visit_if_command_list (tree_if_command_list& lst)
   {
-    tree_if_command_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -264,7 +264,7 @@
 
     std::list<tree_argument_list *> lst = expr.arg_lists ();
 
-    std::list<tree_argument_list *>::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -278,7 +278,7 @@
   void
   tree_checker::visit_matrix (tree_matrix& lst)
   {
-    tree_matrix::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -292,7 +292,7 @@
   void
   tree_checker::visit_cell (tree_cell& lst)
   {
-    tree_matrix::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -346,7 +346,7 @@
   void
   tree_checker::visit_parameter_list (tree_parameter_list& lst)
   {
-    tree_parameter_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -382,7 +382,7 @@
   void
   tree_checker::visit_return_list (tree_return_list& lst)
   {
-    tree_return_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -453,7 +453,7 @@
   void
   tree_checker::visit_switch_case_list (tree_switch_case_list& lst)
   {
-    tree_switch_case_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
--- a/libinterp/parse-tree/pt-classdef.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-classdef.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -37,7 +37,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -51,7 +51,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -65,7 +65,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -85,7 +85,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -101,7 +101,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -115,28 +115,28 @@
   {
     while (! m_properties_lst.empty ())
       {
-        properties_list_iterator p = m_properties_lst.begin ();
+        auto p = m_properties_lst.begin ();
         delete *p;
         m_properties_lst.erase (p);
       }
 
     while (! m_methods_lst.empty ())
       {
-        methods_list_iterator p = m_methods_lst.begin ();
+        auto p = m_methods_lst.begin ();
         delete *p;
         m_methods_lst.erase (p);
       }
 
     while (! m_events_lst.empty ())
       {
-        events_list_iterator p = m_events_lst.begin ();
+        auto p = m_events_lst.begin ();
         delete *p;
         m_events_lst.erase (p);
       }
 
     while (! m_enum_lst.empty ())
       {
-        enum_list_iterator p = m_enum_lst.begin ();
+        auto p = m_enum_lst.begin ();
         delete *p;
         m_enum_lst.erase (p);
       }
--- a/libinterp/parse-tree/pt-const.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-const.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "error.h"
 #include "ovl.h"
--- a/libinterp/parse-tree/pt-decl.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-decl.h	Thu Dec 20 17:18:56 2018 -0500
@@ -84,7 +84,7 @@
 
     bool lvalue_ok (void) { return m_id ? m_id->lvalue_ok () : false; }
 
-    octave_lvalue lvalue (tree_evaluator *tw)
+    octave_lvalue lvalue (tree_evaluator& tw)
     {
       return m_id ? m_id->lvalue (tw) : octave_lvalue ();
     }
@@ -137,7 +137,7 @@
     {
       while (! empty ())
         {
-          iterator p = begin ();
+          auto p = begin ();
           delete *p;
           erase (p);
         }
--- a/libinterp/parse-tree/pt-eval.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-eval.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,11 +27,11 @@
 #include <cctype>
 
 #include <iostream>
-
-#include <fstream>
-#include <typeinfo>
+#include <list>
+#include <string>
 
 #include "cmd-edit.h"
+#include "file-ops.h"
 #include "oct-env.h"
 
 #include "bp-table.h"
@@ -60,24 +60,12 @@
 
 namespace octave
 {
-  int tree_evaluator::dbstep_flag = 0;
-
-  size_t tree_evaluator::current_frame = 0;
-
-  bool tree_evaluator::debug_mode = false;
-
-  bool tree_evaluator::quiet_breakpoint_flag = false;
-
-  tree_evaluator::stmt_list_type tree_evaluator::statement_context
-    = tree_evaluator::other;
-
-  bool tree_evaluator::in_loop_command = false;
-
   // Normal evaluator.
 
   void
   tree_evaluator::reset (void)
   {
+    m_statement_context = SC_OTHER;
     m_result_type = RT_UNDEFINED;
     m_expr_result_value = octave_value ();
     m_expr_result_value_list = octave_value_list ();
@@ -85,6 +73,219 @@
     m_nargout_stack.clear ();
   }
 
+  int tree_evaluator::repl (bool interactive)
+  {
+    int retval = 0;
+
+    lexer *lxr = (interactive
+                  ? new lexer (m_interpreter)
+                  : new lexer (stdin, m_interpreter));
+
+    parser parser (*lxr);
+
+    symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+    do
+      {
+        try
+          {
+            reset_error_handler ();
+
+            parser.reset ();
+
+            if (symtab.at_top_level ())
+              reset_debug_state ();
+
+            retval = parser.run ();
+
+            if (retval == 0)
+              {
+                if (parser.m_stmt_list)
+                  {
+                    parser.m_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)
+                          break;
+                      }
+
+                    if (octave_completion_matches_called)
+                      octave_completion_matches_called = false;
+                    else
+                      command_editor::increment_current_command_number ();
+                  }
+                else if (parser.m_lexer.m_end_of_input)
+                  {
+                    retval = EOF;
+                    break;
+                  }
+              }
+          }
+        catch (const interrupt_exception&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (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& e)
+          {
+            std::string stack_trace = e.info ();
+
+            if (! stack_trace.empty ())
+              std::cerr << stack_trace;
+
+            if (interactive)
+              m_interpreter.recover_from_exception ();
+            else
+              {
+                // We should exit with a nonzero status.
+                retval = 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;
+          }
+
+#if defined (DBSTOP_NANINF)
+        if (Vdebug_on_naninf)
+          {
+            if (setjump (naninf_jump) != 0)
+              debug_or_throw_exception (true);  // true = stack trace
+          }
+#endif
+      }
+    while (retval == 0);
+
+    if (retval == EOF)
+      {
+        if (interactive)
+          octave_stdout << "\n";
+
+        retval = 0;
+      }
+
+    return retval;
+  }
+
+  octave_value_list
+  tree_evaluator::eval_string (const std::string& eval_str, bool silent,
+                               int& parse_status, int nargout)
+  {
+    octave_value_list retval;
+
+    parser parser (eval_str, m_interpreter);
+
+    do
+      {
+        parser.reset ();
+
+        parse_status = parser.run ();
+
+        if (parse_status == 0)
+          {
+            if (parser.m_stmt_list)
+              {
+                tree_statement *stmt = nullptr;
+
+                if (parser.m_stmt_list->length () == 1
+                    && (stmt = parser.m_stmt_list->front ())
+                    && stmt->is_expression ())
+                  {
+                    tree_expression *expr = stmt->expression ();
+
+                    if (silent)
+                      expr->set_print_flag (false);
+
+                    bool do_bind_ans = false;
+
+                    if (expr->is_identifier ())
+                      {
+                        symbol_scope scope = get_current_scope ();
+
+                        symbol_record::context_id context
+                          = scope.current_context ();
+
+                        tree_identifier *id
+                          = dynamic_cast<tree_identifier *> (expr);
+
+                        do_bind_ans = (! id->is_variable (context));
+                      }
+                    else
+                      do_bind_ans = (! expr->is_assignment_expression ());
+
+                    retval = evaluate_n (expr, nargout);
+
+                    if (do_bind_ans && ! retval.empty ())
+                      bind_ans (retval(0), expr->print_result ());
+
+                    if (nargout == 0)
+                      retval = octave_value_list ();
+                  }
+                else if (nargout == 0)
+                  parser.m_stmt_list->accept (*this);
+                else
+                  error ("eval: invalid use of statement list");
+
+                if (returning () || breaking () || continuing ())
+                  break;
+              }
+            else if (parser.m_lexer.m_end_of_input)
+              break;
+          }
+      }
+    while (parse_status == 0);
+
+    return retval;
+  }
+
+  octave_value tree_evaluator::eval_string (const std::string& eval_str,
+                                            bool silent, int& parse_status)
+  {
+    octave_value retval;
+
+    octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
+
+    if (! tmp.empty ())
+      retval = tmp(0);
+
+    return retval;
+  }
+
+  octave_value_list tree_evaluator::eval_string (const octave_value& arg,
+                                                 bool silent, int& parse_status,
+                                                 int nargout)
+  {
+    std::string s = arg.xstring_value ("eval: expecting string argument");
+
+    return eval_string (s, silent, parse_status, nargout);
+  }
+
   void
   tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle& anon_fh)
   {
@@ -151,7 +352,7 @@
 
     octave_value ov_fcn (af);
 
-    octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn, this));
+    octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn, *this));
 
     push_result (fh);
   }
@@ -339,11 +540,11 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
-
-    if (in_loop_command)
-      tree_break_command::breaking = 1;
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    if (m_in_loop_command)
+      m_breaking = 1;
     else
       error ("break must appear in a loop in the same file as loop command");
   }
@@ -421,28 +622,34 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
-
-    if (in_loop_command)
-      tree_continue_command::continuing = 1;
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
+
+    if (m_in_loop_command)
+      m_continuing = 1;
   }
 
   bool
   tree_evaluator::statement_printing_enabled (void)
   {
-    return ! (m_silent_functions && (statement_context == function
-                                     || statement_context == script));
+    return ! (m_silent_functions && (m_statement_context == SC_FUNCTION
+                                     || m_statement_context == SC_SCRIPT));
   }
 
   void
   tree_evaluator::reset_debug_state (void)
   {
-    bp_table& bptab = __get_bp_table__ ("tree_evaluator::reset_debug_state");
-
-    debug_mode = bptab.have_breakpoints () || Vdebugging;
-
-    dbstep_flag = 0;
+    m_debug_mode = m_bp_table.have_breakpoints () || Vdebugging;
+
+    m_dbstep_flag = 0;
+  }
+
+  void
+  tree_evaluator::reset_debug_state (bool mode)
+  {
+    m_debug_mode = mode;
+
+    m_dbstep_flag = 0;
   }
 
   Matrix
@@ -553,7 +760,7 @@
       {
         i++;
 
-        octave_lvalue ref = elt->lvalue (this);
+        octave_lvalue ref = elt->lvalue (*this);
 
         if (i < args.length ())
           {
@@ -575,11 +782,159 @@
   {
     for (tree_decl_elt *elt : *param_list)
       {
-        octave_lvalue ref = elt->lvalue (this);
+        octave_lvalue ref = elt->lvalue (*this);
 
         ref.assign (octave_value::op_asn_eq, octave_value ());
       }
   }
+}
+
+// END is documented in op-kw-docs.
+DEFCONSTMETHOD (end, interp, , ,
+                doc: /* -*- texinfo -*-
+@deftypefn {} {} end
+Last element of an array or the end of any @code{for}, @code{parfor},
+@code{if}, @code{do}, @code{while}, @code{function}, @code{switch},
+@code{try}, or @code{unwind_protect} block.
+
+As an index of an array, the magic index @qcode{"end"} refers to the
+last valid entry in an indexing operation.
+
+Example:
+
+@example
+@group
+@var{x} = [ 1 2 3; 4 5 6 ];
+@var{x}(1,end)
+   @result{} 3
+@var{x}(end,1)
+   @result{} 4
+@var{x}(end,end)
+   @result{} 6
+@end group
+@end example
+@seealso{for, parfor, if, do, while, function, switch, try, unwind_protect}
+@end deftypefn */)
+{
+  octave_value retval;
+
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  const octave_value *indexed_object = tw.indexed_object ();
+  int index_position = tw.index_position ();
+  int num_indices = tw.num_indices ();
+
+  if (! indexed_object)
+    error ("invalid use of end");
+
+  if (indexed_object->isobject ())
+    {
+      octave_value_list args;
+
+      args(2) = num_indices;
+      args(1) = index_position + 1;
+      args(0) = *indexed_object;
+
+      std::string class_name = indexed_object->class_name ();
+
+      octave::symbol_table& symtab = interp.get_symbol_table ();
+
+      octave_value meth = symtab.find_method ("end", class_name);
+
+      if (meth.is_defined ())
+        return octave::feval (meth.function_value (), args, 1);
+    }
+
+  dim_vector dv = indexed_object->dims ();
+  int ndims = dv.ndims ();
+
+  if (num_indices < ndims)
+    {
+      for (int i = num_indices; i < ndims; i++)
+        dv(num_indices-1) *= dv(i);
+
+      if (num_indices == 1)
+        {
+          ndims = 2;
+          dv.resize (ndims);
+          dv(1) = 1;
+        }
+      else
+        {
+          ndims = num_indices;
+          dv.resize (ndims);
+        }
+    }
+
+  if (index_position < ndims)
+    retval = dv(index_position);
+  else
+    retval = 1;
+
+  return retval;
+}
+
+namespace octave
+{
+  octave_value_list
+  tree_evaluator::convert_to_const_vector (tree_argument_list *arg_list,
+                                           const octave_value *object)
+  {
+    // END doesn't make sense as a direct argument for a function (i.e.,
+    // "fcn (end)" is invalid but "fcn (array (end))" is OK).  Maybe we
+    // need a different way of asking an octave_value object this
+    // question?
+
+    bool stash_object = (arg_list->includes_magic_end ()
+                         && object
+                         && ! (object->is_function ()
+                               || object->is_function_handle ()));
+
+    unwind_protect frame;
+
+    if (stash_object)
+      {
+        frame.protect_var (m_indexed_object);
+
+        m_indexed_object = object;
+      }
+
+    int len = arg_list->length ();
+
+    std::list<octave_value_list> args;
+
+    auto p = arg_list->begin ();
+    for (int k = 0; k < len; k++)
+      {
+        if (stash_object)
+          {
+            frame.protect_var (m_index_position);
+            frame.protect_var (m_num_indices);
+
+            m_index_position = k;
+            m_num_indices = len;
+          }
+
+        tree_expression *elt = *p++;
+
+        if (elt)
+          {
+            octave_value tmp = evaluate (elt);
+
+            if (tmp.is_cs_list ())
+              args.push_back (tmp.list_value ());
+            else if (tmp.is_defined ())
+              args.push_back (tmp);
+          }
+        else
+          {
+            args.push_back (octave_value ());
+            break;
+          }
+      }
+
+    return args;
+  }
 
   octave_value_list
   tree_evaluator::convert_return_list_to_const_vector
@@ -640,7 +995,7 @@
 
     if (id && expr)
       {
-        octave_lvalue ult = id->lvalue (this);
+        octave_lvalue ult = id->lvalue (*this);
 
         octave_value init_val = evaluate (expr);
 
@@ -692,6 +1047,85 @@
     return symtab.current_scope ();
   }
 
+  // Return a pointer to the user-defined function FNAME.  If FNAME is empty,
+  // search backward for the first user-defined function in the
+  // current call stack.
+
+  octave_user_code *
+  tree_evaluator::get_user_code (const std::string& fname)
+  {
+    octave_user_code *user_code = nullptr;
+
+    if (fname.empty ())
+      user_code = m_call_stack.debug_user_code ();
+    else
+      {
+        std::string name = fname;
+
+        if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
+          {
+            auto beg = name.begin () + 2;  // never have @/method
+            auto end = name.end () - 1;    // never have trailing '/'
+            std::replace (beg, end, '/', sys::file_ops::dir_sep_char ());
+          }
+
+        size_t name_len = name.length ();
+
+        if (name_len > 2 && name.substr (name_len-2) == ".m")
+          name = name.substr (0, name_len-2);
+
+        if (name.empty ())
+          return nullptr;
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        octave_value fcn;
+        size_t p2;
+
+        if (name[0] == '@')
+          {
+            size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1);
+
+            if (p1 == std::string::npos)
+              return nullptr;
+
+            std::string dispatch_type = name.substr (1, p1-1);
+
+            p2 = name.find ('>', p1);
+
+            std::string method = name.substr (p1+1, p2-1);
+
+            fcn = symtab.find_method (method, dispatch_type);
+          }
+        else
+          {
+            p2 = name.find ('>');
+
+            std::string main_fcn = name.substr (0, p2);
+
+            fcn = symtab.find_function (main_fcn);
+          }
+
+        // List of function names sub1>sub2>...
+        std::string subfuns;
+
+        if (p2 != std::string::npos)
+          subfuns = name.substr (p2+1);
+
+        if (fcn.is_defined () && fcn.is_user_code ())
+          user_code = fcn.user_code_value ();
+
+        if (! user_code || subfuns.empty ())
+          return user_code;
+
+        fcn = user_code->find_subfunction (subfuns);
+
+        user_code = fcn.user_code_value ();
+      }
+
+    return user_code;
+  }
+
   void
   tree_evaluator::visit_decl_command (tree_decl_command& cmd)
   {
@@ -702,8 +1136,8 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
 
     tree_decl_init_list *init_list = cmd.initializer_list ();
 
@@ -783,7 +1217,7 @@
         else
           error ("declaration list element not global or persistent");
 
-        octave_lvalue ult = id->lvalue (this);
+        octave_lvalue ult = id->lvalue (*this);
 
         if (ult.is_undefined ())
           {
@@ -801,27 +1235,6 @@
       }
   }
 
-  // Decide if it's time to quit a for or while loop.
-  static inline bool
-  quit_loop_now (void)
-  {
-    octave_quit ();
-
-    // Maybe handle 'continue N' someday...
-
-    if (octave::tree_continue_command::continuing)
-      octave::tree_continue_command::continuing--;
-
-    bool quit = (octave::tree_return_command::returning
-                 || octave::tree_break_command::breaking
-                 || octave::tree_continue_command::continuing);
-
-    if (octave::tree_break_command::breaking)
-      octave::tree_break_command::breaking--;
-
-    return quit;
-  }
-
   void
   tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd)
   {
@@ -833,17 +1246,17 @@
         line++;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
 
     // FIXME: need to handle PARFOR loops here using cmd.in_parallel ()
     // and cmd.maxproc_expr ();
 
     unwind_protect frame;
 
-    frame.protect_var (in_loop_command);
-
-    in_loop_command = true;
+    frame.protect_var (m_in_loop_command);
+
+    m_in_loop_command = true;
 
     tree_expression *expr = cmd.control_expr ();
 
@@ -859,7 +1272,7 @@
 
     tree_expression *lhs = cmd.left_hand_side ();
 
-    octave_lvalue ult = lhs->lvalue (this);
+    octave_lvalue ult = lhs->lvalue (*this);
 
     tree_statement_list *loop_body = cmd.body ();
 
@@ -971,14 +1384,14 @@
         line++;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
 
     unwind_protect frame;
 
-    frame.protect_var (in_loop_command);
-
-    in_loop_command = true;
+    frame.protect_var (m_in_loop_command);
+
+    m_in_loop_command = true;
 
     tree_expression *expr = cmd.control_expr ();
 
@@ -996,15 +1409,15 @@
 
     tree_argument_list *lhs = cmd.left_hand_side ();
 
-    tree_argument_list::iterator p = lhs->begin ();
+    auto p = lhs->begin ();
 
     tree_expression *elt = *p++;
 
-    octave_lvalue val_ref = elt->lvalue (this);
+    octave_lvalue val_ref = elt->lvalue (*this);
 
     elt = *p;
 
-    octave_lvalue key_ref = elt->lvalue (this);
+    octave_lvalue key_ref = elt->lvalue (*this);
 
     const octave_map tmp_val = rhs.map_value ();
 
@@ -1045,6 +1458,68 @@
     panic_impossible ();
   }
 
+  octave_value_list
+  tree_evaluator::execute_user_script (octave_user_script& user_script,
+                                       int nargout,
+                                       const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    std::string file_name = user_script.fcn_file_name ();
+
+    if (args.length () != 0 || nargout != 0)
+      error ("invalid call to script %s", file_name.c_str ());
+
+    tree_statement_list *cmd_list = user_script.body ();
+
+    if (! cmd_list)
+      return retval;
+
+    unwind_protect frame;
+
+    // XXX FIXME
+    frame.add_method (user_script, &octave_user_script::set_call_depth,
+                      user_script.call_depth ());
+    user_script.increment_call_depth ();
+
+    if (user_script.call_depth () >= max_recursion_depth ())
+      error ("max_recursion_depth exceeded");
+
+    m_call_stack.push (&user_script, &frame);
+
+    // Set pointer to the current unwind_protect frame to allow
+    // certain builtins register simple cleanup in a very optimized manner.
+    // This is *not* intended as a general-purpose on-cleanup mechanism,
+
+    frame.add_method (m_call_stack, &call_stack::pop);
+
+    // Update line number even if debugging.
+    frame.protect_var (Vtrack_line_num);
+    Vtrack_line_num = true;
+
+    frame.protect_var (m_statement_context);
+    m_statement_context = SC_SCRIPT;
+
+    profiler::enter<octave_user_script> block (m_profiler, user_script);
+
+    symbol_scope script_scope = user_script.scope ();
+    frame.add_method (script_scope, &symbol_scope::unbind_script_symbols);
+    script_scope.bind_script_symbols (get_current_scope ());
+
+    if (echo ())
+      push_echo_state (frame, tree_evaluator::ECHO_SCRIPTS, file_name);
+
+    cmd_list->accept (*this);
+
+    if (m_returning)
+      m_returning = 0;
+
+    if (m_breaking)
+      m_breaking--;
+
+    return retval;
+  }
+
   void
   tree_evaluator::visit_octave_user_function (octave_user_function&)
   {
@@ -1052,6 +1527,200 @@
     panic_impossible ();
   }
 
+  octave_value_list
+  tree_evaluator::execute_user_function (octave_user_function& user_function,
+                                         int nargout,
+                                         const octave_value_list& xargs)
+  {
+    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;
+
+    if (user_function.is_classdef_constructor ())
+      {
+        if (args.length () > 0)
+          {
+            ret_args = args.slice (0, 1, true);
+            args = args.slice (1, args.length () - 1, true);
+          }
+        else
+          panic_impossible ();
+      }
+
+#if defined (HAVE_LLVM)
+    if (user_function.is_special_expr ()
+        && tree_jit::execute (user_function, args, retval))
+      return retval;
+#endif
+
+    unwind_protect frame;
+
+    // XXX FIXME
+    frame.add_method (user_function, &octave_user_function::set_call_depth,
+                      user_function.call_depth ());
+    user_function.increment_call_depth ();
+
+    if (user_function.call_depth () >= max_recursion_depth ())
+      error ("max_recursion_depth exceeded");
+
+    // Save old and set current symbol table context, for
+    // eval_undefined_error().
+
+    symbol_scope fcn_scope = user_function.scope ();
+
+    symbol_record::context_id context = user_function.active_context ();
+
+    m_call_stack.push (&user_function, &frame, fcn_scope, context);
+
+    frame.protect_var (Vtrack_line_num);
+    // update source line numbers, even if debugging
+    Vtrack_line_num = true;
+    frame.add_method (m_call_stack, &call_stack::pop);
+
+    if (user_function.call_depth () > 0
+        && ! user_function.is_anonymous_function ())
+      {
+        fcn_scope.push_context ();
+
+#if 0
+        std::cerr << name () << " scope: " << fcn_scope
+                  << " call depth: " << user_function.call_depth ()
+                  << " context: " << fcn_scope.current_context () << std::endl;
+#endif
+
+        frame.add_method (fcn_scope, &symbol_scope::pop_context);
+      }
+
+    bind_auto_fcn_vars (fcn_scope, xargs.name_tags (), args.length (),
+                        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 ())
+      {
+#if 0
+        std::cerr << "defining param list, scope: " << fcn_scope
+                  << ", context: " << fcn_scope.current_context () << std::endl;
+#endif
+        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)
+          error ("%s: invalid classdef constructor, no output argument defined",
+                 user_function.dispatch_class ().c_str ());
+
+        define_parameter_list_from_arg_vector (ret_list, ret_args);
+      }
+
+    // Force parameter list to be undefined when this function exits.
+    // Doing so decrements the reference counts on the values of local
+    // variables that are also named function parameters.
+
+    if (param_list)
+      frame.add_method (this, &tree_evaluator::undefine_parameter_list,
+                        param_list);
+
+    // Force return list to be undefined when this function exits.
+    // Doing so decrements the reference counts on the values of local
+    // variables that are also named values returned by this function.
+
+    if (ret_list)
+      frame.add_method (this, &tree_evaluator::undefine_parameter_list,
+                        ret_list);
+
+    if (user_function.call_depth () == 0)
+      {
+        // Force symbols to be undefined again when this function
+        // exits.
+        //
+        // This cleanup function is added to the unwind_protect stack
+        // after the calls to clear the parameter lists so that local
+        // variables will be cleared before the parameter lists are
+        // cleared.  That way, any function parameters that have been
+        // declared global will be unmarked as global before they are
+        // undefined by the clear_param_list cleanup function.
+
+        frame.add_method (fcn_scope, &symbol_scope::refresh);
+      }
+
+    frame.add_method (&user_function,
+                      &octave_user_function::restore_warning_states);
+
+    // Evaluate the commands that make up the function.
+
+    frame.protect_var (m_statement_context);
+    m_statement_context = SC_FUNCTION;
+
+    {
+      profiler::enter<octave_user_function> block (m_profiler, user_function);
+
+      if (echo ())
+        push_echo_state (frame, 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 = evaluate_n (expr, nargout);
+            }
+        }
+      else
+        cmd_list->accept (*this);
+    }
+
+    if (m_returning)
+      m_returning = 0;
+
+    if (m_breaking)
+      m_breaking--;
+
+    // Copy return values out.
+
+    if (ret_list && ! user_function.is_special_expr ())
+      {
+        Cell varargout;
+
+        if (ret_list->takes_varargs ())
+          {
+            octave_value varargout_varval = fcn_scope.varval ("varargout");
+
+            if (varargout_varval.is_defined ())
+              varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
+          }
+
+        retval = convert_return_list_to_const_vector (ret_list, nargout,
+                                                      varargout);
+      }
+
+    return retval;
+  }
+
   void
   tree_evaluator::visit_octave_user_function_header (octave_user_function&)
   {
@@ -1178,11 +1847,12 @@
       {
         tree_expression *expr = tic->condition ();
 
-        if (statement_context == function || statement_context == script)
+        if (m_statement_context == SC_FUNCTION
+            || m_statement_context == SC_SCRIPT)
           m_call_stack.set_location (tic->line (), tic->column ());
 
-        if (debug_mode && ! tic->is_else_clause ())
-          do_breakpoint (tic->is_breakpoint (true));
+        if (m_debug_mode && ! tic->is_else_clause ())
+          do_breakpoint (tic->is_active_breakpoint (*this));
 
         if (tic->is_else_clause () || is_logically_true (expr, "if"))
           {
@@ -1196,50 +1866,6 @@
       }
   }
 
-  // Final step of processing an indexing error.  Add the name of the
-  // variable being indexed, if any, then issue an error.  (Will this also
-  // be needed by pt-lvalue, which calls subsref?)
-
-  static void
-  final_index_error (octave::index_exception& e,
-                     const octave::tree_expression *expr)
-  {
-    std::string extra_message;
-
-    // FIXME: make this a member function for direct access to symbol
-    // table and scope?
-
-    octave::symbol_scope scope
-      = octave::__require_current_scope__ ("final_index_error");
-
-    octave::symbol_record::context_id context = scope.current_context ();
-
-    if (expr->is_identifier ()
-        && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable (context))
-      {
-        std::string var = expr->name ();
-
-        e.set_var (var);
-
-        octave::symbol_table& symtab =
-          octave::__get_symbol_table__ ("final_index_error");
-
-        octave_value fcn = symtab.find_function (var);
-
-        if (fcn.is_function ())
-          {
-            octave_function *fp = fcn.function_value ();
-
-            if (fp && fp->name () == var)
-              extra_message = " (note: variable '" + var + "' shadows function)";
-          }
-      }
-
-    std::string msg = e.message () + extra_message;
-
-    error_with_id (e.err_id (), msg.c_str ());
-  }
-
   // Unlike Matlab, which does not allow the result of a function call
   // or array indexing expression to be further indexed, Octave attempts
   // to handle arbitrary index expressions.  For example, Octave allows
@@ -1325,9 +1951,9 @@
 
     assert (! args.empty ());
 
-    std::list<tree_argument_list *>::iterator p_args = args.begin ();
-    std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
-    std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
+    auto p_args = args.begin ();
+    auto p_arg_nm = arg_nm.begin ();
+    auto p_dyn_field = dyn_field.begin ();
 
     int n = args.size ();
     int beg = 0;
@@ -1363,7 +1989,7 @@
                                   &value_stack<const std::list<octave_lvalue>*>::pop);
 
                 string_vector anm = *p_arg_nm;
-                first_args = al->convert_to_const_vector (this);
+                first_args = convert_to_const_vector (al);
                 first_args.stash_name_tags (anm);
               }
 
@@ -1506,7 +2132,7 @@
 
           case '.':
             idx.push_back (octave_value
-                           (idx_expr.get_struct_index (this, p_arg_nm, p_dyn_field)));
+                           (idx_expr.get_struct_index (*this, p_arg_nm, p_dyn_field)));
             break;
 
           default:
@@ -1534,7 +2160,7 @@
                 beg = n;
                 idx.clear ();
               }
-            catch (octave::index_exception& e)
+            catch (index_exception& e)
               {
                 final_index_error (e, expr);
               }
@@ -1553,7 +2179,7 @@
                   {
                     retval = fcn->call (*this, nargout, idx);
                   }
-                catch (octave::index_exception& e)
+                catch (index_exception& e)
                   {
                     final_index_error (e, expr);
                   }
@@ -1597,200 +2223,9 @@
   void
   tree_evaluator::visit_matrix (tree_matrix& expr)
   {
-    octave_value retval = Matrix ();
-
-    bool all_strings_p = false;
-    bool all_sq_strings_p = false;
-    bool all_dq_strings_p = false;
-    bool all_empty_p = false;
-    bool all_real_p = false;
-    bool any_sparse_p = false;
-    bool any_class_p = false;
-    bool frc_str_conv = false;
-
-    tm_const tmp (expr, this);
-
-    if (tmp && ! tmp.empty ())
-      {
-        dim_vector dv = tmp.dims ();
-        all_strings_p = tmp.all_strings_p ();
-        all_sq_strings_p = tmp.all_sq_strings_p ();
-        all_dq_strings_p = tmp.all_dq_strings_p ();
-        all_empty_p = tmp.all_empty_p ();
-        all_real_p = tmp.all_real_p ();
-        any_sparse_p = tmp.any_sparse_p ();
-        any_class_p = tmp.any_class_p ();
-        frc_str_conv = tmp.some_strings_p ();
-
-        // Try to speed up the common cases.
-
-        std::string result_type = tmp.class_name ();
-
-        if (any_class_p)
-          {
-            retval = do_class_concat (tmp);
-          }
-        else if (result_type == "double")
-          {
-            if (any_sparse_p)
-              {
-                if (all_real_p)
-                  retval = do_single_type_concat<SparseMatrix> (dv, tmp);
-                else
-                  retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp);
-              }
-            else
-              {
-                if (all_real_p)
-                  retval = do_single_type_concat<NDArray> (dv, tmp);
-                else
-                  retval = do_single_type_concat<ComplexNDArray> (dv, tmp);
-              }
-          }
-        else if (result_type == "single")
-          {
-            if (all_real_p)
-              retval = do_single_type_concat<FloatNDArray> (dv, tmp);
-            else
-              retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp);
-          }
-        else if (result_type == "char")
-          {
-            char type = (all_dq_strings_p ? '"' : '\'');
-
-            if (! all_strings_p)
-              warn_implicit_conversion ("Octave:num-to-str",
-                                        "numeric", result_type);
-            else
-              maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p);
-
-            charNDArray result (dv, m_string_fill_char);
-
-            single_type_concat<charNDArray> (result, tmp);
-
-            retval = octave_value (result, type);
-          }
-        else if (result_type == "logical")
-          {
-            if (any_sparse_p)
-              retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp);
-            else
-              retval = do_single_type_concat<boolNDArray> (dv, tmp);
-          }
-        else if (result_type == "int8")
-          retval = do_single_type_concat<int8NDArray> (dv, tmp);
-        else if (result_type == "int16")
-          retval = do_single_type_concat<int16NDArray> (dv, tmp);
-        else if (result_type == "int32")
-          retval = do_single_type_concat<int32NDArray> (dv, tmp);
-        else if (result_type == "int64")
-          retval = do_single_type_concat<int64NDArray> (dv, tmp);
-        else if (result_type == "uint8")
-          retval = do_single_type_concat<uint8NDArray> (dv, tmp);
-        else if (result_type == "uint16")
-          retval = do_single_type_concat<uint16NDArray> (dv, tmp);
-        else if (result_type == "uint32")
-          retval = do_single_type_concat<uint32NDArray> (dv, tmp);
-        else if (result_type == "uint64")
-          retval = do_single_type_concat<uint64NDArray> (dv, tmp);
-        else if (result_type == "cell")
-          retval = do_single_type_concat<Cell> (dv, tmp);
-        else if (result_type == "struct")
-          retval = do_single_type_concat<octave_map> (dv, tmp);
-        else
-          {
-            // The line below might seem crazy, since we take a copy of
-            // the first argument, resize it to be empty and then resize
-            // it to be 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 copy all data.
-            //
-            // We might also start with a empty octave_value using
-            //
-            //    ctmp = octave::type_info::lookup_type
-            //          (tmp.begin() -> begin() -> type_name());
-            //
-            // and then directly resize.  However, for some types there
-            // might be some additional setup needed, and so this should
-            // be avoided.
-
-            octave_value ctmp;
-
-            // Find the first non-empty object
-
-            if (any_sparse_p)
-              {
-                // Start with sparse matrix to avoid issues memory issues
-                // with things like [ones(1,4),sprandn(1e8,4,1e-4)]
-                if (all_real_p)
-                  ctmp = octave_sparse_matrix ().resize (dv);
-                else
-                  ctmp = octave_sparse_complex_matrix ().resize (dv);
-              }
-            else
-              {
-                for (tm_row_const& row : tmp)
-                  {
-                    octave_quit ();
-
-                    for (auto& elt : row)
-                      {
-                        octave_quit ();
-
-                        ctmp = elt;
-
-                        if (! ctmp.all_zero_dims ())
-                          goto found_non_empty;
-                      }
-                  }
-
-                ctmp = (*(tmp.begin () -> begin ()));
-
-              found_non_empty:
-
-                if (! all_empty_p)
-                  ctmp = ctmp.resize (dim_vector (0,0)).resize (dv);
-              }
-
-            // Now, extract the values from the individual elements and
-            // insert them in the result matrix.
-
-            type_info& ti = m_interpreter.get_type_info ();
-
-            int dv_len = dv.ndims ();
-            octave_idx_type ntmp = (dv_len > 1 ? dv_len : 2);
-            Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
-
-            for (tm_row_const& row : tmp)
-              {
-                octave_quit ();
-
-                for (auto& elt : row)
-                  {
-                    octave_quit ();
-
-                    if (elt.isempty ())
-                      continue;
-
-                    ctmp = do_cat_op (ti, ctmp, elt, ra_idx);
-
-                    ra_idx (1) += elt.columns ();
-                  }
-
-                ra_idx (0) += row.rows ();
-                ra_idx (1) = 0;
-              }
-
-            retval = ctmp;
-
-            if (frc_str_conv && ! retval.is_string ())
-              retval = retval.convert_to_str ();
-          }
-      }
-
-    push_result (retval);
+    tm_const tmp (expr, *this);
+
+    push_result (tmp.concat (m_string_fill_char));
   }
 
   void
@@ -1817,7 +2252,7 @@
 
     for (tree_argument_list *elt : expr)
       {
-        octave_value_list row = elt->convert_to_const_vector (this);
+        octave_value_list row = convert_to_const_vector (elt);
 
         if (nr == 1)
           // Optimize the single row case.
@@ -1895,7 +2330,7 @@
         // postpone joining the final values.
         std::list<octave_value_list> retval_list;
 
-        tree_argument_list::iterator q = lhs->begin ();
+        auto q = lhs->begin ();
 
         for (octave_lvalue ult : lvalue_list)
           {
@@ -1961,8 +2396,8 @@
                         octave_value tmp = rhs_val(k);
 
                         if (tmp.is_undefined ())
-                          error ("element number %d undefined in return list",
-                                 k+1);
+                          error ("element number %" OCTAVE_IDX_TYPE_FORMAT
+                                 " undefined in return list", k+1);
 
                         ult.assign (octave_value::op_asn_eq, tmp);
 
@@ -1989,7 +2424,8 @@
                     // don't need is missing from the list.
 
                     if (! ult.is_black_hole ())
-                      error ("element number %d undefined in return list", k+1);
+                      error ("element number %" OCTAVE_IDX_TYPE_FORMAT
+                             " undefined in return list", k+1);
 
                     k++;
                     continue;
@@ -2030,8 +2466,8 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode && cmd.is_end_of_fcn_or_script ())
-      do_breakpoint (cmd.is_breakpoint (true), true);
+    if (m_debug_mode && cmd.is_end_of_fcn_or_script ())
+      do_breakpoint (cmd.is_active_breakpoint (*this), true);
   }
 
   void
@@ -2106,7 +2542,7 @@
 
         if (etype == octave_value::op_incr || etype == octave_value::op_decr)
           {
-            octave_lvalue ref = op->lvalue (this);
+            octave_lvalue ref = op->lvalue (*this);
 
             val = ref.value ();
 
@@ -2146,7 +2582,7 @@
 
         if (etype == octave_value::op_incr || etype == octave_value::op_decr)
           {
-            octave_lvalue op_ref = op->lvalue (this);
+            octave_lvalue op_ref = op->lvalue (*this);
 
             profiler::enter<tree_prefix_expression> block (m_profiler, expr);
 
@@ -2190,20 +2626,21 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
 
     // Act like dbcont.
 
-    if (Vdebugging && m_call_stack.current_frame () == current_frame)
+    if (Vdebugging && m_call_stack.current_frame () == m_current_frame)
       {
         Vdebugging = false;
 
         reset_debug_state ();
       }
-    else if (statement_context == function || statement_context == script
-             || in_loop_command)
-      tree_return_command::returning = 1;
+    else if (m_statement_context == SC_FUNCTION
+             || m_statement_context == SC_SCRIPT
+             || m_in_loop_command)
+      m_returning = 1;
   }
 
   void
@@ -2221,28 +2658,13 @@
 
     if (rhs)
       {
-        octave_value rhs_val = evaluate (rhs);
-
-        if (rhs_val.is_undefined ())
-          error ("value on right hand side of assignment is undefined");
-
-        if (rhs_val.is_cs_list ())
-          {
-            const octave_value_list lst = rhs_val.list_value ();
-
-            if (lst.empty ())
-              error ("invalid number of elements on RHS of assignment");
-
-            rhs_val = lst(0);
-          }
-
         tree_expression *lhs = expr.left_hand_side ();
 
         try
           {
             unwind_protect frame;
 
-            octave_lvalue ult = lhs->lvalue (this);
+            octave_lvalue ult = lhs->lvalue (*this);
 
             std::list<octave_lvalue> lvalue_list;
             lvalue_list.push_back (ult);
@@ -2255,6 +2677,21 @@
             if (ult.numel () != 1)
               err_invalid_structure_assignment ();
 
+            octave_value rhs_val = evaluate (rhs);
+
+            if (rhs_val.is_undefined ())
+              error ("value on right hand side of assignment is undefined");
+
+            if (rhs_val.is_cs_list ())
+              {
+                const octave_value_list lst = rhs_val.list_value ();
+
+                if (lst.empty ())
+                  error ("invalid number of elements on RHS of assignment");
+
+                rhs_val = lst(0);
+              }
+
             octave_value::assign_op etype = expr.op_type ();
 
             ult.assign (etype, rhs_val);
@@ -2285,7 +2722,7 @@
           {
             e.set_var (lhs->name ());
             std::string msg = e.message ();
-            error_with_id (e.err_id (), msg.c_str ());
+            error_with_id (e.err_id (), "%s", msg.c_str ());
           }
       }
 
@@ -2300,7 +2737,8 @@
 
     if (cmd || expr)
       {
-        if (statement_context == function || statement_context == script)
+        if (m_statement_context == SC_FUNCTION
+            || m_statement_context == SC_SCRIPT)
           {
             // Skip commands issued at a debug> prompt to avoid disturbing
             // the state of the program we are debugging.
@@ -2322,8 +2760,8 @@
                     m_echo_file_pos = line + 1;
                   }
 
-                if (debug_mode)
-                  do_breakpoint (expr->is_breakpoint (true));
+                if (m_debug_mode)
+                  do_breakpoint (expr->is_active_breakpoint (*this));
 
                 // FIXME: maybe all of this should be packaged in
                 // one virtual function that returns a flag saying whether
@@ -2371,12 +2809,12 @@
             error_with_id ("Octave:bad-alloc",
                            "out of memory or dimension too large for Octave's index type");
           }
-        catch (const octave::interrupt_exception&)
+        catch (const interrupt_exception&)
           {
             // If we are debugging, then continue with next statement.
             // Otherwise, jump out of here.
 
-            if (debug_mode)
+            if (m_debug_mode)
               interpreter::recover_from_exception ();
             else
               throw;
@@ -2390,7 +2828,7 @@
     // FIXME: commented out along with else clause below.
     // static octave_value_list empty_list;
 
-    tree_statement_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     if (p != lst.end ())
       {
@@ -2405,11 +2843,10 @@
 
             elt->accept (*this);
 
-            if (tree_break_command::breaking
-                || tree_continue_command::continuing)
+            if (m_breaking || m_continuing)
               break;
 
-            if (tree_return_command::returning)
+            if (m_returning)
               break;
 
             if (p == lst.end ())
@@ -2457,8 +2894,8 @@
         m_echo_file_pos = line + 1;
       }
 
-    if (debug_mode)
-      do_breakpoint (cmd.is_breakpoint (true));
+    if (m_debug_mode)
+      do_breakpoint (cmd.is_active_breakpoint (*this));
 
     tree_expression *expr = cmd.switch_value ();
 
@@ -2546,7 +2983,7 @@
 
             if (expr_id)
               {
-                octave_lvalue ult = expr_id->lvalue (this);
+                octave_lvalue ult = expr_id->lvalue (*this);
 
                 octave_scalar_map err;
 
@@ -2585,11 +3022,11 @@
     // We don't have to worry about continue statements because they can
     // only occur in loops.
 
-    frame.protect_var (tree_return_command::returning);
-    tree_return_command::returning = 0;
-
-    frame.protect_var (tree_break_command::breaking);
-    tree_break_command::breaking = 0;
+    frame.protect_var (m_returning);
+    m_returning = 0;
+
+    frame.protect_var (m_breaking);
+    m_breaking = 0;
 
     try
       {
@@ -2600,7 +3037,7 @@
       {
         interpreter::recover_from_exception ();
 
-        if (tree_break_command::breaking || tree_return_command::returning)
+        if (m_breaking || m_returning)
           frame.discard (2);
         else
           frame.run (2);
@@ -2637,7 +3074,7 @@
     // break in the cleanup block, the values should be reset to
     // whatever they were when the cleanup block was entered.
 
-    if (tree_break_command::breaking || tree_return_command::returning)
+    if (m_breaking || m_returning)
       frame.discard (2);
     else
       frame.run (2);
@@ -2711,9 +3148,9 @@
 
     unwind_protect frame;
 
-    frame.protect_var (in_loop_command);
-
-    in_loop_command = true;
+    frame.protect_var (m_in_loop_command);
+
+    m_in_loop_command = true;
 
     tree_expression *expr = cmd.condition ();
 
@@ -2725,8 +3162,8 @@
         if (m_echo_state)
           m_echo_file_pos = line;
 
-        if (debug_mode)
-          do_breakpoint (cmd.is_breakpoint (true));
+        if (m_debug_mode)
+          do_breakpoint (cmd.is_active_breakpoint (*this));
 
         if (is_logically_true (expr, "while"))
           {
@@ -2761,9 +3198,9 @@
 
     unwind_protect frame;
 
-    frame.protect_var (in_loop_command);
-
-    in_loop_command = true;
+    frame.protect_var (m_in_loop_command);
+
+    m_in_loop_command = true;
 
     tree_expression *expr = cmd.condition ();
     int until_line = cmd.line ();
@@ -2785,8 +3222,8 @@
         if (quit_loop_now ())
           break;
 
-        if (debug_mode)
-          do_breakpoint (cmd.is_breakpoint (true));
+        if (m_debug_mode)
+          do_breakpoint (cmd.is_active_breakpoint (*this));
 
         m_call_stack.set_location (until_line, until_column);
 
@@ -2825,38 +3262,31 @@
   }
 
   void
-  tree_evaluator::do_breakpoint (tree_statement& stmt) const
+  tree_evaluator::do_breakpoint (tree_statement& stmt)
   {
-    do_breakpoint (stmt.is_breakpoint (true), stmt.is_end_of_fcn_or_script ());
+    do_breakpoint (stmt.is_active_breakpoint (*this),
+                   stmt.is_end_of_fcn_or_script ());
   }
 
   void
   tree_evaluator::do_breakpoint (bool is_breakpoint,
-                                 bool is_end_of_fcn_or_script) const
+                                 bool is_end_of_fcn_or_script)
   {
     bool break_on_this_statement = false;
 
-    if (octave_debug_on_interrupt_state)
+    if (is_breakpoint)
       {
         break_on_this_statement = true;
 
-        octave_debug_on_interrupt_state = false;
-
-        current_frame = m_call_stack.current_frame ();
+        m_dbstep_flag = 0;
+
+        m_current_frame = m_call_stack.current_frame ();
       }
-    else if (is_breakpoint)
+    else if (m_dbstep_flag > 0)
       {
-        break_on_this_statement = true;
-
-        dbstep_flag = 0;
-
-        current_frame = m_call_stack.current_frame ();
-      }
-    else if (dbstep_flag > 0)
-      {
-        if (m_call_stack.current_frame () == current_frame)
+        if (m_call_stack.current_frame () == m_current_frame)
           {
-            if (dbstep_flag == 1 || is_end_of_fcn_or_script)
+            if (m_dbstep_flag == 1 || is_end_of_fcn_or_script)
               {
                 // We get here if we are doing a "dbstep" or a "dbstep N" and the
                 // count has reached 1 so that we must stop and return to debug
@@ -2866,39 +3296,39 @@
 
                 break_on_this_statement = true;
 
-                dbstep_flag = 0;
+                m_dbstep_flag = 0;
               }
             else
               {
                 // Executing "dbstep N".  Decrease N by one and continue.
 
-                dbstep_flag--;
+                m_dbstep_flag--;
               }
 
           }
-        else if (dbstep_flag == 1
-                 && m_call_stack.current_frame () < current_frame)
+        else if (m_dbstep_flag == 1
+                 && m_call_stack.current_frame () < m_current_frame)
           {
             // We stepped out from the end of a function.
 
-            current_frame = m_call_stack.current_frame ();
+            m_current_frame = m_call_stack.current_frame ();
 
             break_on_this_statement = true;
 
-            dbstep_flag = 0;
+            m_dbstep_flag = 0;
           }
       }
-    else if (dbstep_flag == -1)
+    else if (m_dbstep_flag == -1)
       {
         // We get here if we are doing a "dbstep in".
 
         break_on_this_statement = true;
 
-        dbstep_flag = 0;
-
-        current_frame = m_call_stack.current_frame ();
+        m_dbstep_flag = 0;
+
+        m_current_frame = m_call_stack.current_frame ();
       }
-    else if (dbstep_flag == -2)
+    else if (m_dbstep_flag == -2)
       {
         // We get here if we are doing a "dbstep out".  Check for end of
         // function and whether the current frame is the same as the
@@ -2907,13 +3337,16 @@
         // that frame.
 
         if (is_end_of_fcn_or_script
-            && m_call_stack.current_frame () == current_frame)
-          dbstep_flag = -1;
+            && m_call_stack.current_frame () == m_current_frame)
+          m_dbstep_flag = -1;
       }
 
     if (break_on_this_statement)
-      do_keyboard ();
-
+      {
+        input_system& input_sys = m_interpreter.get_input_system ();
+
+        input_sys.keyboard ();
+      }
   }
 
   // ARGS is currently unused, but since the do_keyboard function in
@@ -2923,7 +3356,9 @@
   octave_value
   tree_evaluator::do_keyboard (const octave_value_list& args) const
   {
-    return ::do_keyboard (args);
+    input_system& input_sys = m_interpreter.get_input_system ();
+
+    return input_sys.keyboard (args);
   }
 
   bool
@@ -2965,7 +3400,7 @@
             && object->is_undefined ())
           err_invalid_inquiry_subscript ();
 
-        retval = args->convert_to_const_vector (this, object);
+        retval = convert_to_const_vector (args, object);
       }
 
     octave_idx_type n = retval.length ();
@@ -2982,7 +3417,7 @@
     std::list<octave_lvalue> retval;
 
     for (tree_expression *elt : *lhs)
-      retval.push_back (elt->lvalue (this));
+      retval.push_back (elt->lvalue (*this));
 
     return retval;
   }
@@ -2996,6 +3431,13 @@
   }
 
   octave_value
+  tree_evaluator::whos_line_format (const octave_value_list& args, int nargout)
+  {
+    return set_internal_variable (m_whos_line_format, args, nargout,
+                                  "whos_line_format");
+  }
+
+  octave_value
   tree_evaluator::silent_functions (const octave_value_list& args, int nargout)
   {
     return set_internal_variable (m_silent_functions, args, nargout,
@@ -3009,6 +3451,45 @@
                                   "string_fill_char");
   }
 
+  // Final step of processing an indexing error.  Add the name of the
+  // 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,
+                                          const tree_expression *expr)
+  {
+    std::string extra_message;
+
+    symbol_scope scope = get_current_scope ();
+
+    symbol_record::context_id ctxt = scope.current_context ();
+
+    if (expr->is_identifier ()
+        && dynamic_cast<const tree_identifier *> (expr)->is_variable (ctxt))
+      {
+        std::string var = expr->name ();
+
+        e.set_var (var);
+
+        symbol_table& symtab = m_interpreter.get_symbol_table ();
+
+        octave_value fcn = symtab.find_function (var);
+
+        if (fcn.is_function ())
+          {
+            octave_function *fp = fcn.function_value ();
+
+            if (fp && fp->name () == var)
+              extra_message
+                = " (note: variable '" + var + "' shadows function)";
+          }
+      }
+
+    std::string msg = e.message () + extra_message;
+
+    error_with_id (e.err_id (), "%s", msg.c_str ());
+  }
+
   void
   tree_evaluator::push_echo_state (unwind_protect& frame, int type,
                                    const std::string& file_name,
@@ -3029,6 +3510,15 @@
   }
 
   void
+  tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name,
+                                      size_t pos)
+  {
+    m_echo_state = state;
+    m_echo_file_name = file_name;
+    m_echo_file_pos = pos;
+  }
+
+  void
   tree_evaluator::maybe_set_echo_state (void)
   {
     octave_function *caller = m_call_stack.caller ();
@@ -3050,36 +3540,23 @@
   void
   tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
   {
-    frame.add_method (*this, &tree_evaluator::set_echo_state,
-                      m_echo_state);
-
-    frame.add_method (*this, &tree_evaluator::set_echo_file_name,
-                      m_echo_file_name);
-
-    frame.add_method (*this, &tree_evaluator::set_echo_file_pos,
-                      m_echo_file_pos);
+    frame.add_method (this, &tree_evaluator::uwp_set_echo_state,
+                      m_echo_state, m_echo_file_name, m_echo_file_pos);
   }
 
   bool tree_evaluator::maybe_push_echo_state_cleanup (void)
   {
     // This function is expected to be called from ECHO, which would be
     // the top of the call stack.  If the caller of ECHO is a
-    // user-defined fucntion or script, then set up unwind-protect
+    // user-defined function or script, then set up unwind-protect
     // elements to restore echo state.
 
-    octave_function *caller = m_call_stack.caller ();
-
-    if (caller && caller->is_user_code ())
+    unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
+
+    if (frame)
       {
-        octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
-
-        unwind_protect *frame = fcn->unwind_protect_frame ();
-
-        if (frame)
-          {
-            push_echo_state_cleanup (*frame);
-            return true;
-          }
+        push_echo_state_cleanup (*frame);
+        return true;
       }
 
     return false;
@@ -3272,6 +3749,66 @@
           octave_stdout << prefix << elt << std::endl;
       }
   }
+
+  // Decide if it's time to quit a for or while loop.
+  bool tree_evaluator::quit_loop_now (void)
+  {
+    octave_quit ();
+
+    // Maybe handle 'continue N' someday...
+
+    if (m_continuing)
+      m_continuing--;
+
+    bool quit = (m_returning || m_breaking || m_continuing);
+
+    if (m_breaking)
+      m_breaking--;
+
+    return quit;
+  }
+
+  void tree_evaluator::bind_auto_fcn_vars (symbol_scope& scope,
+                                           const string_vector& arg_names,
+                                           int nargin, int nargout,
+                                           bool takes_varargs,
+                                           const octave_value_list& va_args)
+  {
+    scope.force_assign (".argn.", Cell (arg_names));
+    scope.mark_hidden (".argn.");
+    scope.mark_automatic (".argn.");
+
+    scope.force_assign (".ignored.", ignored_fcn_outputs ());
+    scope.mark_hidden (".ignored.");
+    scope.mark_automatic (".ignored.");
+
+    scope.force_assign (".nargin.", nargin);
+    scope.mark_hidden (".nargin.");
+    scope.mark_automatic (".nargin.");
+
+    scope.force_assign (".nargout.", nargout);
+    scope.mark_hidden (".nargout.");
+    scope.mark_automatic (".nargout.");
+
+    scope.force_assign (".saved_warning_states.", octave_value ());
+    scope.mark_hidden (".saved_warning_states.");
+    scope.mark_automatic (".saved_warning_states.");
+
+    if (! arg_names.empty ())
+      {
+        // It is better to save this in the hidden variable .argn. and
+        // then use that in the inputname function instead of using argn,
+        // which might be redefined in a function.  Keep the old argn name
+        // for backward compatibility of functions that use it directly.
+
+        charMatrix chm (arg_names, string_fill_char ());
+        scope.force_assign ("argn", chm);
+        scope.mark_automatic ("argn");
+      }
+
+    if (takes_varargs)
+      scope.assign ("varargin", va_args.cell_value ());
+  }
 }
 
 DEFMETHOD (max_recursion_depth, interp, args, nargout,
@@ -3309,6 +3846,85 @@
 %!error (max_recursion_depth (1, 2))
 */
 
+DEFMETHOD (whos_line_format, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{val} =} whos_line_format ()
+@deftypefnx {} {@var{old_val} =} whos_line_format (@var{new_val})
+@deftypefnx {} {} whos_line_format (@var{new_val}, "local")
+Query or set the format string used by the command @code{whos}.
+
+A full format string is:
+@c Set example in small font to prevent overfull line
+
+@smallexample
+%[modifier]<command>[:width[:left-min[:balance]]];
+@end smallexample
+
+The following command sequences are available:
+
+@table @code
+@item %a
+Prints attributes of variables (g=global, p=persistent, f=formal parameter,
+a=automatic variable).
+
+@item %b
+Prints number of bytes occupied by variables.
+
+@item %c
+Prints class names of variables.
+
+@item %e
+Prints elements held by variables.
+
+@item %n
+Prints variable names.
+
+@item %s
+Prints dimensions of variables.
+
+@item %t
+Prints type names of variables.
+@end table
+
+Every command may also have an alignment modifier:
+
+@table @code
+@item l
+Left alignment.
+
+@item r
+Right alignment (default).
+
+@item c
+Column-aligned (only applicable to command %s).
+@end table
+
+The @code{width} parameter is a positive integer specifying the minimum
+number of columns used for printing.  No maximum is needed as the field will
+auto-expand as required.
+
+The parameters @code{left-min} and @code{balance} are only available when
+the column-aligned modifier is used with the command @samp{%s}.
+@code{balance} specifies the column number within the field width which
+will be aligned between entries.  Numbering starts from 0 which indicates
+the leftmost column.  @code{left-min} specifies the minimum field width to
+the left of the specified balance column.
+
+The default format is:
+
+@qcode{"  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;@xbackslashchar{}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.
+The original variable value is restored when exiting the function.
+@seealso{whos}
+@end deftypefn */)
+{
+  octave::tree_evaluator& tw = interp.get_evaluator ();
+
+  return tw.whos_line_format (args, nargout);
+}
+
 DEFMETHOD (silent_functions, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} silent_functions ()
--- a/libinterp/parse-tree/pt-eval.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-eval.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,6 +30,7 @@
 #include <stack>
 #include <string>
 
+#include "bp-table.h"
 #include "call-stack.h"
 #include "ov.h"
 #include "ovl.h"
@@ -37,6 +38,8 @@
 #include "pt-exp.h"
 #include "pt-walk.h"
 
+class octave_user_code;
+
 namespace octave
 {
   class symbol_scope;
@@ -123,14 +126,19 @@
     typedef void (*decl_elt_init_fcn) (tree_decl_elt&);
 
     tree_evaluator (interpreter& interp)
-      : m_interpreter (interp), m_result_type (RT_UNDEFINED),
-        m_expr_result_value (), m_expr_result_value_list (),
-        m_lvalue_list_stack (), m_nargout_stack (),
-        m_call_stack (interp), m_profiler (),
-        m_max_recursion_depth (256), m_silent_functions (false),
-        m_string_fill_char (' '), m_PS4 ("+ "), m_echo (ECHO_OFF),
+      : m_interpreter (interp), m_statement_context (SC_OTHER),
+        m_result_type (RT_UNDEFINED), m_expr_result_value (),
+        m_expr_result_value_list (), m_lvalue_list_stack (),
+        m_nargout_stack (), m_bp_table (*this), m_call_stack (interp),
+        m_profiler (), m_current_frame (0), m_debug_mode (false),
+        m_quiet_breakpoint_flag (false), 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_echo_state (false), m_echo_file_name (), m_echo_file_pos (1),
-        m_echo_files ()
+        m_echo_files (), m_in_loop_command (false),
+        m_breaking (0), m_continuing (0), m_returning (0),
+        m_indexed_object (nullptr), m_index_position (0), m_num_indices (0)
     { }
 
     // No copying!
@@ -143,6 +151,17 @@
 
     void reset (void);
 
+    int repl (bool interactive);
+
+    octave_value_list eval_string (const std::string& eval_str, bool silent,
+                                   int& parse_status, int nargout);
+
+    octave_value eval_string (const std::string& eval_str, bool silent,
+                              int& parse_status);
+
+    octave_value_list eval_string (const octave_value& arg, bool silent,
+                                   int& parse_status, int nargout);
+
     void visit_anon_fcn_handle (tree_anon_fcn_handle&);
 
     void visit_argument_list (tree_argument_list&);
@@ -171,8 +190,16 @@
 
     void visit_octave_user_script (octave_user_script&);
 
+    octave_value_list
+    execute_user_script (octave_user_script& user_script, int nargout,
+                         const octave_value_list& args);
+
     void visit_octave_user_function (octave_user_function&);
 
+    octave_value_list
+    execute_user_function (octave_user_function& user_function, int nargout,
+                           const octave_value_list& args);
+
     void visit_octave_user_function_header (octave_user_function&);
 
     void visit_octave_user_function_trailer (octave_user_function&);
@@ -238,35 +265,20 @@
 
     bool statement_printing_enabled (void);
 
-    static void reset_debug_state (void);
+    void reset_debug_state (void);
 
-    // If > 0, stop executing at the (N-1)th stopping point, counting
-    //         from the the current execution point in the current frame.
-    //
-    // If < 0, stop executing at the next possible stopping point.
-    static int dbstep_flag;
+    void reset_debug_state (bool mode);
 
-    // The number of the stack frame we are currently debugging.
-    static size_t current_frame;
-
-    static bool debug_mode;
-
-    static bool quiet_breakpoint_flag;
+    void set_dbstep_flag (int step) { m_dbstep_flag = step; }
 
     // Possible types of evaluation contexts.
     enum stmt_list_type
     {
-      function,  // function body
-      script,    // script file
-      other      // command-line input or eval string
+      SC_FUNCTION,  // function body
+      SC_SCRIPT,    // script file
+      SC_OTHER      // command-line input or eval string
     };
 
-    // The context for the current evaluation.
-    static stmt_list_type statement_context;
-
-    // TRUE means we are evaluating some kind of looping construct.
-    static bool in_loop_command;
-
     Matrix ignored_fcn_outputs (void) const;
 
     bool isargout (int nargout, int iout) const;
@@ -360,6 +372,10 @@
     void undefine_parameter_list (tree_parameter_list *param_list);
 
     octave_value_list
+    convert_to_const_vector (tree_argument_list *arg_list,
+                             const octave_value *object = nullptr);
+
+    octave_value_list
     convert_return_list_to_const_vector
       (tree_parameter_list *ret_list, int nargout, const Cell& varargout);
 
@@ -368,12 +384,18 @@
     bool switch_case_label_matches (tree_switch_case *expr,
                                     const octave_value& val);
 
+    interpreter& get_interpreter (void) { return m_interpreter; }
+
+    bp_table& get_bp_table (void) { return m_bp_table; }
+
     call_stack& get_call_stack (void) { return m_call_stack; }
 
     profiler& get_profiler (void) { return m_profiler; }
 
     symbol_scope get_current_scope (void);
 
+    octave_user_code * get_user_code (const std::string& fname = "");
+
     int max_recursion_depth (void) const { return m_max_recursion_depth; }
 
     int max_recursion_depth (int n)
@@ -395,9 +417,47 @@
       return val;
     }
 
+    octave_value whos_line_format (const octave_value_list& args, int nargout);
+
+    std::string whos_line_format (void) const { return m_whos_line_format; }
+
+    std::string whos_line_format (const std::string& s)
+    {
+      std::string val = m_whos_line_format;
+      m_whos_line_format = s;
+      return val;
+    }
+
     octave_value
     silent_functions (const octave_value_list& args, int nargout);
 
+    size_t current_frame (void) const { return m_current_frame; }
+
+    size_t current_frame (size_t n)
+    {
+      size_t val = m_current_frame;
+      m_current_frame = n;
+      return val;
+    }
+
+    bool debug_mode (void) const { return m_debug_mode; }
+
+    bool debug_mode (bool flag)
+    {
+      bool val = m_debug_mode;
+      m_debug_mode = flag;
+      return val;
+    }
+
+    bool quiet_breakpoint_flag (void) const { return m_quiet_breakpoint_flag; }
+
+    bool quiet_breakpoint_flag (bool flag)
+    {
+      bool val = m_quiet_breakpoint_flag;
+      m_quiet_breakpoint_flag = flag;
+      return val;
+    }
+
     char string_fill_char (void) const { return m_string_fill_char; }
 
     char string_fill_char (char c)
@@ -418,6 +478,42 @@
       return val;
     }
 
+    const octave_value * indexed_object (void) const
+    {
+      return m_indexed_object;
+    }
+
+    int index_position (void) const { return m_index_position; }
+
+    int num_indices (void) const { return m_num_indices; }
+
+    int breaking (void) const { return m_breaking; }
+
+    int breaking (int n)
+    {
+      int val = m_breaking;
+      m_breaking = n;
+      return val;
+    }
+
+    int continuing (void) const { return m_continuing; }
+
+    int continuing (int n)
+    {
+      int val = m_continuing;
+      m_continuing = n;
+      return val;
+    }
+
+    int returning (void) const { return m_returning; }
+
+    int returning (int n)
+    {
+      int val = m_returning;
+      m_returning = n;
+      return val;
+    }
+
     octave_value echo (const octave_value_list& args, int nargout);
 
     int echo (void) const { return m_echo; }
@@ -432,6 +528,8 @@
     octave_value
     string_fill_char (const octave_value_list& args, int nargout);
 
+    void final_index_error (index_exception& e, const tree_expression *expr);
+
     void push_echo_state (unwind_protect& frame, int type,
                           const std::string& file_name, size_t pos = 1);
 
@@ -445,10 +543,10 @@
 
     bool maybe_push_echo_state_cleanup (void);
 
-    void do_breakpoint (tree_statement& stmt) const;
+    void do_breakpoint (tree_statement& stmt);
 
     void do_breakpoint (bool is_breakpoint,
-                        bool is_end_of_fcn_or_script = false) const;
+                        bool is_end_of_fcn_or_script = false);
 
     virtual octave_value
     do_keyboard (const octave_value_list& args = octave_value_list ()) const;
@@ -463,26 +561,25 @@
     std::list<octave_lvalue> make_lvalue_list (tree_argument_list *);
 
     // For unwind-protect.
-    void set_echo_state (bool val) { m_echo_state = val; }
-
-    // For unwind-protect.
-    void set_echo_file_name (const std::string& file_name)
-    {
-      m_echo_file_name = file_name;
-    }
-
-    // For unwind-protect.
-    void set_echo_file_pos (const size_t& file_pos)
-    {
-      m_echo_file_pos = file_pos;
-    }
+    void uwp_set_echo_state (bool state, const std::string& file_name,
+                             size_t pos);
 
     bool echo_this_file (const std::string& file, int type) const;
 
     void echo_code (size_t line);
 
+    bool quit_loop_now (void);
+
+    void bind_auto_fcn_vars (symbol_scope& scope,
+                             const string_vector& arg_names, int nargin,
+                             int nargout, bool takes_varargs,
+                             const octave_value_list& va_args);
+
     interpreter& m_interpreter;
 
+    // The context for the current evaluation.
+    stmt_list_type m_statement_context;
+
     result_type m_result_type;
     octave_value m_expr_result_value;
     octave_value_list m_expr_result_value_list;
@@ -491,14 +588,26 @@
 
     value_stack<int> m_nargout_stack;
 
+    bp_table m_bp_table;
+
     call_stack m_call_stack;
 
     profiler m_profiler;
 
+    // The number of the stack frame we are currently debugging.
+    size_t m_current_frame;
+
+    bool m_debug_mode;
+
+    bool m_quiet_breakpoint_flag;
+
     // Maximum nesting level for functions, scripts, or sourced files
     // called recursively.
     int m_max_recursion_depth;
 
+    // Defines layout for the whos/who -long command
+    std::string m_whos_line_format;
+
     // If TRUE, turn off printing of results in functions (as if a
     // semicolon has been appended to each statement).
     bool m_silent_functions;
@@ -509,6 +618,12 @@
     // String printed before echoed commands (enabled by --echo-commands).
     std::string m_PS4;
 
+    // If > 0, stop executing at the (N-1)th stopping point, counting
+    //         from the the current execution point in the current frame.
+    //
+    // If < 0, stop executing at the next possible stopping point.
+    int m_dbstep_flag;
+
     // Echo commands as they are executed?
     //
     //   1  ==>  echo commands read from script files
@@ -527,6 +642,23 @@
     size_t m_echo_file_pos;
 
     std::map<std::string, bool> m_echo_files;
+
+    // TRUE means we are evaluating some kind of looping construct.
+    bool m_in_loop_command;
+
+    // Nonzero means we're breaking out of a loop or function body.
+    int m_breaking;
+
+    // Nonzero means we're jumping to the end of a loop.
+    int m_continuing;
+
+    // Nonzero means we're returning from a function.
+    int m_returning;
+
+    // Used by END function.
+    const octave_value *m_indexed_object;
+    int m_index_position;
+    int m_num_indices;
   };
 }
 
--- a/libinterp/parse-tree/pt-exp.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-exp.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <string>
 
 #include "error.h"
@@ -38,7 +37,7 @@
   // Expressions.
 
   octave_lvalue
-  tree_expression::lvalue (tree_evaluator *)
+  tree_expression::lvalue (tree_evaluator&)
   {
     error ("invalid lvalue function called in expression");
   }
--- a/libinterp/parse-tree/pt-exp.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-exp.h	Thu Dec 20 17:18:56 2018 -0500
@@ -84,7 +84,7 @@
 
     virtual bool rvalue_ok (void) const { return false; }
 
-    virtual octave_lvalue lvalue (tree_evaluator *);
+    virtual octave_lvalue lvalue (tree_evaluator&);
 
     int paren_count (void) const { return num_parens; }
 
--- a/libinterp/parse-tree/pt-fcn-handle.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-fcn-handle.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "interpreter-private.h"
 #include "pt-fcn-handle.h"
--- a/libinterp/parse-tree/pt-id.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-id.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -65,12 +65,12 @@
   }
 
   octave_lvalue
-  tree_identifier::lvalue (tree_evaluator *tw)
+  tree_identifier::lvalue (tree_evaluator& tw)
   {
     if (m_sym.is_added_static ())
       static_workspace_error ();
 
-    symbol_scope scope = tw->get_current_scope ();
+    symbol_scope scope = tw.get_current_scope ();
 
     return octave_lvalue (m_sym, scope.current_context ());
   }
--- a/libinterp/parse-tree/pt-id.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-id.h	Thu Dec 20 17:18:56 2018 -0500
@@ -117,7 +117,7 @@
 
     bool lvalue_ok (void) const { return true; }
 
-    octave_lvalue lvalue (tree_evaluator *);
+    octave_lvalue lvalue (tree_evaluator&);
 
     void eval_undefined_error (void);
 
@@ -160,7 +160,7 @@
       return new tree_black_hole;
     }
 
-    octave_lvalue lvalue (tree_evaluator *)
+    octave_lvalue lvalue (tree_evaluator&)
     {
       octave_lvalue retval;
       retval.mark_black_hole ();
--- a/libinterp/parse-tree/pt-idx.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-idx.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -110,14 +110,14 @@
 
     while (! m_args.empty ())
       {
-        std::list<tree_argument_list *>::iterator p = m_args.begin ();
+        auto p = m_args.begin ();
         delete *p;
         m_args.erase (p);
       }
 
     while (! m_dyn_field.empty ())
       {
-        std::list<tree_expression *>::iterator p = m_dyn_field.begin ();
+        auto p = m_dyn_field.begin ();
         delete *p;
         m_dyn_field.erase (p);
       }
@@ -145,8 +145,8 @@
   }
 
   static inline octave_value_list
-  make_value_list (octave::tree_evaluator *tw,
-                   octave::tree_argument_list *m_args,
+  make_value_list (tree_evaluator& tw,
+                   tree_argument_list *m_args,
                    const string_vector& m_arg_nm, const octave_value *object,
                    bool rvalue = true)
   {
@@ -158,7 +158,7 @@
             && object->is_undefined ())
           err_invalid_inquiry_subscript ();
 
-        retval = m_args->convert_to_const_vector (tw, object);
+        retval = tw.convert_to_const_vector (m_args, object);
       }
 
     octave_idx_type n = retval.length ();
@@ -171,7 +171,7 @@
 
   std::string
   tree_index_expression::get_struct_index
-  (tree_evaluator *tw,
+  (tree_evaluator& tw,
    std::list<string_vector>::const_iterator p_arg_nm,
    std::list<tree_expression *>::const_iterator p_dyn_field) const
   {
@@ -183,7 +183,7 @@
 
         if (df)
           {
-            octave_value t = tw->evaluate (df);
+            octave_value t = tw.evaluate (df);
 
             fn = t.xstring_value ("dynamic structure field names must be strings");
           }
@@ -194,46 +194,8 @@
     return fn;
   }
 
-  // Final step of processing an indexing error.  Add the name of the
-  // variable being indexed, if any, then issue an error.  (Will this also
-  // be needed by pt-lvalue, which calls subsref?)
-
-  static void
-  final_index_error (octave::index_exception& e,
-                     const octave::tree_expression *expr)
-  {
-    std::string extra_message;
-
-    octave::symbol_table& symtab
-      = octave::__get_symbol_table__ ("final_index_error");
-
-    octave::symbol_record::context_id context = symtab.current_context ();
-
-    if (expr->is_identifier ()
-        && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable (context))
-      {
-        std::string var = expr->name ();
-
-        e.set_var (var);
-
-        octave_value fcn = symtab.find_function (var);
-
-        if (fcn.is_function ())
-          {
-            octave_function *fp = fcn.function_value ();
-
-            if (fp && fp->name () == var)
-              extra_message = " (note: variable '" + var + "' shadows function)";
-          }
-      }
-
-    std::string msg = e.message () + extra_message;
-
-    error_with_id (e.err_id (), msg.c_str ());
-  }
-
   octave_lvalue
-  tree_index_expression::lvalue (tree_evaluator *tw)
+  tree_index_expression::lvalue (tree_evaluator& tw)
   {
     octave_lvalue retval;
 
@@ -242,9 +204,9 @@
 
     int n = m_args.size ();
 
-    std::list<tree_argument_list *>::iterator p_args = m_args.begin ();
-    std::list<string_vector>::iterator p_arg_nm = m_arg_nm.begin ();
-    std::list<tree_expression *>::iterator p_dyn_field = m_dyn_field.begin ();
+    auto p_args = m_args.begin ();
+    auto p_arg_nm = m_arg_nm.begin ();
+    auto p_dyn_field = m_dyn_field.begin ();
 
     retval = m_expr->lvalue (tw);
 
@@ -266,7 +228,7 @@
               }
             catch (index_exception& e)  // problems with range, invalid type etc.
               {
-                final_index_error (e, m_expr);
+                tw.final_index_error (e, m_expr);
               }
 
             tmpidx.clear ();
--- a/libinterp/parse-tree/pt-idx.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-idx.h	Thu Dec 20 17:18:56 2018 -0500
@@ -93,7 +93,7 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_lvalue lvalue (tree_evaluator *tw);
+    octave_lvalue lvalue (tree_evaluator& tw);
 
     tree_index_expression * dup (symbol_scope& scope) const;
 
@@ -104,7 +104,7 @@
 
     std::string
     get_struct_index
-    (tree_evaluator *tw, std::list<string_vector>::const_iterator p_arg_nm,
+    (tree_evaluator& tw, std::list<string_vector>::const_iterator p_arg_nm,
      std::list<tree_expression *>::const_iterator p_dyn_field) const;
 
   private:
--- a/libinterp/parse-tree/pt-jit.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-jit.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,14 +29,14 @@
 #  include "config.h"
 #endif
 
+#include <sstream>
 #include <string>
-#include <sstream>
-#include <iostream>
 
 #include "bp-table.h"
 #include "defun.h"
 #include "errwarn.h"
 #include "ov.h"
+#include "pager.h"
 #include "pt-all.h"
 #include "pt-jit.h"
 #include "sighandlers.h"
@@ -156,8 +156,7 @@
     m_block->append (m_factory.create<jit_branch> (m_final_block));
     m_blocks.push_back (m_final_block);
 
-    for (variable_map::iterator iter = m_vmap.begin (); iter != m_vmap.end ();
-         ++iter)
+    for (auto iter = m_vmap.begin (); iter != m_vmap.end (); ++iter)
       {
         jit_variable *var = iter->second;
         const std::string& name = var->name ();
@@ -184,7 +183,7 @@
 
     if (plist)
       {
-        tree_parameter_list::iterator piter = plist->begin ();
+        auto piter = plist->begin ();
         for (size_t i = 0; i < args.size (); ++i, ++piter)
           {
             if (piter == plist->end ())
@@ -250,7 +249,7 @@
 
     // FIXME: We should use live range analysis to delete variables where
     // needed.  For now we just delete everything at the end of the function.
-    for (variable_map::iterator iter = m_vmap.begin ();
+    for (auto iter = m_vmap.begin ();
          iter != m_vmap.end ();
          ++iter)
       {
@@ -575,7 +574,7 @@
     entry_blocks[0] = m_block;
 
     // Need to construct blocks first, because they have jumps to each other.
-    tree_if_command_list::iterator iter = lst.begin ();
+    auto iter = lst.begin ();
     ++iter;
     for (size_t i = 1; iter != lst.end (); ++iter, ++i)
       {
@@ -800,7 +799,7 @@
       visit (cmd);
     else
       {
-        // stolen from octave::tree_evaluator::visit_statement
+        // stolen from tree_evaluator::visit_statement
         bool do_bind_ans = false;
 
         if (expr->is_identifier ())
@@ -832,8 +831,7 @@
   void
   jit_convert::visit_statement_list (tree_statement_list& lst)
   {
-    for (tree_statement_list::iterator iter = lst.begin (); iter != lst.end();
-         ++iter)
+    for (auto iter = lst.begin (); iter != lst.end(); ++iter)
       {
         tree_statement *elt = *iter;
         // jwe: Can this ever be null?
@@ -899,7 +897,7 @@
 
     size_t num_incoming = 0; // number of incoming blocks to our tail
 
-    tree_switch_case_list::iterator iter = lst->begin ();
+    auto iter = lst->begin ();
     for (size_t i = 0; i < case_blocks_num; ++iter, ++i)
       {
         tree_switch_case *twc = *iter;
@@ -1149,7 +1147,7 @@
 
     symbol_table& symtab = __get_symbol_table__ ("jit_convert::find_variable");
 
-    symbol_record record = symtab.find_symbol (vname, m_scope);
+    symbol_record record = m_scope.find_symbol (vname);
     if (record.is_persistent () || record.is_global ())
       throw jit_fail_exception ("Persistent and global not yet supported");
 
@@ -1234,7 +1232,7 @@
       object = visit (tree_object);
 
     size_t narg = arg_list->size ();
-    tree_argument_list::iterator iter = arg_list->begin ();
+    auto iter = arg_list->begin ();
     bool have_extra = extra_arg;
     std::vector<jit_value *> call_args (narg + 1 + have_extra);
     call_args[0] = object;
@@ -1315,8 +1313,7 @@
   void
   jit_convert::finish_breaks (jit_block *dest, const block_list& lst)
   {
-    for (block_list::const_iterator iter = lst.begin (); iter != lst.end ();
-         ++iter)
+    for (auto iter = lst.begin (); iter != lst.end (); ++iter)
       {
         jit_block *b = *iter;
         b->append (m_factory.create<jit_branch> (dest));
@@ -1335,9 +1332,8 @@
     // for now just init arguments from entry, later we will have to do
     // something more interesting
     jit_block *m_entry_block = blocks.front ();
-    for (jit_block::iterator iter = m_entry_block->begin ();
-         iter != m_entry_block->end ();
-         ++iter)
+    for (auto iter = m_entry_block->begin ();
+         iter != m_entry_block->end (); ++iter)
       if (jit_extract_argument *extract
           = dynamic_cast<jit_extract_argument *> (*iter))
         m_argument_vec.push_back (std::make_pair (extract->name (), true));
@@ -1406,8 +1402,8 @@
         tree_parameter_list *plist = fcn.parameter_list ();
         if (plist)
           {
-            tree_parameter_list::iterator piter = plist->begin ();
-            tree_parameter_list::iterator pend = plist->end ();
+            auto piter = plist->begin ();
+            auto pend = plist->end ();
             for (size_t i = 0; i < args.size () && piter != pend; ++i, ++piter)
               {
                 tree_decl_elt *elt = *piter;
@@ -1445,8 +1441,7 @@
     builder.CreateBr (first->to_llvm ());
 
     // constants aren't in the IR, we visit those first
-    for (std::list<jit_value *>::const_iterator iter = constants.begin ();
-         iter != constants.end (); ++iter)
+    for (auto iter = constants.begin (); iter != constants.end (); ++iter)
       if (! isa<jit_instruction> (*iter))
         visit (*iter);
 
@@ -1458,7 +1453,7 @@
     for (biter = blocks.begin (); biter != blocks.end (); ++biter)
       {
         jit_block& m_block = **biter;
-        for (jit_block::iterator piter = m_block.begin ();
+        for (auto piter = m_block.begin ();
              piter != m_block.end () && isa<jit_phi> (*piter); ++piter)
           {
             jit_instruction *phi = *piter;
@@ -1536,7 +1531,7 @@
   {
     llvm::BasicBlock *m_block = b.to_llvm ();
     builder.SetInsertPoint (m_block);
-    for (jit_block::iterator iter = b.begin (); iter != b.end (); ++iter)
+    for (auto iter = b.begin (); iter != b.end (); ++iter)
       visit (*iter);
   }
 
@@ -1695,8 +1690,7 @@
 
     // initialize the worklist to instructions derived from constants
     const std::list<jit_value *>& constants = m_factory.constants ();
-    for (std::list<jit_value *>::const_iterator iter = constants.begin ();
-         iter != constants.end (); ++iter)
+    for (auto iter = constants.begin (); iter != constants.end (); ++iter)
       append_users (*iter);
 
     // the entry block terminator may be a regular branch statement
@@ -1741,7 +1735,7 @@
         if (term->alive (i))
           {
             jit_block *succ = term->successor (i);
-            for (jit_block::iterator iter = succ->begin ();
+            for (auto iter = succ->begin ();
                  iter != succ->end () && isa<jit_phi> (*iter); ++iter)
               push_worklist (*iter);
 
@@ -1761,9 +1755,7 @@
     entry_block ().create_dom_tree ();
 
     // insert phi nodes where needed, this is done on a per variable basis
-    for (variable_map::const_iterator iter = m_vmap.begin ();
-         iter != m_vmap.end ();
-         ++iter)
+    for (auto iter = m_vmap.cbegin (); iter != m_vmap.cend (); ++iter)
       {
         jit_block::df_set visited, added_phi;
         std::list<jit_block *> ssa_worklist;
@@ -1776,8 +1768,7 @@
             jit_block *b = ssa_worklist.front ();
             ssa_worklist.pop_front ();
 
-            for (jit_block::df_iterator diter = b->df_begin ();
-                 diter != b->df_end (); ++diter)
+            for (auto diter = b->df_begin (); diter != b->df_end (); ++diter)
               {
                 jit_block *dblock = *diter;
                 if (! added_phi.count (dblock))
@@ -1807,9 +1798,7 @@
       return;
 
     // replace variables with their current SSA value
-    for (jit_block::iterator iter = ablock.begin ();
-         iter != ablock.end ();
-         ++iter)
+    for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
       {
         jit_instruction *instr = *iter;
         instr->construct_ssa ();
@@ -1821,7 +1810,7 @@
       {
         jit_block *finish = ablock.successor (i);
 
-        for (jit_block::iterator iter = finish->begin ();
+        for (auto  iter = finish->begin ();
              iter != finish->end () && isa<jit_phi> (*iter);)
           {
             jit_phi *phi = static_cast<jit_phi *> (*iter);
@@ -1851,9 +1840,7 @@
   jit_infer::place_releases (void)
   {
     std::set<jit_value *> temporaries;
-    for (jit_block_list::iterator iter = m_blocks.begin ();
-         iter != m_blocks.end ();
-         ++iter)
+    for (auto iter = m_blocks.begin (); iter != m_blocks.end (); ++iter)
       {
         jit_block& ablock = **iter;
         if (ablock.id () != jit_block::NO_ID)
@@ -1883,7 +1870,7 @@
         jit_block *b = *biter;
         if (b->alive ())
           {
-            for (jit_block::iterator iter = b->begin ();
+            for (auto iter = b->begin ();
                  iter != b->end () && isa<jit_phi> (*iter);)
               {
                 jit_phi *phi = static_cast<jit_phi *> (*iter);
@@ -1927,7 +1914,7 @@
   void
   jit_infer::release_dead_phi (jit_block& ablock)
   {
-    jit_block::iterator iter = ablock.begin ();
+    auto iter = ablock.begin ();
     while (iter != ablock.end () && isa<jit_phi> (*iter))
       {
         jit_phi *phi = static_cast<jit_phi *> (*iter);
@@ -1963,9 +1950,7 @@
   void
   jit_infer::release_temp (jit_block& ablock, std::set<jit_value *>& temp)
   {
-    for (jit_block::iterator iter = ablock.begin ();
-         iter != ablock.end ();
-         ++iter)
+    for (auto iter = ablock.begin (); iter != ablock.end (); ++iter)
       {
         jit_instruction *instr = *iter;
 
@@ -2005,9 +1990,7 @@
     jit_block *split = ablock.maybe_split (m_factory, m_blocks,
                                            final_block ());
     jit_terminator *term = split->terminator ();
-    for (std::set<jit_value *>::const_iterator iter = temp.begin ();
-         iter != temp.end ();
-         ++iter)
+    for (auto iter = temp.cbegin (); iter != temp.cend (); ++iter)
       {
         jit_value *value = *iter;
         jit_call *release
@@ -2020,12 +2003,10 @@
   void
   jit_infer::simplify_phi (void)
   {
-    for (jit_block_list::iterator biter = m_blocks.begin ();
-         biter != m_blocks.end ();
-         ++biter)
+    for (auto biter = m_blocks.begin (); biter != m_blocks.end (); ++biter)
       {
         jit_block &ablock = **biter;
-        for (jit_block::iterator iter = ablock.begin ();
+        for (auto iter = ablock.begin ();
              iter != ablock.end () && isa<jit_phi> (*iter); ++iter)
           simplify_phi (*static_cast<jit_phi *> (*iter));
       }
@@ -2162,10 +2143,7 @@
     // FIXME: autconf this
 
     if (e == nullptr)
-      {
-        std::cerr << "Failed to create JIT engine" << std::endl;
-        std::cerr << err << std::endl;
-      }
+      error ("failed to create JIT engine: %s", err.c_str ());
 
     return jit::EngineOwner (e);
   }
@@ -2323,8 +2301,7 @@
   bool
   tree_jit::enabled (void)
   {
-    octave::bp_table& bptab
-      = octave::__get_bp_table__ ("tree_jit::enabled");
+    bp_table& bptab = __get_bp_table__ ("tree_jit::enabled");
 
     // Ideally, we should only disable JIT if there is a breakpoint in the code
     // we are about to run. However, we can't figure this out in O(1) time, so
@@ -2523,14 +2500,14 @@
           {
             jit_block_list& blocks = infer.get_blocks ();
             blocks.label ();
-            std::cout << "-------------------- Compiling function ";
-            std::cout << "--------------------\n";
-
-            tree_print_code tpc (std::cout);
+            octave_stdout << "-------------------- Compiling function ";
+            octave_stdout << "--------------------\n";
+
+            tree_print_code tpc (octave_stdout);
             tpc.visit_octave_user_function_header (fcn);
             tpc.visit_statement_list (*fcn.body ());
             tpc.visit_octave_user_function_trailer (fcn);
-            blocks.print (std::cout, "octave jit ir");
+            blocks.print (octave_stdout, "octave jit ir");
           }
 
         jit_factory& factory = conv.get_factory ();
@@ -2541,9 +2518,9 @@
 
         if (Vdebug_jit)
           {
-            std::cout << "-------------------- raw function ";
-            std::cout << "--------------------\n";
-            std::cout << *raw_fn.to_llvm () << std::endl;
+            octave_stdout << "-------------------- raw function ";
+            octave_stdout << "--------------------\n";
+            octave_stdout << *raw_fn.to_llvm () << std::endl;
             llvm::verifyFunction (*raw_fn.to_llvm ());
           }
 
@@ -2595,9 +2572,9 @@
 
         if (Vdebug_jit)
           {
-            std::cout << "-------------------- optimized and wrapped ";
-            std::cout << "--------------------\n";
-            std::cout << *llvm_function << std::endl;
+            octave_stdout << "-------------------- optimized and wrapped ";
+            octave_stdout << "--------------------\n";
+            octave_stdout << *llvm_function << std::endl;
             llvm::verifyFunction (*llvm_function);
           }
 
@@ -2623,7 +2600,7 @@
         if (Vdebug_jit)
           {
             if (e.known ())
-              std::cout << "jit fail: " << e.what () << std::endl;
+              octave_stdout << "jit fail: " << e.what () << std::endl;
           }
 
         Vjit_failcnt++;
@@ -2776,9 +2753,9 @@
           {
             jit_block_list& blocks = infer.get_blocks ();
             blocks.label ();
-            std::cout << "-------------------- Compiling tree --------------------\n";
-            std::cout << tee.str_print_code () << std::endl;
-            blocks.print (std::cout, "octave jit ir");
+            octave_stdout << "-------------------- Compiling tree --------------------\n";
+            octave_stdout << tee.str_print_code () << std::endl;
+            blocks.print (octave_stdout, "octave jit ir");
           }
 
         jit_factory& factory = conv.get_factory ();
@@ -2797,7 +2774,7 @@
         if (Vdebug_jit)
           {
             if (e.known ())
-              std::cout << "jit fail: " << e.what () << std::endl;
+              octave_stdout << "jit fail: " << e.what () << std::endl;
           }
 
         Vjit_failcnt++;
@@ -2808,8 +2785,8 @@
       {
         if (Vdebug_jit)
           {
-            std::cout << "-------------------- llvm ir --------------------";
-            std::cout << *llvm_function << std::endl;
+            octave_stdout << "-------------------- llvm ir --------------------";
+            octave_stdout << *llvm_function << std::endl;
             llvm::verifyFunction (*llvm_function);
           }
 
@@ -2817,9 +2794,9 @@
 
         if (Vdebug_jit)
           {
-            std::cout << "-------------------- optimized llvm ir "
+            octave_stdout << "-------------------- optimized llvm ir "
                       << "--------------------\n";
-            std::cout << *llvm_function << std::endl;
+            octave_stdout << *llvm_function << std::endl;
           }
 
         finalizeObject ();
--- a/libinterp/parse-tree/pt-jump.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
-
-Copyright (C) 1996-2018 John W. Eaton
-
-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 "pt-jump.h"
-
-class octave_value_list;
-
-namespace octave
-{
-  // Break.
-
-  // Nonzero means we're breaking out of a loop or function body.
-  int tree_break_command::breaking = 0;
-
-  // Continue.
-
-  // Nonzero means we're jumping to the end of a loop.
-  int tree_continue_command::continuing = 0;
-
-  // Return.
-
-  // Nonzero means we're returning from a function.
-  int tree_return_command::returning = 0;
-}
--- a/libinterp/parse-tree/pt-jump.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-jump.h	Thu Dec 20 17:18:56 2018 -0500
@@ -51,8 +51,6 @@
     {
       tw.visit_break_command (*this);
     }
-
-    static int breaking;
   };
 
   // Continue.
@@ -76,8 +74,6 @@
     {
       tw.visit_continue_command (*this);
     }
-
-    static int continuing;
   };
 
   // Return.
@@ -101,8 +97,6 @@
     {
       tw.visit_return_command (*this);
     }
-
-    static int returning;
   };
 }
 
--- a/libinterp/parse-tree/pt-mat.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-mat.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,7 +29,6 @@
 #include "pt-arg-list.h"
 #include "pt-exp.h"
 #include "pt-mat.h"
-#include "pt-tm-const.h"
 #include "ov.h"
 #include "variables.h"
 
@@ -131,230 +130,3 @@
     return new_matrix;
   }
 }
-
-
-/*
-## test concatenation with all zero matrices
-%!assert ([ "" 65*ones(1,10) ], "AAAAAAAAAA")
-%!assert ([ 65*ones(1,10) "" ], "AAAAAAAAAA")
-
-%!test
-%! c = {"foo"; "bar"; "bazoloa"};
-%! assert ([c; "a"; "bc"; "def"], {"foo"; "bar"; "bazoloa"; "a"; "bc"; "def"});
-
-%!assert (class ([int64(1), int64(1)]), "int64")
-%!assert (class ([int64(1), int32(1)]), "int64")
-%!assert (class ([int64(1), int16(1)]), "int64")
-%!assert (class ([int64(1), int8(1)]), "int64")
-%!assert (class ([int64(1), uint64(1)]), "int64")
-%!assert (class ([int64(1), uint32(1)]), "int64")
-%!assert (class ([int64(1), uint16(1)]), "int64")
-%!assert (class ([int64(1), uint8(1)]), "int64")
-%!assert (class ([int64(1), single(1)]), "int64")
-%!assert (class ([int64(1), double(1)]), "int64")
-%!assert (class ([int64(1), cell(1)]), "cell")
-%!assert (class ([int64(1), true]), "int64")
-%!assert (class ([int64(1), "a"]), "char")
-
-%!assert (class ([int32(1), int64(1)]), "int32")
-%!assert (class ([int32(1), int32(1)]), "int32")
-%!assert (class ([int32(1), int16(1)]), "int32")
-%!assert (class ([int32(1), int8(1)]), "int32")
-%!assert (class ([int32(1), uint64(1)]), "int32")
-%!assert (class ([int32(1), uint32(1)]), "int32")
-%!assert (class ([int32(1), uint16(1)]), "int32")
-%!assert (class ([int32(1), uint8(1)]), "int32")
-%!assert (class ([int32(1), single(1)]), "int32")
-%!assert (class ([int32(1), double(1)]), "int32")
-%!assert (class ([int32(1), cell(1)]), "cell")
-%!assert (class ([int32(1), true]), "int32")
-%!assert (class ([int32(1), "a"]), "char")
-
-%!assert (class ([int16(1), int64(1)]), "int16")
-%!assert (class ([int16(1), int32(1)]), "int16")
-%!assert (class ([int16(1), int16(1)]), "int16")
-%!assert (class ([int16(1), int8(1)]), "int16")
-%!assert (class ([int16(1), uint64(1)]), "int16")
-%!assert (class ([int16(1), uint32(1)]), "int16")
-%!assert (class ([int16(1), uint16(1)]), "int16")
-%!assert (class ([int16(1), uint8(1)]), "int16")
-%!assert (class ([int16(1), single(1)]), "int16")
-%!assert (class ([int16(1), double(1)]), "int16")
-%!assert (class ([int16(1), cell(1)]), "cell")
-%!assert (class ([int16(1), true]), "int16")
-%!assert (class ([int16(1), "a"]), "char")
-
-%!assert (class ([int8(1), int64(1)]), "int8")
-%!assert (class ([int8(1), int32(1)]), "int8")
-%!assert (class ([int8(1), int16(1)]), "int8")
-%!assert (class ([int8(1), int8(1)]), "int8")
-%!assert (class ([int8(1), uint64(1)]), "int8")
-%!assert (class ([int8(1), uint32(1)]), "int8")
-%!assert (class ([int8(1), uint16(1)]), "int8")
-%!assert (class ([int8(1), uint8(1)]), "int8")
-%!assert (class ([int8(1), single(1)]), "int8")
-%!assert (class ([int8(1), double(1)]), "int8")
-%!assert (class ([int8(1), cell(1)]), "cell")
-%!assert (class ([int8(1), true]), "int8")
-%!assert (class ([int8(1), "a"]), "char")
-
-%!assert (class ([uint64(1), int64(1)]), "uint64")
-%!assert (class ([uint64(1), int32(1)]), "uint64")
-%!assert (class ([uint64(1), int16(1)]), "uint64")
-%!assert (class ([uint64(1), int8(1)]), "uint64")
-%!assert (class ([uint64(1), uint64(1)]), "uint64")
-%!assert (class ([uint64(1), uint32(1)]), "uint64")
-%!assert (class ([uint64(1), uint16(1)]), "uint64")
-%!assert (class ([uint64(1), uint8(1)]), "uint64")
-%!assert (class ([uint64(1), single(1)]), "uint64")
-%!assert (class ([uint64(1), double(1)]), "uint64")
-%!assert (class ([uint64(1), cell(1)]), "cell")
-%!assert (class ([uint64(1), true]), "uint64")
-%!assert (class ([uint64(1), "a"]), "char")
-
-%!assert (class ([uint32(1), int64(1)]), "uint32")
-%!assert (class ([uint32(1), int32(1)]), "uint32")
-%!assert (class ([uint32(1), int16(1)]), "uint32")
-%!assert (class ([uint32(1), int8(1)]), "uint32")
-%!assert (class ([uint32(1), uint64(1)]), "uint32")
-%!assert (class ([uint32(1), uint32(1)]), "uint32")
-%!assert (class ([uint32(1), uint16(1)]), "uint32")
-%!assert (class ([uint32(1), uint8(1)]), "uint32")
-%!assert (class ([uint32(1), single(1)]), "uint32")
-%!assert (class ([uint32(1), double(1)]), "uint32")
-%!assert (class ([uint32(1), cell(1)]), "cell")
-%!assert (class ([uint32(1), true]), "uint32")
-%!assert (class ([uint32(1), "a"]), "char")
-
-%!assert (class ([uint16(1), int64(1)]), "uint16")
-%!assert (class ([uint16(1), int32(1)]), "uint16")
-%!assert (class ([uint16(1), int16(1)]), "uint16")
-%!assert (class ([uint16(1), int8(1)]), "uint16")
-%!assert (class ([uint16(1), uint64(1)]), "uint16")
-%!assert (class ([uint16(1), uint32(1)]), "uint16")
-%!assert (class ([uint16(1), uint16(1)]), "uint16")
-%!assert (class ([uint16(1), uint8(1)]), "uint16")
-%!assert (class ([uint16(1), single(1)]), "uint16")
-%!assert (class ([uint16(1), double(1)]), "uint16")
-%!assert (class ([uint16(1), cell(1)]), "cell")
-%!assert (class ([uint16(1), true]), "uint16")
-%!assert (class ([uint16(1), "a"]), "char")
-
-%!assert (class ([uint8(1), int64(1)]), "uint8")
-%!assert (class ([uint8(1), int32(1)]), "uint8")
-%!assert (class ([uint8(1), int16(1)]), "uint8")
-%!assert (class ([uint8(1), int8(1)]), "uint8")
-%!assert (class ([uint8(1), uint64(1)]), "uint8")
-%!assert (class ([uint8(1), uint32(1)]), "uint8")
-%!assert (class ([uint8(1), uint16(1)]), "uint8")
-%!assert (class ([uint8(1), uint8(1)]), "uint8")
-%!assert (class ([uint8(1), single(1)]), "uint8")
-%!assert (class ([uint8(1), double(1)]), "uint8")
-%!assert (class ([uint8(1), cell(1)]), "cell")
-%!assert (class ([uint8(1), true]), "uint8")
-%!assert (class ([uint8(1), "a"]), "char")
-
-%!assert (class ([single(1), int64(1)]), "int64")
-%!assert (class ([single(1), int32(1)]), "int32")
-%!assert (class ([single(1), int16(1)]), "int16")
-%!assert (class ([single(1), int8(1)]), "int8")
-%!assert (class ([single(1), uint64(1)]), "uint64")
-%!assert (class ([single(1), uint32(1)]), "uint32")
-%!assert (class ([single(1), uint16(1)]), "uint16")
-%!assert (class ([single(1), uint8(1)]), "uint8")
-%!assert (class ([single(1), single(1)]), "single")
-%!assert (class ([single(1), double(1)]), "single")
-%!assert (class ([single(1), cell(1)]), "cell")
-%!assert (class ([single(1), true]), "single")
-%!assert (class ([single(1), "a"]), "char")
-
-%!assert (class ([double(1), int64(1)]), "int64")
-%!assert (class ([double(1), int32(1)]), "int32")
-%!assert (class ([double(1), int16(1)]), "int16")
-%!assert (class ([double(1), int8(1)]), "int8")
-%!assert (class ([double(1), uint64(1)]), "uint64")
-%!assert (class ([double(1), uint32(1)]), "uint32")
-%!assert (class ([double(1), uint16(1)]), "uint16")
-%!assert (class ([double(1), uint8(1)]), "uint8")
-%!assert (class ([double(1), single(1)]), "single")
-%!assert (class ([double(1), double(1)]), "double")
-%!assert (class ([double(1), cell(1)]), "cell")
-%!assert (class ([double(1), true]), "double")
-%!assert (class ([double(1), "a"]), "char")
-
-%!assert (class ([cell(1), int64(1)]), "cell")
-%!assert (class ([cell(1), int32(1)]), "cell")
-%!assert (class ([cell(1), int16(1)]), "cell")
-%!assert (class ([cell(1), int8(1)]), "cell")
-%!assert (class ([cell(1), uint64(1)]), "cell")
-%!assert (class ([cell(1), uint32(1)]), "cell")
-%!assert (class ([cell(1), uint16(1)]), "cell")
-%!assert (class ([cell(1), uint8(1)]), "cell")
-%!assert (class ([cell(1), single(1)]), "cell")
-%!assert (class ([cell(1), double(1)]), "cell")
-%!assert (class ([cell(1), cell(1)]), "cell")
-%!assert (class ([cell(1), true]), "cell")
-%!assert (class ([cell(1), "a"]), "cell")
-
-%!assert (class ([true, int64(1)]), "int64")
-%!assert (class ([true, int32(1)]), "int32")
-%!assert (class ([true, int16(1)]), "int16")
-%!assert (class ([true, int8(1)]), "int8")
-%!assert (class ([true, uint64(1)]), "uint64")
-%!assert (class ([true, uint32(1)]), "uint32")
-%!assert (class ([true, uint16(1)]), "uint16")
-%!assert (class ([true, uint8(1)]), "uint8")
-%!assert (class ([true, single(1)]), "single")
-%!assert (class ([true, double(1)]), "double")
-%!assert (class ([true, cell(1)]), "cell")
-%!assert (class ([true, true]), "logical")
-%!assert (class ([true, "a"]), "char")
-
-%!assert (class (["a", int64(1)]), "char")
-%!assert (class (["a", int32(1)]), "char")
-%!assert (class (["a", int16(1)]), "char")
-%!assert (class (["a", int8(1)]), "char")
-%!assert (class (["a", int64(1)]), "char")
-%!assert (class (["a", int32(1)]), "char")
-%!assert (class (["a", int16(1)]), "char")
-%!assert (class (["a", int8(1)]), "char")
-%!assert (class (["a", single(1)]), "char")
-%!assert (class (["a", double(1)]), "char")
-%!assert (class (["a", cell(1)]), "cell")
-%!assert (class (["a", true]), "char")
-%!assert (class (["a", "a"]), "char")
-
-%!assert (class ([cell(1), struct("foo", "bar")]), "cell")
-%!error [struct("foo", "bar"), cell(1)]
-
-%!test <*39041> assert (class ([cell(0), struct()]), "cell")
-%!test <51086> assert (class ([struct(), cell(0)]), "struct")
-
-%!assert ([,1], 1)
-%!assert ([1,], 1)
-%!assert ([,1,], 1)
-%!assert ([,1,;;], 1)
-%!assert ([,1,;,;], 1)
-
-%!assert ([1,1], ones (1, 2))
-%!assert ([,1,1], ones (1, 2))
-%!assert ([1,1,], ones (1, 2))
-%!assert ([,1,1,], ones (1, 2))
-%!assert ([,1,1,;;], ones (1, 2))
-%!assert ([,1,1,;,;], ones (1, 2))
-%!assert ([,;,1,1], ones (1, 2))
-
-%!assert ([1;1], ones (2, 1))
-%!assert ([1,;1], ones (2, 1))
-%!assert ([1,;,;1], ones (2, 1))
-
-%!error eval ("[,,]")
-%!error eval ("[,,;,]")
-%!error eval ("[,;,,;,]")
-
-%!assert (isnull ([,]))
-%!assert (isnull ([;]))
-%!assert (isnull ([;;]))
-%!assert (isnull ([;,;]))
-%!assert (isnull ([,;,;,]))
-*/
--- a/libinterp/parse-tree/pt-misc.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-misc.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -35,7 +35,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
@@ -96,7 +96,7 @@
   {
     while (! empty ())
       {
-        iterator p = begin ();
+        auto p = begin ();
         delete *p;
         erase (p);
       }
--- a/libinterp/parse-tree/pt-pr-code.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-pr-code.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,8 +26,6 @@
 
 #include <cctype>
 
-#include <iostream>
-
 #include "comment-list.h"
 #include "error.h"
 #include "ov-usr-fcn.h"
@@ -60,7 +58,7 @@
   void
   tree_print_code::visit_argument_list (tree_argument_list& lst)
   {
-    tree_argument_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -163,7 +161,7 @@
   void
   tree_print_code::visit_decl_init_list (tree_decl_init_list& lst)
   {
-    tree_decl_init_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -393,14 +391,6 @@
 
         param_list->accept (*this);
 
-        if (takes_varargs)
-          {
-            if (len > 0)
-              m_os << ", ";
-
-            m_os << "varargin";
-          }
-
         if (len > 0 || takes_varargs)
           {
             m_nesting.pop ();
@@ -495,7 +485,7 @@
   void
   tree_print_code::visit_if_command_list (tree_if_command_list& lst)
   {
-    tree_if_command_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     bool first_elt = true;
 
@@ -542,8 +532,8 @@
 
     int n = type_tags.length ();
 
-    std::list<tree_argument_list *>::iterator p_arg_lists = arg_lists.begin ();
-    std::list<string_vector>::iterator p_arg_names = arg_names.begin ();
+    auto p_arg_lists = arg_lists.begin ();
+    auto p_arg_names = arg_names.begin ();
 
     for (int i = 0; i < n; i++)
       {
@@ -616,7 +606,7 @@
     m_os << '[';
     m_nesting.push ('[');
 
-    tree_matrix::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -647,7 +637,7 @@
     m_os << '{';
     m_nesting.push ('{');
 
-    tree_cell::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -756,7 +746,7 @@
   void
   tree_print_code::visit_parameter_list (tree_parameter_list& lst)
   {
-    tree_parameter_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -766,10 +756,13 @@
           {
             elt->accept (*this);
 
-            if (p != lst.end ())
+            if (p != lst.end () || lst.takes_varargs ())
               m_os << ", ";
           }
       }
+
+    if (lst.takes_varargs ())
+      m_os << "varargin";
   }
 
   void
@@ -817,7 +810,7 @@
   void
   tree_print_code::visit_return_list (tree_return_list& lst)
   {
-    tree_return_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -933,7 +926,7 @@
   void
   tree_print_code::visit_switch_case_list (tree_switch_case_list& lst)
   {
-    tree_switch_case_list::iterator p = lst.begin ();
+    auto p = lst.begin ();
 
     while (p != lst.end ())
       {
@@ -1282,7 +1275,7 @@
   {
     if (comment_list)
       {
-        comment_list::iterator p = comment_list->begin ();
+        auto p = comment_list->begin ();
 
         while (p != comment_list->end ())
           {
--- a/libinterp/parse-tree/pt-select.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-select.h	Thu Dec 20 17:18:56 2018 -0500
@@ -104,7 +104,7 @@
     {
       while (! empty ())
         {
-          iterator p = begin ();
+          auto p = begin ();
           delete *p;
           erase (p);
         }
@@ -229,7 +229,7 @@
     {
       while (! empty ())
         {
-          iterator p = begin ();
+          auto p = begin ();
           delete *p;
           erase (p);
         }
--- a/libinterp/parse-tree/pt-stmt.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-stmt.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -37,6 +37,7 @@
 #include "pager.h"
 #include "pt-bp.h"
 #include "pt-cmd.h"
+#include "pt-eval.h"
 #include "pt-id.h"
 #include "pt-idx.h"
 #include "pt-jump.h"
@@ -89,10 +90,17 @@
   }
 
   bool
-  tree_statement::is_breakpoint (bool check_active) const
+  tree_statement::is_breakpoint (void) const
   {
-    return m_command ? m_command->is_breakpoint (check_active)
-      : (m_expression ? m_expression->is_breakpoint (check_active) : false);
+    return m_command ? m_command->is_breakpoint ()
+      : (m_expression ? m_expression->is_breakpoint () : false);
+  }
+
+  bool
+  tree_statement::is_active_breakpoint (tree_evaluator& tw) const
+  {
+    return m_command ? m_command->is_active_breakpoint (tw)
+      : (m_expression ? m_expression->is_active_breakpoint (tw) : false);
   }
 
   std::string
--- a/libinterp/parse-tree/pt-stmt.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-stmt.h	Thu Dec 20 17:18:56 2018 -0500
@@ -38,6 +38,7 @@
 {
   class comment_list;
   class tree_command;
+  class tree_evaluator;
   class tree_expression;
 
   // A statement is either a command to execute or an expression to
@@ -77,7 +78,10 @@
 
     void delete_breakpoint (void);
 
-    bool is_breakpoint (bool check_valid = false) const;
+    bool is_breakpoint (void) const;
+
+    bool is_active_breakpoint (tree_evaluator& tw) const;
+
     std::string bp_cond () const;
 
     int line (void) const;
@@ -153,7 +157,7 @@
     {
       while (! empty ())
         {
-          iterator p = begin ();
+          auto p = begin ();
           delete *p;
           erase (p);
         }
--- a/libinterp/parse-tree/pt-tm-const.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-tm-const.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,8 +24,6 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
-
 #include "oct-locbuf.h"
 #include "quit.h"
 
@@ -59,20 +57,61 @@
 
 namespace octave
 {
-  void
-  tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val,
-                                                   bool& first_elem)
+  void tm_row_const::cellify (void)
   {
-    std::string this_elt_class_nm = val.isobject () ? "class"
-                                                    : val.class_name ();
+    bool elt_changed = false;
+
+    for (auto& elt : m_values)
+      {
+        octave_quit ();
+
+        if (! elt.iscell ())
+          {
+            elt_changed = true;
+
+            if (elt.isempty ())
+              elt = Cell ();
+            else
+              elt = Cell (elt);
+          }
+      }
+
+    if (! elt_changed)
+      return;
+
+    bool first_elem = true;
 
-    m_class_nm = get_concat_class (m_class_nm, this_elt_class_nm);
+    for (const auto& val : m_values)
+      {
+        octave_quit ();
+
+        dim_vector this_elt_dv = val.dims ();
+
+        if (! this_elt_dv.zero_by_zero ())
+          {
+            if (first_elem)
+              {
+                first_elem = false;
+                m_dv = this_elt_dv;
+              }
+            else if (! m_dv.hvcat (this_elt_dv, 1))
+              eval_error ("horizontal dimensions mismatch", m_dv, this_elt_dv);
+          }
+      }
+  }
+
+  void tm_row_const::init_element (const octave_value& val, bool& first_elem)
+  {
+    std::string this_elt_class_name
+      = val.isobject () ? "class" : val.class_name ();
+
+    m_class_name = get_concat_class (m_class_name, this_elt_class_name);
 
     dim_vector this_elt_dv = val.dims ();
 
     if (! this_elt_dv.zero_by_zero ())
       {
-        m_all_mt = false;
+        m_all_empty = false;
 
         if (first_elem)
           {
@@ -85,25 +124,25 @@
     else if (val.iscell ())
       first_elem = false;
 
-    append (val);
+    m_values.push_back (val);
 
-    if (m_all_str && ! val.is_string ())
-      m_all_str = false;
+    if (m_all_strings && ! val.is_string ())
+      m_all_strings = false;
 
-    if (m_all_sq_str && ! val.is_sq_string ())
-      m_all_sq_str = false;
+    if (m_all_sq_strings && ! val.is_sq_string ())
+      m_all_sq_strings = false;
 
-    if (m_all_dq_str && ! val.is_dq_string ())
-      m_all_dq_str = false;
+    if (m_all_dq_strings && ! val.is_dq_string ())
+      m_all_dq_strings = false;
 
-    if (! m_some_str && val.is_string ())
-      m_some_str = true;
+    if (! m_some_strings && val.is_string ())
+      m_some_strings = true;
 
     if (m_all_real && ! val.isreal ())
       m_all_real = false;
 
-    if (m_all_cmplx && ! (val.iscomplex () || val.isreal ()))
-      m_all_cmplx = false;
+    if (m_all_complex && ! (val.iscomplex () || val.isreal ()))
+      m_all_complex = false;
 
     if (! m_any_cell && val.iscell ())
       m_any_cell = true;
@@ -118,48 +157,32 @@
     m_all_1x1 = m_all_1x1 && ! val.issparse () && val.numel () == 1;
   }
 
-  void
-  tm_row_const::tm_row_const_rep::init (const tree_argument_list& row,
-                                        tree_evaluator *tw)
+  void tm_row_const::init (const tree_argument_list& row, tree_evaluator& tw)
   {
-    m_all_str = true;
-    m_all_sq_str = true;
-    m_all_dq_str = true;
-    m_all_real = true;
-    m_all_cmplx = true;
-    m_any_cell = false;
-    m_any_sparse = false;
-    m_any_class = false;
-
     bool first_elem = true;
 
-    for (tree_expression* elt : row)
+    for (auto *elt : row)
       {
         octave_quit ();
 
-        octave_value tmp = tw->evaluate (elt);
+        octave_value tmp = tw.evaluate (elt);
 
         if (tmp.is_undefined ())
+          return;
+
+        if (tmp.is_cs_list ())
           {
-            m_ok = true;
-            return;
+            octave_value_list tlst = tmp.list_value ();
+
+            for (octave_idx_type i = 0; i < tlst.length (); i++)
+              {
+                octave_quit ();
+
+                init_element (tlst(i), first_elem);
+              }
           }
         else
-          {
-            if (tmp.is_cs_list ())
-              {
-                octave_value_list tlst = tmp.list_value ();
-
-                for (octave_idx_type i = 0; i < tlst.length (); i++)
-                  {
-                    octave_quit ();
-
-                    do_init_element (tlst(i), first_elem);
-                  }
-              }
-            else
-              do_init_element (tmp, first_elem);
-          }
+          init_element (tmp, first_elem);
       }
 
     if (m_any_cell && ! m_any_class && ! m_first_elem_is_struct)
@@ -167,7 +190,7 @@
 
     first_elem = true;
 
-    for (const octave_value& val : *this)
+    for (const auto& val : m_values)
       {
         octave_quit ();
 
@@ -175,7 +198,7 @@
 
         if (! this_elt_dv.zero_by_zero ())
           {
-            m_all_mt = false;
+            m_all_empty = false;
 
             if (first_elem)
               {
@@ -186,129 +209,152 @@
               eval_error ("horizontal dimensions mismatch", m_dv, this_elt_dv);
           }
       }
-
-    m_ok = true;
   }
 
-  void
-  tm_row_const::tm_row_const_rep::cellify (void)
+  octave_value tm_const::concat (char string_fill_char) const
   {
-    bool elt_changed = false;
+    if (m_tm_rows.empty ())
+      return Matrix ();
 
-    for (auto& elt : *this)
-      {
-        octave_quit ();
+    // Try to speed up the common cases.
+
+    std::string result_type = m_class_name;
 
-        if (! elt.iscell ())
+    if (m_any_class)
+      return class_concat ();
+    else if (result_type == "double")
+      {
+        if (m_any_sparse)
           {
-            elt_changed = true;
-
-            if (elt.isempty ())
-              elt = Cell ();
+            if (m_all_real)
+              return sparse_array_concat<SparseMatrix> ();
             else
-              elt = Cell (elt);
+              return sparse_array_concat<SparseComplexMatrix> ();
+          }
+        else
+          {
+            if (m_all_real)
+              return array_concat<NDArray> ();
+            else
+              return array_concat<ComplexNDArray> ();
           }
       }
-
-    if (elt_changed)
+    else if (result_type == "single")
       {
-        bool first_elem = true;
-
-        for (const octave_value& val : *this)
-          {
-            octave_quit ();
-
-            dim_vector this_elt_dv = val.dims ();
+        if (m_all_real)
+          return array_concat<FloatNDArray> ();
+        else
+          return array_concat<FloatComplexNDArray> ();
+      }
+    else if (result_type == "char")
+      {
+        if (! m_all_strings)
+          warn_implicit_conversion ("Octave:num-to-str",
+                                    "numeric", result_type);
+        else
+          maybe_warn_string_concat (m_all_dq_strings, m_all_sq_strings);
 
-            if (! this_elt_dv.zero_by_zero ())
-              {
-                if (first_elem)
-                  {
-                    first_elem = false;
-                    m_dv = this_elt_dv;
-                  }
-                else if (! m_dv.hvcat (this_elt_dv, 1))
-                  eval_error ("horizontal dimensions mismatch", m_dv, this_elt_dv);
-              }
-          }
+        return char_array_concat (string_fill_char);
+      }
+    else if (result_type == "logical")
+      {
+        if (m_any_sparse)
+          return sparse_array_concat<SparseBoolMatrix> ();
+        else
+          return array_concat<boolNDArray> ();
       }
+    else if (result_type == "int8")
+      return array_concat<int8NDArray> ();
+    else if (result_type == "int16")
+      return array_concat<int16NDArray> ();
+    else if (result_type == "int32")
+      return array_concat<int32NDArray> ();
+    else if (result_type == "int64")
+      return array_concat<int64NDArray> ();
+    else if (result_type == "uint8")
+      return array_concat<uint8NDArray> ();
+    else if (result_type == "uint16")
+      return array_concat<uint16NDArray> ();
+    else if (result_type == "uint32")
+      return array_concat<uint32NDArray> ();
+    else if (result_type == "uint64")
+      return array_concat<uint64NDArray> ();
+    else if (result_type == "cell")
+      return array_concat<Cell> ();
+    else if (result_type == "struct")
+      {
+        if (m_all_1x1)
+          return map_concat<octave_scalar_map> ();
+        else
+          return map_concat<octave_map> ();
+      }
+    else
+      return generic_concat ();
   }
 
-  void
-  tm_const::init (const tree_matrix& tm, tree_evaluator *tw)
+  void tm_const::init (const tree_matrix& tm)
   {
-    m_all_str = true;
-    m_all_sq_str = true;
-    m_all_dq_str = true;
-    m_all_real = true;
-    m_all_cmplx = true;
-    m_any_cell = false;
-    m_any_sparse = false;
-    m_any_class = false;
-    m_all_1x1 = ! tm.empty ();
-
     bool first_elem = true;
     bool first_elem_is_struct = false;
 
     // Just eval and figure out if what we have is complex or all strings.
     // We can't check columns until we know that this is a numeric matrix --
     // collections of strings can have elements of different lengths.
-    for (const tree_argument_list* elt : tm)
+
+    for (const auto *elt : tm)
       {
         octave_quit ();
 
-        tm_row_const tmp (*elt, tw);
+        tm_row_const row (*elt, m_evaluator);
 
         if (first_elem)
           {
-            first_elem_is_struct = tmp.first_elem_struct_p ();
+            first_elem_is_struct = row.first_elem_struct_p ();
 
             first_elem = false;
           }
 
-        if (tmp && ! tmp.empty ())
-          {
-            if (m_all_str && ! tmp.all_strings_p ())
-              m_all_str = false;
+        if (row.empty ())
+          break;
 
-            if (m_all_sq_str && ! tmp.all_sq_strings_p ())
-              m_all_sq_str = false;
+        if (m_all_strings && ! row.all_strings_p ())
+          m_all_strings = false;
+
+        if (m_all_sq_strings && ! row.all_sq_strings_p ())
+          m_all_sq_strings = false;
 
-            if (m_all_dq_str && ! tmp.all_dq_strings_p ())
-              m_all_dq_str = false;
+        if (m_all_dq_strings && ! row.all_dq_strings_p ())
+          m_all_dq_strings = false;
 
-            if (! m_some_str && tmp.some_strings_p ())
-              m_some_str = true;
+        if (! m_some_strings && row.some_strings_p ())
+          m_some_strings = true;
 
-            if (m_all_real && ! tmp.all_real_p ())
-              m_all_real = false;
+        if (m_all_real && ! row.all_real_p ())
+          m_all_real = false;
 
-            if (m_all_cmplx && ! tmp.all_complex_p ())
-              m_all_cmplx = false;
+        if (m_all_complex && ! row.all_complex_p ())
+          m_all_complex = false;
 
-            if (m_all_mt && ! tmp.all_empty_p ())
-              m_all_mt = false;
+        if (m_all_empty && ! row.all_empty_p ())
+          m_all_empty = false;
 
-            if (! m_any_cell && tmp.any_cell_p ())
-              m_any_cell = true;
+        if (! m_any_cell && row.any_cell_p ())
+          m_any_cell = true;
 
-            if (! m_any_sparse && tmp.any_sparse_p ())
-              m_any_sparse = true;
-
-            if (! m_any_class && tmp.any_class_p ())
-              m_any_class = true;
+        if (! m_any_sparse && row.any_sparse_p ())
+          m_any_sparse = true;
 
-            m_all_1x1 = m_all_1x1 && tmp.all_1x1_p ();
+        if (! m_any_class && row.any_class_p ())
+          m_any_class = true;
 
-            append (tmp);
-          }
-        else
-          break;
+        m_all_1x1 = m_all_1x1 && row.all_1x1_p ();
+
+        m_tm_rows.push_back (row);
       }
 
     if (m_any_cell && ! m_any_class && ! first_elem_is_struct)
       {
-        for (auto& elt : *this)
+        for (auto& elt : m_tm_rows)
           {
             octave_quit ();
 
@@ -318,19 +364,19 @@
 
     first_elem = true;
 
-    for (tm_row_const& elt : *this)
+    for (const auto& elt : m_tm_rows)
       {
         octave_quit ();
 
         octave_idx_type this_elt_nr = elt.rows ();
         octave_idx_type this_elt_nc = elt.cols ();
 
-        std::string this_elt_class_nm = elt.class_name ();
-        m_class_nm = get_concat_class (m_class_nm, this_elt_class_nm);
+        std::string this_elt_class_name = elt.class_name ();
+        m_class_name = get_concat_class (m_class_name, this_elt_class_name);
 
         dim_vector this_elt_dv = elt.dims ();
 
-        m_all_mt = false;
+        m_all_empty = false;
 
         if (first_elem)
           {
@@ -338,7 +384,7 @@
 
             m_dv = this_elt_dv;
           }
-        else if (m_all_str && m_dv.ndims () == 2
+        else if (m_all_strings && m_dv.ndims () == 2
                  && this_elt_dv.ndims () == 2)
           {
             // This is Octave's specialty.
@@ -359,33 +405,27 @@
         else if ((! m_any_class) && (! m_dv.hvcat (this_elt_dv, 0)))
           eval_error ("vertical dimensions mismatch", m_dv, this_elt_dv);
       }
-
-    m_ok = true;
   }
 
-  template <>
-  octave_value
-  do_single_type_concat<octave_map> (const dim_vector& dv,
-                                     tm_const& tmp)
+  octave_value tm_const::char_array_concat (char string_fill_char) const
   {
-    octave_map result;
+    char type = (m_all_dq_strings ? '"' : '\'');
 
-    if (tmp.all_1x1_p ())
-      single_type_concat<octave_scalar_map> (result, dv, tmp);
-    else
-      single_type_concat<octave_map> (result, dv, tmp);
+    charNDArray result (m_dv, string_fill_char);
 
-    return result;
+    array_concat_internal<charNDArray> (result);
+
+    return octave_value (result, type);
   }
 
-  octave_value do_class_concat (tm_const& tmc)
+  octave_value tm_const::class_concat (void) const
   {
     octave_value retval;
 
-    octave_value_list rows (tmc.length (), octave_value ());
+    octave_value_list rows (m_tm_rows.size (), octave_value ());
 
     octave_idx_type j = 0;
-    for (tm_row_const& tmrc : tmc)
+    for (const auto& tmrc : m_tm_rows)
       {
         octave_quit ();
 
@@ -396,18 +436,493 @@
             octave_value_list row (tmrc.length (), octave_value ());
 
             octave_idx_type i = 0;
-            for (auto& elt : tmrc)
+            for (const auto& elt : tmrc)
               row(i++) = elt;
 
-            rows(j++) = do_class_concat (row, "horzcat", 1);
+            rows(j++) = ::do_class_concat (row, "horzcat", 1);
           }
       }
 
     if (rows.length () == 1)
       retval = rows(0);
     else
-      retval = do_class_concat (rows, "vertcat", 0);
+      retval = ::do_class_concat (rows, "vertcat", 0);
+
+    return retval;
+  }
+
+  octave_value tm_const::generic_concat (void) const
+  {
+    // The line below might seem crazy, since we take a copy of the
+    // first argument, resize it to be empty and then resize it to be
+    // 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
+    // copy all data.
+    //
+    // We might also start with a empty octave_value using
+    //
+    //    ctmp = octave::type_info::lookup_type
+    //          (tmp.begin() -> begin() -> type_name());
+    //
+    // and then directly resize.  However, for some types there might be
+    // some additional setup needed, and so this should be avoided.
+
+    octave_value ctmp;
+
+    // Find the first non-empty object
+
+    if (m_any_sparse)
+      {
+        // Start with sparse matrix to avoid issues memory issues with
+        // things like [ones(1,4),sprandn(1e8,4,1e-4)]
+
+        if (m_all_real)
+          ctmp = octave_sparse_matrix ().resize (m_dv);
+        else
+          ctmp = octave_sparse_complex_matrix ().resize (m_dv);
+      }
+    else
+      {
+        for (const auto& row : m_tm_rows)
+          {
+            octave_quit ();
+
+            for (const auto& elt : row)
+              {
+                octave_quit ();
+
+                ctmp = elt;
+
+                if (! ctmp.all_zero_dims ())
+                  goto found_non_empty;
+              }
+          }
+
+        ctmp = (*(m_tm_rows.begin () -> begin ()));
+
+      found_non_empty:
+
+        if (! m_all_empty)
+          ctmp = ctmp.resize (dim_vector (0,0)).resize (m_dv);
+      }
+
+    // Now, extract the values from the individual elements and insert
+    // them in the result matrix.
+
+    interpreter& interp = m_evaluator.get_interpreter ();
+
+    type_info& ti = interp.get_type_info ();
+
+    int dv_len = m_dv.ndims ();
+    octave_idx_type ntmp = (dv_len > 1 ? dv_len : 2);
+    Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
+
+    for (const auto& row : m_tm_rows)
+      {
+        octave_quit ();
+
+        for (const auto& elt : row)
+          {
+            octave_quit ();
+
+            if (elt.isempty ())
+              continue;
+
+            ctmp = do_cat_op (ti, ctmp, elt, ra_idx);
+
+            ra_idx (1) += elt.columns ();
+          }
+
+        ra_idx (0) += row.rows ();
+        ra_idx (1) = 0;
+      }
+
+    octave_value retval = ctmp;
+
+    // If some elements are strings, force the result to be a string.
+
+    if (m_some_strings && ! retval.is_string ())
+      retval = retval.convert_to_str ();
 
     return retval;
   }
+
+  // The result is passed as a parameter to this function so that the
+  // char_array_concat function can create the array externally.
+  // Otherwise, we would need a specialization of this function for
+  // character arrays just to handle string_fill_char.
+
+  template <typename TYPE>
+  void tm_const::array_concat_internal (TYPE& result) const
+  {
+    octave_idx_type r = 0;
+    octave_idx_type c = 0;
+
+    for (const auto& row : m_tm_rows)
+      {
+        // Skip empty arrays to allow looser rules.
+        if (row.dims ().any_zero ())
+          continue;
+
+        for (const auto& elt : row)
+          {
+            octave_quit ();
+
+            TYPE ra = octave_value_extract<TYPE> (elt);
+
+            // Skip empty arrays to allow looser rules.
+
+            if (! ra.isempty ())
+              {
+                result.insert (ra, r, c);
+
+                c += ra.columns ();
+              }
+          }
+
+        r += row.rows ();
+        c = 0;
+      }
+  }
+
+  template <typename TYPE>
+  TYPE tm_const::array_concat (void) const
+  {
+    typedef typename TYPE::element_type ELT_T;
+
+    if (m_dv.any_zero ())
+      return TYPE (m_dv);
+
+    if (m_tm_rows.size () == 1)
+      {
+        // If possible, forward the operation to liboctave.
+        // Single row.
+        const tm_row_const& row = m_tm_rows.front ();
+        if (! (equal_types<ELT_T, char>::value
+               || equal_types<ELT_T, octave_value>::value)
+            && row.all_1x1_p ())
+          {
+            // Optimize all scalars case.
+            TYPE result (m_dv);
+            assert (static_cast<size_t> (result.numel ()) == row.length ());
+            octave_idx_type i = 0;
+            for (const auto& elt : row)
+              result(i++) = octave_value_extract<ELT_T> (elt);
+
+            return result;
+          }
+
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (TYPE, array_list, ncols);
+
+        for (const auto& elt : row)
+          {
+            octave_quit ();
+
+            array_list[i++] = octave_value_extract<TYPE> (elt);
+          }
+
+        return TYPE::cat (-2, ncols, array_list);
+      }
+    else
+      {
+        TYPE result (m_dv);
+        array_concat_internal<TYPE> (result);
+        return result;
+      }
+  }
+
+  template <typename TYPE>
+  TYPE tm_const::sparse_array_concat (void) const
+  {
+    if (m_dv.any_zero ())
+      return TYPE (m_dv);
+
+    // Sparse matrices require preallocation for efficient indexing; besides,
+    // only horizontal concatenation can be efficiently handled by indexing.
+    // So we just cat all rows through liboctave, then cat the final column.
+    octave_idx_type nrows = m_tm_rows.size ();
+    octave_idx_type j = 0;
+    OCTAVE_LOCAL_BUFFER (TYPE, sparse_row_list, nrows);
+    for (const auto& row : m_tm_rows)
+      {
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (TYPE, sparse_list, ncols);
+
+        for (auto& elt : row)
+          {
+            octave_quit ();
+
+            sparse_list[i] = octave_value_extract<TYPE> (elt);
+            i++;
+          }
+
+        TYPE stmp = TYPE::cat (-2, ncols, sparse_list);
+        sparse_row_list[j] = stmp;
+        j++;
+      }
+
+    return TYPE::cat (-1, nrows, sparse_row_list);
+  }
+
+  template <typename MAP>
+  octave_map tm_const::map_concat (void) const
+  {
+    if (m_dv.any_zero ())
+      return octave_map (m_dv);
+
+    octave_idx_type nrows = m_tm_rows.size ();
+    octave_idx_type j = 0;
+    OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
+    for (const auto& row : m_tm_rows)
+      {
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
+
+        for (auto& elt : row)
+          {
+            octave_quit ();
+
+            map_list[i] = octave_value_extract<MAP> (elt);
+            i++;
+          }
+
+        octave_map mtmp = octave_map::cat (-2, ncols, map_list);
+        map_row_list[j] = mtmp;
+        j++;
+      }
+
+    return octave_map::cat (-1, nrows, map_row_list);
+  }
 }
+
+/*
+## test concatenation with all zero matrices
+%!assert ([ "" 65*ones(1,10) ], "AAAAAAAAAA")
+%!assert ([ 65*ones(1,10) "" ], "AAAAAAAAAA")
+
+%!test
+%! c = {"foo"; "bar"; "bazoloa"};
+%! assert ([c; "a"; "bc"; "def"], {"foo"; "bar"; "bazoloa"; "a"; "bc"; "def"});
+
+%!assert (class ([int64(1), int64(1)]), "int64")
+%!assert (class ([int64(1), int32(1)]), "int64")
+%!assert (class ([int64(1), int16(1)]), "int64")
+%!assert (class ([int64(1), int8(1)]), "int64")
+%!assert (class ([int64(1), uint64(1)]), "int64")
+%!assert (class ([int64(1), uint32(1)]), "int64")
+%!assert (class ([int64(1), uint16(1)]), "int64")
+%!assert (class ([int64(1), uint8(1)]), "int64")
+%!assert (class ([int64(1), single(1)]), "int64")
+%!assert (class ([int64(1), double(1)]), "int64")
+%!assert (class ([int64(1), cell(1)]), "cell")
+%!assert (class ([int64(1), true]), "int64")
+%!assert (class ([int64(1), "a"]), "char")
+
+%!assert (class ([int32(1), int64(1)]), "int32")
+%!assert (class ([int32(1), int32(1)]), "int32")
+%!assert (class ([int32(1), int16(1)]), "int32")
+%!assert (class ([int32(1), int8(1)]), "int32")
+%!assert (class ([int32(1), uint64(1)]), "int32")
+%!assert (class ([int32(1), uint32(1)]), "int32")
+%!assert (class ([int32(1), uint16(1)]), "int32")
+%!assert (class ([int32(1), uint8(1)]), "int32")
+%!assert (class ([int32(1), single(1)]), "int32")
+%!assert (class ([int32(1), double(1)]), "int32")
+%!assert (class ([int32(1), cell(1)]), "cell")
+%!assert (class ([int32(1), true]), "int32")
+%!assert (class ([int32(1), "a"]), "char")
+
+%!assert (class ([int16(1), int64(1)]), "int16")
+%!assert (class ([int16(1), int32(1)]), "int16")
+%!assert (class ([int16(1), int16(1)]), "int16")
+%!assert (class ([int16(1), int8(1)]), "int16")
+%!assert (class ([int16(1), uint64(1)]), "int16")
+%!assert (class ([int16(1), uint32(1)]), "int16")
+%!assert (class ([int16(1), uint16(1)]), "int16")
+%!assert (class ([int16(1), uint8(1)]), "int16")
+%!assert (class ([int16(1), single(1)]), "int16")
+%!assert (class ([int16(1), double(1)]), "int16")
+%!assert (class ([int16(1), cell(1)]), "cell")
+%!assert (class ([int16(1), true]), "int16")
+%!assert (class ([int16(1), "a"]), "char")
+
+%!assert (class ([int8(1), int64(1)]), "int8")
+%!assert (class ([int8(1), int32(1)]), "int8")
+%!assert (class ([int8(1), int16(1)]), "int8")
+%!assert (class ([int8(1), int8(1)]), "int8")
+%!assert (class ([int8(1), uint64(1)]), "int8")
+%!assert (class ([int8(1), uint32(1)]), "int8")
+%!assert (class ([int8(1), uint16(1)]), "int8")
+%!assert (class ([int8(1), uint8(1)]), "int8")
+%!assert (class ([int8(1), single(1)]), "int8")
+%!assert (class ([int8(1), double(1)]), "int8")
+%!assert (class ([int8(1), cell(1)]), "cell")
+%!assert (class ([int8(1), true]), "int8")
+%!assert (class ([int8(1), "a"]), "char")
+
+%!assert (class ([uint64(1), int64(1)]), "uint64")
+%!assert (class ([uint64(1), int32(1)]), "uint64")
+%!assert (class ([uint64(1), int16(1)]), "uint64")
+%!assert (class ([uint64(1), int8(1)]), "uint64")
+%!assert (class ([uint64(1), uint64(1)]), "uint64")
+%!assert (class ([uint64(1), uint32(1)]), "uint64")
+%!assert (class ([uint64(1), uint16(1)]), "uint64")
+%!assert (class ([uint64(1), uint8(1)]), "uint64")
+%!assert (class ([uint64(1), single(1)]), "uint64")
+%!assert (class ([uint64(1), double(1)]), "uint64")
+%!assert (class ([uint64(1), cell(1)]), "cell")
+%!assert (class ([uint64(1), true]), "uint64")
+%!assert (class ([uint64(1), "a"]), "char")
+
+%!assert (class ([uint32(1), int64(1)]), "uint32")
+%!assert (class ([uint32(1), int32(1)]), "uint32")
+%!assert (class ([uint32(1), int16(1)]), "uint32")
+%!assert (class ([uint32(1), int8(1)]), "uint32")
+%!assert (class ([uint32(1), uint64(1)]), "uint32")
+%!assert (class ([uint32(1), uint32(1)]), "uint32")
+%!assert (class ([uint32(1), uint16(1)]), "uint32")
+%!assert (class ([uint32(1), uint8(1)]), "uint32")
+%!assert (class ([uint32(1), single(1)]), "uint32")
+%!assert (class ([uint32(1), double(1)]), "uint32")
+%!assert (class ([uint32(1), cell(1)]), "cell")
+%!assert (class ([uint32(1), true]), "uint32")
+%!assert (class ([uint32(1), "a"]), "char")
+
+%!assert (class ([uint16(1), int64(1)]), "uint16")
+%!assert (class ([uint16(1), int32(1)]), "uint16")
+%!assert (class ([uint16(1), int16(1)]), "uint16")
+%!assert (class ([uint16(1), int8(1)]), "uint16")
+%!assert (class ([uint16(1), uint64(1)]), "uint16")
+%!assert (class ([uint16(1), uint32(1)]), "uint16")
+%!assert (class ([uint16(1), uint16(1)]), "uint16")
+%!assert (class ([uint16(1), uint8(1)]), "uint16")
+%!assert (class ([uint16(1), single(1)]), "uint16")
+%!assert (class ([uint16(1), double(1)]), "uint16")
+%!assert (class ([uint16(1), cell(1)]), "cell")
+%!assert (class ([uint16(1), true]), "uint16")
+%!assert (class ([uint16(1), "a"]), "char")
+
+%!assert (class ([uint8(1), int64(1)]), "uint8")
+%!assert (class ([uint8(1), int32(1)]), "uint8")
+%!assert (class ([uint8(1), int16(1)]), "uint8")
+%!assert (class ([uint8(1), int8(1)]), "uint8")
+%!assert (class ([uint8(1), uint64(1)]), "uint8")
+%!assert (class ([uint8(1), uint32(1)]), "uint8")
+%!assert (class ([uint8(1), uint16(1)]), "uint8")
+%!assert (class ([uint8(1), uint8(1)]), "uint8")
+%!assert (class ([uint8(1), single(1)]), "uint8")
+%!assert (class ([uint8(1), double(1)]), "uint8")
+%!assert (class ([uint8(1), cell(1)]), "cell")
+%!assert (class ([uint8(1), true]), "uint8")
+%!assert (class ([uint8(1), "a"]), "char")
+
+%!assert (class ([single(1), int64(1)]), "int64")
+%!assert (class ([single(1), int32(1)]), "int32")
+%!assert (class ([single(1), int16(1)]), "int16")
+%!assert (class ([single(1), int8(1)]), "int8")
+%!assert (class ([single(1), uint64(1)]), "uint64")
+%!assert (class ([single(1), uint32(1)]), "uint32")
+%!assert (class ([single(1), uint16(1)]), "uint16")
+%!assert (class ([single(1), uint8(1)]), "uint8")
+%!assert (class ([single(1), single(1)]), "single")
+%!assert (class ([single(1), double(1)]), "single")
+%!assert (class ([single(1), cell(1)]), "cell")
+%!assert (class ([single(1), true]), "single")
+%!assert (class ([single(1), "a"]), "char")
+
+%!assert (class ([double(1), int64(1)]), "int64")
+%!assert (class ([double(1), int32(1)]), "int32")
+%!assert (class ([double(1), int16(1)]), "int16")
+%!assert (class ([double(1), int8(1)]), "int8")
+%!assert (class ([double(1), uint64(1)]), "uint64")
+%!assert (class ([double(1), uint32(1)]), "uint32")
+%!assert (class ([double(1), uint16(1)]), "uint16")
+%!assert (class ([double(1), uint8(1)]), "uint8")
+%!assert (class ([double(1), single(1)]), "single")
+%!assert (class ([double(1), double(1)]), "double")
+%!assert (class ([double(1), cell(1)]), "cell")
+%!assert (class ([double(1), true]), "double")
+%!assert (class ([double(1), "a"]), "char")
+
+%!assert (class ([cell(1), int64(1)]), "cell")
+%!assert (class ([cell(1), int32(1)]), "cell")
+%!assert (class ([cell(1), int16(1)]), "cell")
+%!assert (class ([cell(1), int8(1)]), "cell")
+%!assert (class ([cell(1), uint64(1)]), "cell")
+%!assert (class ([cell(1), uint32(1)]), "cell")
+%!assert (class ([cell(1), uint16(1)]), "cell")
+%!assert (class ([cell(1), uint8(1)]), "cell")
+%!assert (class ([cell(1), single(1)]), "cell")
+%!assert (class ([cell(1), double(1)]), "cell")
+%!assert (class ([cell(1), cell(1)]), "cell")
+%!assert (class ([cell(1), true]), "cell")
+%!assert (class ([cell(1), "a"]), "cell")
+
+%!assert (class ([true, int64(1)]), "int64")
+%!assert (class ([true, int32(1)]), "int32")
+%!assert (class ([true, int16(1)]), "int16")
+%!assert (class ([true, int8(1)]), "int8")
+%!assert (class ([true, uint64(1)]), "uint64")
+%!assert (class ([true, uint32(1)]), "uint32")
+%!assert (class ([true, uint16(1)]), "uint16")
+%!assert (class ([true, uint8(1)]), "uint8")
+%!assert (class ([true, single(1)]), "single")
+%!assert (class ([true, double(1)]), "double")
+%!assert (class ([true, cell(1)]), "cell")
+%!assert (class ([true, true]), "logical")
+%!assert (class ([true, "a"]), "char")
+
+%!assert (class (["a", int64(1)]), "char")
+%!assert (class (["a", int32(1)]), "char")
+%!assert (class (["a", int16(1)]), "char")
+%!assert (class (["a", int8(1)]), "char")
+%!assert (class (["a", int64(1)]), "char")
+%!assert (class (["a", int32(1)]), "char")
+%!assert (class (["a", int16(1)]), "char")
+%!assert (class (["a", int8(1)]), "char")
+%!assert (class (["a", single(1)]), "char")
+%!assert (class (["a", double(1)]), "char")
+%!assert (class (["a", cell(1)]), "cell")
+%!assert (class (["a", true]), "char")
+%!assert (class (["a", "a"]), "char")
+
+%!assert (class ([cell(1), struct("foo", "bar")]), "cell")
+%!error [struct("foo", "bar"), cell(1)]
+
+%!test <*39041> assert (class ([cell(0), struct()]), "cell")
+%!test <51086> assert (class ([struct(), cell(0)]), "struct")
+
+%!assert ([,1], 1)
+%!assert ([1,], 1)
+%!assert ([,1,], 1)
+%!assert ([,1,;;], 1)
+%!assert ([,1,;,;], 1)
+
+%!assert ([1,1], ones (1, 2))
+%!assert ([,1,1], ones (1, 2))
+%!assert ([1,1,], ones (1, 2))
+%!assert ([,1,1,], ones (1, 2))
+%!assert ([,1,1,;;], ones (1, 2))
+%!assert ([,1,1,;,;], ones (1, 2))
+%!assert ([,;,1,1], ones (1, 2))
+
+%!assert ([1;1], ones (2, 1))
+%!assert ([1,;1], ones (2, 1))
+%!assert ([1,;,;1], ones (2, 1))
+
+%!error eval ("[,,]")
+%!error eval ("[,,;,]")
+%!error eval ("[,;,,;,]")
+
+%!assert (isnull ([,]))
+%!assert (isnull ([;]))
+%!assert (isnull ([;;]))
+%!assert (isnull ([;,;]))
+%!assert (isnull ([,;,;,]))
+*/
--- a/libinterp/parse-tree/pt-tm-const.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-tm-const.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,11 +25,12 @@
 
 #include "octave-config.h"
 
+#include <list>
+#include <memory>
 #include <string>
 
 #include "Array.h"
 #include "Sparse.h"
-#include "base-list.h"
 
 #include "data.h"
 #include "dim-vector.h"
@@ -43,395 +44,198 @@
   class tree_evaluator;
   class tree_matrix;
 
-  // General matrices.  This list type is much more work to handle than
-  // constant matrices, but it allows us to construct matrices from
-  // other matrices, variables, and functions.
-
-  // But first, some internal classes that make our job much easier.
-
-  class
-  tm_row_const
-  {
-  private:
-
-    class
-    tm_row_const_rep : public base_list<octave_value>
-    {
-    public:
-
-      tm_row_const_rep (void)
-        : m_count (1), m_dv (0, 0), m_all_str (false),
-          m_all_sq_str (false), m_all_dq_str (false),
-          m_some_str (false), m_all_real (false), m_all_cmplx (false),
-          m_all_mt (true), m_any_cell (false), m_any_sparse (false),
-          m_any_class (false), m_all_1x1 (false),
-          m_first_elem_is_struct (false), m_class_nm (), m_ok (false)
-      { }
-
-      tm_row_const_rep (const tree_argument_list& row, tree_evaluator *tw)
-        : m_count (1), m_dv (0, 0), m_all_str (false), m_all_sq_str (false),
-          m_some_str (false), m_all_real (false), m_all_cmplx (false),
-          m_all_mt (true), m_any_cell (false), m_any_sparse (false),
-          m_any_class (false), m_all_1x1 (! row.empty ()),
-          m_first_elem_is_struct (false), m_class_nm (), m_ok (false)
-      { init (row, tw); }
-
-      ~tm_row_const_rep (void) = default;
-
-      refcount<int> m_count;
-
-      dim_vector m_dv;
-
-      bool m_all_str;
-      bool m_all_sq_str;
-      bool m_all_dq_str;
-      bool m_some_str;
-      bool m_all_real;
-      bool m_all_cmplx;
-      bool m_all_mt;
-      bool m_any_cell;
-      bool m_any_sparse;
-      bool m_any_class;
-      bool m_all_1x1;
-      bool m_first_elem_is_struct;
-
-      std::string m_class_nm;
-
-      bool m_ok;
-
-      void do_init_element (const octave_value&, bool&);
-
-      void init (const tree_argument_list&, tree_evaluator *tw);
-
-      void cellify (void);
-
-    private:
-
-      tm_row_const_rep (const tm_row_const_rep&);
-
-      tm_row_const_rep& operator = (const tm_row_const_rep&);
-
-    };
-
-  public:
-
-    typedef tm_row_const_rep::iterator iterator;
-    typedef tm_row_const_rep::const_iterator const_iterator;
+  // Evaluate tree_matrix objects and convert them to octave_value
+  // arrays (full and sparse numeric, char, cell, struct, class and
+  // anything else that works like an array).  Use a separate class
+  // (tm_const) and pass the evaluator object to it instead of doing
+  // all this work in tree_evaluator::visit_matrix because the job is
+  // fairly large and requires extra data (stored in the tm_info
+  // class) for each row and for the overall array.
 
-    tm_row_const (void)
-      : m_rep (nullptr) { }
-
-    tm_row_const (const tree_argument_list& row, tree_evaluator *tw)
-      : m_rep (new tm_row_const_rep (row, tw)) { }
-
-    tm_row_const (const tm_row_const& x)
-      : m_rep (x.m_rep)
-    {
-      if (m_rep)
-        m_rep->m_count++;
-    }
-
-    tm_row_const& operator = (const tm_row_const& x)
-    {
-      if (this != &x && m_rep != x.m_rep)
-        {
-          if (m_rep && --m_rep->m_count == 0)
-            delete m_rep;
-
-          m_rep = x.m_rep;
-
-          if (m_rep)
-            m_rep->m_count++;
-        }
-
-      return *this;
-    }
-
-    ~tm_row_const (void)
-    {
-      if (m_rep && --m_rep->m_count == 0)
-        delete m_rep;
-    }
-
-    octave_idx_type rows (void) { return m_rep->m_dv(0); }
-    octave_idx_type cols (void) { return m_rep->m_dv(1); }
+  // Evaluate all elements of the array, recording info about each
+  // row, then create summary info for the full array.  Compute the
+  // result type and dimension first before copying values.
 
-    bool empty (void) const { return m_rep->empty (); }
-
-    size_t length (void) const { return m_rep->length (); }
-
-    dim_vector dims (void) { return m_rep->m_dv; }
-
-    bool all_strings_p (void) const { return m_rep->m_all_str; }
-    bool all_sq_strings_p (void) const { return m_rep->m_all_sq_str; }
-    bool all_dq_strings_p (void) const { return m_rep->m_all_dq_str; }
-    bool some_strings_p (void) const { return m_rep->m_some_str; }
-    bool all_real_p (void) const { return m_rep->m_all_real; }
-    bool all_complex_p (void) const { return m_rep->m_all_cmplx; }
-    bool all_empty_p (void) const { return m_rep->m_all_mt; }
-    bool any_cell_p (void) const { return m_rep->m_any_cell; }
-    bool any_sparse_p (void) const { return m_rep->m_any_sparse; }
-    bool any_class_p (void) const { return m_rep->m_any_class; }
-    bool all_1x1_p (void) const { return m_rep->m_all_1x1; }
-    bool first_elem_struct_p (void) const { return m_rep->m_first_elem_is_struct; }
+  // FIXME: Handle overloading of horzcat and vertcat for for built-in
+  // types.
 
-    std::string class_name (void) const { return m_rep->m_class_nm; }
-
-    void cellify (void) { m_rep->cellify (); }
-
-    operator bool () const { return (m_rep && m_rep->m_ok); }
-
-    iterator begin (void) { return m_rep->begin (); }
-    const_iterator begin (void) const { return m_rep->begin (); }
+  // Summary info about the current row or matrix.
 
-    iterator end (void) { return m_rep->end (); }
-    const_iterator end (void) const { return m_rep->end (); }
-
-  private:
-
-    tm_row_const_rep *m_rep;
-  };
-
-  class
-  tm_const : public base_list<tm_row_const>
+  class tm_info
   {
   public:
 
-    tm_const (const tree_matrix& tm, tree_evaluator *tw = nullptr)
-      : m_dv (0, 0), m_all_str (false), m_all_sq_str (false),
-        m_all_dq_str (false),
-        m_some_str (false), m_all_real (false), m_all_cmplx (false),
-        m_all_mt (true), m_any_cell (false), m_any_sparse (false),
-        m_any_class (false), m_class_nm (), m_ok (false)
-    { init (tm, tw); }
-
-    ~tm_const (void) = default;
-
-    octave_idx_type rows (void) const { return m_dv.elem (0); }
-    octave_idx_type cols (void) const { return m_dv.elem (1); }
+    tm_info (bool obj_is_empty)
+      : m_dv (0, 0), m_all_strings (true), m_all_sq_strings (true),
+        m_all_dq_strings (true), m_some_strings (false),
+        m_all_real (true), m_all_complex (true), m_all_empty (true),
+        m_any_cell (false), m_any_sparse (false),
+        m_any_class (false), m_all_1x1 (! obj_is_empty),
+        m_first_elem_is_struct (false), m_class_name ()
+    { }
 
     dim_vector dims (void) const { return m_dv; }
 
-    bool all_strings_p (void) const { return m_all_str; }
-    bool all_sq_strings_p (void) const { return m_all_sq_str; }
-    bool all_dq_strings_p (void) const { return m_all_dq_str; }
-    bool some_strings_p (void) const { return m_some_str; }
+    octave_idx_type rows (void) const { return m_dv(0); }
+    octave_idx_type cols (void) const { return m_dv(1); }
+
+    bool all_strings_p (void) const { return m_all_strings; }
+    bool all_sq_strings_p (void) const { return m_all_sq_strings; }
+    bool all_dq_strings_p (void) const { return m_all_dq_strings; }
+    bool some_strings_p (void) const { return m_some_strings; }
     bool all_real_p (void) const { return m_all_real; }
-    bool all_complex_p (void) const { return m_all_cmplx; }
-    bool all_empty_p (void) const { return m_all_mt; }
+    bool all_complex_p (void) const { return m_all_complex; }
+    bool all_empty_p (void) const { return m_all_empty; }
     bool any_cell_p (void) const { return m_any_cell; }
     bool any_sparse_p (void) const { return m_any_sparse; }
     bool any_class_p (void) const { return m_any_class; }
     bool all_1x1_p (void) const { return m_all_1x1; }
+    bool first_elem_struct_p (void) const { return m_first_elem_is_struct; }
 
-    std::string class_name (void) const { return m_class_nm; }
+    std::string class_name (void) const { return m_class_name; }
+
+  protected:
+
+    // Size of this row or matrix after evaluation.
+    dim_vector m_dv;
+
+    // Are all elements character strings?
+    bool m_all_strings;
+
+    // Are all elements double-quoted character strings?
+    bool m_all_sq_strings;
+
+    // Are all elements single-quoted character strings?
+    bool m_all_dq_strings;
+
+    // Are any elements character strings?
+    bool m_some_strings;
+
+    // Are all elements real valued?
+    bool m_all_real;
+
+    // Are all elements complex valued?
+    bool m_all_complex;
+
+    // Are all elements empty?
+    bool m_all_empty;
+
+    // Are any elements cells?
+    bool m_any_cell;
+
+    // Are any elements sparse arrays?
+    bool m_any_sparse;
+
+    // Are any elements sparse class objects?
+    bool m_any_class;
+
+    // Do all elements have dimensions 1x1?
+    bool m_all_1x1;
 
-    operator bool () const { return m_ok; }
+    // Is the first element a struct?
+    bool m_first_elem_is_struct;
+
+    // Class name of result.
+    std::string m_class_name;
+  };
+
+  class tm_row_const : public tm_info
+  {
+  public:
+
+    typedef std::list<octave_value>::iterator iterator;
+    typedef std::list<octave_value>::const_iterator const_iterator;
+
+    tm_row_const (void) = delete;
+
+    tm_row_const (const tree_argument_list& row, tree_evaluator& tw)
+      : tm_info (row.empty ()), m_values ()
+    {
+      init (row, tw);
+    }
+
+    tm_row_const (const tm_row_const&) = default;
+
+    tm_row_const& operator = (const tm_row_const&) = delete;
+
+    ~tm_row_const (void) = default;
+
+    iterator begin (void) { return m_values.begin (); }
+    const_iterator begin (void) const { return m_values.begin (); }
+
+    iterator end (void) { return m_values.end (); }
+    const_iterator end (void) const { return m_values.end (); }
+
+    bool empty (void) const { return m_values.empty (); }
+
+    size_t length (void) const { return m_values.size (); }
+
+    void cellify (void);
 
   private:
 
-    dim_vector m_dv;
+    std::list<octave_value> m_values;
 
-    bool m_all_str;
-    bool m_all_sq_str;
-    bool m_all_dq_str;
-    bool m_some_str;
-    bool m_all_real;
-    bool m_all_cmplx;
-    bool m_all_mt;
-    bool m_any_cell;
-    bool m_any_sparse;
-    bool m_any_class;
-    bool m_all_1x1;
+    void init_element (const octave_value&, bool&);
 
-    std::string m_class_nm;
-
-    bool m_ok;
-
-    tm_const (void);
-
-    tm_const (const tm_const&);
-
-    tm_const& operator = (const tm_const&);
-
-    void init (const tree_matrix& tm, tree_evaluator *tw);
+    void init (const tree_argument_list&, tree_evaluator& tw);
   };
 
-  template <typename TYPE, typename T>
-  void
-  single_type_concat (Array<T>& result, tm_const& tmp)
-  {
-    octave_idx_type r = 0;
-    octave_idx_type c = 0;
-
-    for (tm_row_const& row : tmp)
-      {
-        // Skip empty arrays to allow looser rules.
-        if (row.dims ().any_zero ())
-          continue;
-
-        for (auto& elt : row)
-          {
-            octave_quit ();
-
-            TYPE ra = octave_value_extract<TYPE> (elt);
-
-            // Skip empty arrays to allow looser rules.
-
-            if (! ra.isempty ())
-              {
-                result.insert (ra, r, c);
-
-                c += ra.columns ();
-              }
-          }
-
-        r += row.rows ();
-        c = 0;
-      }
-  }
-
-  template <typename TYPE, typename T>
-  void
-  single_type_concat (Array<T>& result, const dim_vector& dv,
-                      tm_const& tmp)
-  {
-    if (dv.any_zero ())
-      {
-        result = Array<T> (dv);
-        return;
-      }
-
-    if (tmp.length () == 1)
-      {
-        // If possible, forward the operation to liboctave.
-        // Single row.
-        tm_row_const& row = tmp.front ();
-        if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value)
-            && row.all_1x1_p ())
-          {
-            // Optimize all scalars case.
-            result.clear (dv);
-            assert (static_cast<size_t> (result.numel ()) == row.length ());
-            octave_idx_type i = 0;
-            for (const auto& elt : row)
-              result(i++) = octave_value_extract<T> (elt);
-
-            return;
-          }
-
-        octave_idx_type ncols = row.length ();
-        octave_idx_type i = 0;
-        OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
-
-        for (const auto& elt : row)
-          {
-            octave_quit ();
-
-            array_list[i++] = octave_value_extract<TYPE> (elt);
-          }
-
-        result = Array<T>::cat (-2, ncols, array_list);
-      }
-    else
-      {
-        result = Array<T> (dv);
-        single_type_concat<TYPE> (result, tmp);
-      }
-  }
-
-  template <typename TYPE, typename T>
-  void
-  single_type_concat (Sparse<T>& result, const dim_vector& dv,
-                      tm_const& tmp)
+  class tm_const : public tm_info
   {
-    if (dv.any_zero ())
-      {
-        result = Sparse<T> (dv);
-        return;
-      }
+  public:
+
+    typedef std::list<tm_row_const>::iterator iterator;
+    typedef std::list<tm_row_const>::const_iterator const_iterator;
+
+    tm_const (void) = delete;
+
+    tm_const (const tree_matrix& tm, tree_evaluator& tw)
+      : tm_info (tm.empty ()), m_evaluator (tw), m_tm_rows ()
+    {
+      init (tm);
+    }
 
-    // Sparse matrices require preallocation for efficient indexing; besides,
-    // only horizontal concatenation can be efficiently handled by indexing.
-    // So we just cat all rows through liboctave, then cat the final column.
-    octave_idx_type nrows = tmp.length ();
-    octave_idx_type j = 0;
-    OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows);
-    for (tm_row_const& row : tmp)
-      {
-        octave_idx_type ncols = row.length ();
-        octave_idx_type i = 0;
-        OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols);
+    // No copying!
+
+    tm_const (const tm_const&) = delete;
+
+    tm_const& operator = (const tm_const&) = delete;
 
-        for (auto& elt : row)
-          {
-            octave_quit ();
+    ~tm_const (void) = default;
 
-            sparse_list[i] = octave_value_extract<TYPE> (elt);
-            i++;
-          }
+    octave_value concat (char string_fill_char) const;
 
-        Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list);
-        sparse_row_list[j] = stmp;
-        j++;
-      }
+  private:
 
-    result = Sparse<T>::cat (-1, nrows, sparse_row_list);
-  }
+    tree_evaluator& m_evaluator;
 
-  template <typename MAP>
-  void
-  single_type_concat (octave_map& result, const dim_vector& dv,
-                      tm_const& tmp)
-  {
-    if (dv.any_zero ())
-      {
-        result = octave_map (dv);
-        return;
-      }
+    // The list of lists of octave_value objects that contain the
+    // values of elements in each row of the tree_matrix object we are
+    // evaluating.
+
+    std::list<tm_row_const> m_tm_rows;
 
-    octave_idx_type nrows = tmp.length ();
-    octave_idx_type j = 0;
-    OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
-    for (tm_row_const& row : tmp)
-      {
-        octave_idx_type ncols = row.length ();
-        octave_idx_type i = 0;
-        OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
+    void init (const tree_matrix& tm);
 
-        for (auto& elt : row)
-          {
-            octave_quit ();
+    octave_value char_array_concat (char string_fill_char) const;
+
+    octave_value class_concat (void) const;
 
-            map_list[i] = octave_value_extract<MAP> (elt);
-            i++;
-          }
+    octave_value generic_concat (void) const;
 
-        octave_map mtmp = octave_map::cat (-2, ncols, map_list);
-        map_row_list[j] = mtmp;
-        j++;
-      }
-
-    result = octave_map::cat (-1, nrows, map_row_list);
-  }
+    template <typename TYPE>
+    void array_concat_internal (TYPE& result) const;
 
-  template <typename TYPE>
-  octave_value
-  do_single_type_concat (const dim_vector& dv, tm_const& tmp)
-  {
-    TYPE result;
-
-    single_type_concat<TYPE> (result, dv, tmp);
+    template <typename TYPE>
+    TYPE array_concat (void) const;
 
-    return result;
-  }
+    template <typename TYPE>
+    TYPE sparse_array_concat (void) const;
 
-  template <>
-  octave_value
-  do_single_type_concat<octave_map> (const dim_vector& dv,
-                                     tm_const& tmp);
-
-  extern octave_value do_class_concat (tm_const& tmc);
+    template <typename MAP>
+    octave_map map_concat (void) const;
+  };
 }
 
 #endif
--- a/libinterp/parse-tree/pt-unop.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt-unop.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,6 +30,7 @@
 class octave_value;
 class octave_value_list;
 
+#include "ov.h"
 #include "pt-exp.h"
 #include "pt-walk.h"
 
--- a/libinterp/parse-tree/pt.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,12 +24,12 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
 #include <sstream>
 #include <string>
 
 #include "ov-fcn.h"
 #include "pt.h"
+#include "pt-eval.h"
 #include "pt-pr-code.h"
 #include "unwind-prot.h"
 
@@ -52,11 +52,10 @@
     return retval;
   }
 
-  // function from libinterp/parse-tree/oct-parse.cc, not listed in oct-parse.h
-  octave_value_list eval_string (const std::string&, bool, int&, int);
   // Is the current breakpoint condition met?
+
   bool
-  tree::meets_bp_condition () const
+  tree::meets_bp_condition (tree_evaluator& tw) const
   {
     bool retval;
     if (m_bp_cond == nullptr)
@@ -80,7 +79,7 @@
         try
           {
             octave_value_list val
-              = eval_string (*m_bp_cond, 1, parse_status, 1);
+              = tw.eval_string (*m_bp_cond, 1, parse_status, 1);
 
             if (parse_status == 0)
               {
--- a/libinterp/parse-tree/pt.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/pt.h	Thu Dec 20 17:18:56 2018 -0500
@@ -33,6 +33,7 @@
 
 namespace octave
 {
+  class tree_evaluator;
   class tree_walker;
 
   // Base class for the parse tree.
@@ -85,11 +86,16 @@
         }
     }
 
-    bool meets_bp_condition (void) const;
+    bool meets_bp_condition (tree_evaluator& tw) const;
 
-    bool is_breakpoint (bool check_active = false) const
+    bool is_breakpoint (void) const
     {
-      return m_bp_cond && (! check_active || meets_bp_condition ());
+      return m_bp_cond;
+    }
+
+    bool is_active_breakpoint (tree_evaluator& tw) const
+    {
+      return m_bp_cond && meets_bp_condition (tw);
     }
 
     // breakpoint condition, or "0" (i.e., "false") if no breakpoint.
--- a/libinterp/parse-tree/token.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/libinterp/parse-tree/token.h	Thu Dec 20 17:18:56 2018 -0500
@@ -97,9 +97,15 @@
     int line (void) const { return m_line_num; }
     int column (void) const { return m_column_num; }
 
+    bool iskeyword (void) const
+    {
+      return m_type_tag == keyword_token || m_type_tag == ettype_token;
+    }
+
+    OCTAVE_DEPRECATED (5, "use 'octave::iskeyword' instead")
     bool is_keyword (void) const
     {
-      return m_type_tag == keyword_token || m_type_tag == ettype_token;
+      return iskeyword ();
     }
 
     bool is_symbol (void) const
--- a/libinterp/version.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
-
-Copyright (C) 2013-2018 John W. Eaton
-
-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 <string>
-
-#include "defaults.h"
-#include "version.h"
-
-static std::string
-octave_warranty_statement (const std::string& extra_info = "")
-{
-  return "There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or\n\
-FITNESS FOR A PARTICULAR PURPOSE."
-         + extra_info;
-}
-
-static std::string
-format_url (bool html, const std::string& url)
-{
-  return html ? R"(<a href=")" + url + R"(">)" + url + "</a>" : url;
-}
-
-std::string
-octave_www_statement (bool html)
-{
-  return "Additional information about Octave is available at "
-         + format_url (html, "https://www.octave.org") + ".";
-}
-
-std::string
-octave_contrib_statement (bool html)
-{
-  return "Please contribute if you find this software useful.\n\
-For more information, visit "
-         + format_url (html, "https://www.octave.org/get-involved.html");
-}
-
-std::string
-octave_bugs_statement (bool html)
-{
-  return "Read " + format_url (html, "https://www.octave.org/bugs.html")
-         + " to learn how to submit bug reports.";
-}
-
-std::string
-octave_name_version_and_copyright (void)
-{
-  // The GNU coding standards say that on the first line printed by
-  // --version, the version number should follow the last space on the
-  // line.
-
-  return "GNU Octave, version " OCTAVE_VERSION "\n" OCTAVE_COPYRIGHT;
-}
-
-std::string
-octave_name_version_copyright_copying_and_warranty
-  (bool html, const std::string& extra_info)
-{
-  std::string br = (html ? "<br>\n" : "\n");
-  std::string sep = (html ? "\n</p>\n<p>\n" : "\n\n");
-
-  return octave_name_version_and_copyright ()
-         + br
-         + "This is free software; see the source code for copying conditions."
-         + br
-         + octave_warranty_statement (extra_info)
-         + sep
-         + R"(Octave was configured for ")"
-         + octave::config::canonical_host_type ()
-         + R"(".)";
-}
-
-std::string
-octave_name_version_copyright_copying_warranty_and_bugs
-  (bool html, const std::string& extra_info)
-{
-  std::string sep = (html ? "\n</p>\n<p>\n" : "\n\n");
-
-  std::string msg;
-
-  if (html)
-    msg = "<p>\n";
-
-  msg += octave_name_version_copyright_copying_and_warranty (html, extra_info)
-         + sep
-         + octave_www_statement (html)
-         + sep
-         + octave_contrib_statement (html)
-         + sep
-         + octave_bugs_statement (html)
-         + (html ? "\n</p>" : "");
-
-  return msg;
-}
-
-std::string
-octave_startup_message (bool html)
-{
-  std::string msg
-    = octave_name_version_copyright_copying_warranty_and_bugs
-        (html, "  For details, type 'warranty'.");
-
-  msg += (html ? "<p>\n" : "\n");
-
-  msg += "For information about changes from previous versions, type 'news'.";
-
-  msg += (html ? "\n</p>" : "");
-
-  return msg;
-}
--- a/libinterp/version.in.h	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-// %NO_EDIT_WARNING%
-/*
-
-Copyright (C) 1992-2018 John W. Eaton
-
-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_version_h)
-#define octave_version_h 1
-
-#include "octave-config.h"
-
-#define OCTAVE_VERSION %OCTAVE_VERSION%
-
-#define OCTAVE_MAJOR_VERSION %OCTAVE_MAJOR_VERSION%
-
-#define OCTAVE_MINOR_VERSION %OCTAVE_MINOR_VERSION%
-
-#define OCTAVE_PATCH_VERSION %OCTAVE_PATCH_VERSION%
-
-// The "API version" is used as a way of checking that interfaces in the
-// liboctave and libinterp libraries haven't changed in a backwardly
-// incompatible way when loading .oct files.  A better way to do that is
-// with library versioning, but not all systems support that.
-// NOTE: This macro will be removed in a future version of Octave.  If
-// you insist on checking for features using a version number, use the
-// OCTAVE_MAJOR_VERSION, OCTAVE_MINOR_VERSION, and
-// OCTAVE_PATCH_VERSION macros instead.
-#define OCTAVE_API_VERSION %OCTAVE_API_VERSION%
-
-#define OCTAVE_RELEASE_DATE %OCTAVE_RELEASE_DATE%
-
-#define OCTAVE_COPYRIGHT %OCTAVE_COPYRIGHT%
-
-#include <string>
-
-extern OCTINTERP_API std::string octave_www_statement (bool html = false);
-
-extern OCTINTERP_API std::string octave_contrib_statement (bool html = false);
-
-extern OCTINTERP_API std::string octave_bugs_statement (bool html = false);
-
-extern OCTINTERP_API std::string octave_name_version_and_copyright (void);
-
-extern OCTINTERP_API std::string
-octave_name_version_copyright_copying_and_warranty
-  (bool html = false, const std::string& extra_info = "");
-
-extern OCTINTERP_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);
-
-#endif
--- a/liboctave/array/Array.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/Array.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
 // C++ source files that should have included config.h before including
 // this file.
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "Array.h"
--- a/liboctave/array/CColVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CColVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
--- a/liboctave/array/CDiagMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CDiagMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "lo-error.h"
@@ -261,7 +261,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return row (static_cast<octave_idx_type>(0));
+    return row (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return row (rows () - 1);
   else
@@ -291,7 +291,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return column (static_cast<octave_idx_type>(0));
+    return column (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return column (cols () - 1);
   else
--- a/liboctave/array/CMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,8 +28,9 @@
 
 #include <algorithm>
 #include <complex>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "CDiagMatrix.h"
@@ -715,7 +716,7 @@
 norm1 (const ComplexMatrix& a)
 {
   double anorm = 0.0;
-  ColumnVector colsum = a.abs ().sum ().row (0);
+  RowVector colsum = a.abs ().sum ().row (0);
 
   for (octave_idx_type i = 0; i < colsum.numel (); i++)
     {
@@ -860,8 +861,6 @@
                              F77_DBLE_CMPLX_ARG (z.fortran_vec ()), lwork,
                              tmp_info));
 
-  info = tmp_info;
-
   lwork = static_cast<F77_INT> (std::real (z(0)));
   lwork = (lwork < 2 * nc ? 2 * nc : lwork);
   z.resize (dim_vector (lwork, 1));
@@ -879,8 +878,8 @@
     info = -1;
   else
     {
-      F77_XFCN (zgetrf, ZGETRF, (nc, nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
-                                 tmp_info));
+      F77_XFCN (zgetrf, ZGETRF, (nc, nc, F77_DBLE_CMPLX_ARG (tmp_data), nr,
+                                 pipvt, tmp_info));
 
       info = tmp_info;
     }
@@ -958,13 +957,13 @@
       if (! mattype.ishermitian ())
         ret = finverse (mattype, info, rcon, force, calc_cond);
 
-      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.)
+      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0)
         {
           if (numel () == 1)
-            ret = ComplexMatrix (1, 1, 0.);
+            ret = ComplexMatrix (1, 1, 0.0);
           else
             ret = ComplexMatrix (rows (), columns (),
-                                 Complex (octave::numeric_limits<double>::Inf (), 0.));
+                                 Complex (octave::numeric_limits<double>::Inf (), 0.0));
         }
     }
 
@@ -1104,234 +1103,40 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 ComplexMatrix
 ComplexMatrix::fourier (void) const
 {
-  ComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 ComplexMatrix::ifourier (void) const
 {
-  ComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  for (octave_idx_type j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 ComplexMatrix::fourier2d (void) const
 {
-  ComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<Complex> tmp (dim_vector (npts, 1));
-  Complex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i];
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 ComplexMatrix::ifourier2d (void) const
 {
-  ComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  for (F77_INT j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<Complex> tmp (dim_vector (npts, 1));
-  Complex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i] / static_cast<double> (npts);
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 #endif
@@ -1396,7 +1201,7 @@
       ComplexMatrix atmp = *this;
       Complex *tmp_data = atmp.fortran_vec ();
 
-      double anorm = 0;
+      double anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1417,23 +1222,26 @@
         }
       else
         {
-          Array<Complex> z (dim_vector (2 * nc, 1));
-          Complex *pz = z.fortran_vec ();
-          Array<double> rz (dim_vector (nc, 1));
-          double *prz = rz.fortran_vec ();
-
-          F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
-                                     nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
-                                     rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
-                                     F77_CHAR_ARG_LEN (1)));
-
-          info = tmp_info;
-
-          if (info != 0)
-            rcon = 0.0;
+          if (calc_cond)
+            {
+              Array<Complex> z (dim_vector (2 * nc, 1));
+              Complex *pz = z.fortran_vec ();
+              Array<double> rz (dim_vector (nc, 1));
+              double *prz = rz.fortran_vec ();
+
+              F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
+                                         nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
+                                         rcon, F77_DBLE_CMPLX_ARG (pz), prz, tmp_info
+                                         F77_CHAR_ARG_LEN (1)));
+
+              info = tmp_info;
+
+              if (info != 0)
+                rcon = 0.0;
+            }
 
           for (F77_INT i = 0; i < nc; i++)
-            retval *= atmp (i,i);
+            retval *= atmp(i,i);
 
           retval = retval.square ();
         }
@@ -1647,7 +1455,7 @@
               Array<F77_INT> ipvt (dim_vector (nr, 1));
               F77_INT *pipvt = ipvt.fortran_vec ();
 
-              if (anorm < 0.)
+              if (anorm < 0.0)
                 anorm = norm1 (atmp);
 
               Array<Complex> z (dim_vector (2 * nc, 1));
@@ -1659,8 +1467,9 @@
               if (octave::math::isnan (anorm))
                 info = -1;
               else
-                F77_XFCN (zgetrf, ZGETRF, (nr, nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
-                                           info));
+                F77_XFCN (zgetrf, ZGETRF, (nr, nr,
+                                           F77_DBLE_CMPLX_ARG (tmp_data),
+                                           nr, pipvt, info));
 
               if (info != 0)
                 {
@@ -1714,7 +1523,7 @@
       if (typ != MatrixType::Permuted_Upper && typ != MatrixType::Upper)
         (*current_liboctave_error_handler) ("incorrect matrix type");
 
-      rcon = 1.;
+      rcon = 1.0;
       info = 0;
 
       if (typ == MatrixType::Permuted_Upper)
@@ -1812,7 +1621,7 @@
       if (typ != MatrixType::Permuted_Lower && typ != MatrixType::Lower)
         (*current_liboctave_error_handler) ("incorrect matrix type");
 
-      rcon = 1.;
+      rcon = 1.0;
       info = 0;
 
       if (typ == MatrixType::Permuted_Lower)
@@ -1907,8 +1716,8 @@
     {
       volatile int typ = mattype.type ();
 
-      // Calculate the norm of the matrix, for later use.
-      double anorm = -1.;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      double anorm = -1.0;
 
       if (typ == MatrixType::Hermitian)
         {
@@ -1918,7 +1727,9 @@
           ComplexMatrix atmp = *this;
           Complex *tmp_data = atmp.fortran_vec ();
 
-          anorm = norm1 (atmp);
+          // The norm of the matrix for later use when determining rcon.
+          if (calc_cond)
+            anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
 
@@ -2005,7 +1816,7 @@
           double *prz = rz.fortran_vec ();
 
           // Calculate the norm of the matrix, for later use.
-          if (anorm < 0.)
+          if (calc_cond && anorm < 0.0)
             anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
@@ -2016,8 +1827,8 @@
             info = -2;
           else
             {
-              F77_XFCN (zgetrf, ZGETRF, (nr, nr, F77_DBLE_CMPLX_ARG (tmp_data), nr, pipvt,
-                                         tmp_info));
+              F77_XFCN (zgetrf, ZGETRF, (nr, nr, F77_DBLE_CMPLX_ARG (tmp_data),
+                                         nr, pipvt, tmp_info));
 
               info = tmp_info;
             }
@@ -2039,8 +1850,7 @@
             {
               if (calc_cond)
                 {
-                  // Now calculate the condition number for
-                  // non-singular matrix.
+                  // Calculate the condition number for non-singular matrix.
                   char job = '1';
                   F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
                                              nc, F77_DBLE_CMPLX_ARG (tmp_data), nr, anorm,
@@ -2445,13 +2255,12 @@
 {
   ComplexMatrix retval;
 
-  F77_INT nrhs = octave::to_f77_int (b.cols ());
-
   F77_INT m = octave::to_f77_int (rows ());
   F77_INT n = octave::to_f77_int (cols ());
 
   F77_INT b_nr = octave::to_f77_int (b.rows ());
   F77_INT b_nc = octave::to_f77_int (b.cols ());
+  F77_INT nrhs = b_nc;  // alias for code readability
 
   if (m != b_nr)
     (*current_liboctave_error_handler)
@@ -2508,7 +2317,6 @@
       double dminmn = static_cast<double> (minmn);
       double dsmlsizp1 = static_cast<double> (smlsiz+1);
       double tmp = octave::math::log2 (dminmn / dsmlsizp1);
-      double anorm = 0.0;
 
       F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
       if (nlvl < 0)
@@ -2573,12 +2381,11 @@
       lwork = static_cast<F77_INT> (std::real (work(0)));
       work.resize (dim_vector (lwork, 1));
 
-      anorm = norm1 (*this);
+      double anorm = norm1 (*this);
 
       if (octave::math::isinf (anorm))
         {
           rcon = 0.0;
-          octave::warn_singular_matrix ();
           retval = ComplexMatrix (n, b_nc, 0.0);
         }
       else if (octave::math::isnan (anorm))
@@ -3819,7 +3626,7 @@
   // The last column is unused so temporarily store delta there
   Complex *delta = &retval(0, n-1);
   for (octave_idx_type i = 0; i < m; i++)
-    delta[i] = (x2(i) - x1(i)) / (n - 1.0);
+    delta[i] = (x1(i) == x2(i)) ? 0 : (x2(i) - x1(i)) / (n - 1.0);
 
   for (octave_idx_type j = 1; j < n-1; j++)
     for (octave_idx_type i = 0; i < m; i++)
--- a/liboctave/array/CNDArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CNDArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,8 @@
 #endif
 
 #include <complex>
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "CNDArray.h"
@@ -186,299 +187,58 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 ComplexNDArray
 ComplexNDArray::fourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return ComplexNDArray ();
-
-  ComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (Complex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (tmp),
-                                   F77_DBLE_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i];
-        }
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 ComplexNDArray::ifourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return ComplexNDArray ();
-
-  ComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (Complex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (tmp),
-                                   F77_DBLE_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i] /
-                                                   static_cast<double> (npts);
-        }
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 ComplexNDArray::fourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 ComplexNDArray::ifourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<double> (npts);
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 ComplexNDArray::fourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 ComplexNDArray::ifourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<double> (npts);
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 #endif
--- a/liboctave/array/CRowVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CRowVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
@@ -432,7 +433,7 @@
 
   retval(0) = x1;
 
-  Complex delta = (x2 - x1) / (n - 1.0);
+  Complex delta = (x1 == x2) ? 0 : (x2 - x1) / (n - 1.0);
   for (octave_idx_type i = 1; i < n-1; i++)
     retval(i) = x1 + static_cast<double> (i)*delta;
 
--- a/liboctave/array/CSparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/CSparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,8 @@
 #endif
 
 #include <complex>
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "quit.h"
 #include "lo-ieee.h"
@@ -6045,14 +6046,14 @@
               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               retval = SparseComplexMatrix
-                       (static_cast<octave_idx_type>(X->nrow),
-                        static_cast<octave_idx_type>(X->ncol),
-                        static_cast<octave_idx_type>(X->nzmax));
+                       (static_cast<octave_idx_type> (X->nrow),
+                        static_cast<octave_idx_type> (X->ncol),
+                        static_cast<octave_idx_type> (X->nzmax));
               for (octave_idx_type j = 0;
-                   j <= static_cast<octave_idx_type>(X->ncol); j++)
+                   j <= static_cast<octave_idx_type> (X->ncol); j++)
                 retval.xcidx (j) = static_cast<octave_idx_type *>(X->p)[j];
               for (octave_idx_type j = 0;
-                   j < static_cast<octave_idx_type>(X->nzmax); j++)
+                   j < static_cast<octave_idx_type> (X->nzmax); j++)
                 {
                   retval.xridx (j) = static_cast<octave_idx_type *>(X->i)[j];
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
@@ -6579,14 +6580,14 @@
               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               retval = SparseComplexMatrix
-                       (static_cast<octave_idx_type>(X->nrow),
-                        static_cast<octave_idx_type>(X->ncol),
-                        static_cast<octave_idx_type>(X->nzmax));
+                       (static_cast<octave_idx_type> (X->nrow),
+                        static_cast<octave_idx_type> (X->ncol),
+                        static_cast<octave_idx_type> (X->nzmax));
               for (octave_idx_type j = 0;
-                   j <= static_cast<octave_idx_type>(X->ncol); j++)
+                   j <= static_cast<octave_idx_type> (X->ncol); j++)
                 retval.xcidx (j) = static_cast<octave_idx_type *>(X->p)[j];
               for (octave_idx_type j = 0;
-                   j < static_cast<octave_idx_type>(X->nzmax); j++)
+                   j < static_cast<octave_idx_type> (X->nzmax); j++)
                 {
                   retval.xridx (j) = static_cast<octave_idx_type *>(X->i)[j];
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
@@ -7525,61 +7526,61 @@
 ComplexMatrix
 operator * (const ComplexMatrix& m, const SparseMatrix& a)
 {
-  FULL_SPARSE_MUL (ComplexMatrix, double, Complex (0.,0.));
+  FULL_SPARSE_MUL (ComplexMatrix, double);
 }
 
 ComplexMatrix
 operator * (const Matrix& m, const SparseComplexMatrix& a)
 {
-  FULL_SPARSE_MUL (ComplexMatrix, Complex, Complex (0.,0.));
+  FULL_SPARSE_MUL (ComplexMatrix, Complex);
 }
 
 ComplexMatrix
 operator * (const ComplexMatrix& m, const SparseComplexMatrix& a)
 {
-  FULL_SPARSE_MUL (ComplexMatrix, Complex, Complex (0.,0.));
+  FULL_SPARSE_MUL (ComplexMatrix, Complex);
 }
 
 ComplexMatrix
 mul_trans (const ComplexMatrix& m, const SparseComplexMatrix& a)
 {
-  FULL_SPARSE_MUL_TRANS (ComplexMatrix, Complex, Complex (0.,0.), );
+  FULL_SPARSE_MUL_TRANS (ComplexMatrix, Complex, );
 }
 
 ComplexMatrix
 mul_herm (const ComplexMatrix& m, const SparseComplexMatrix& a)
 {
-  FULL_SPARSE_MUL_TRANS (ComplexMatrix, Complex, Complex (0.,0.), conj);
+  FULL_SPARSE_MUL_TRANS (ComplexMatrix, Complex, conj);
 }
 
 ComplexMatrix
 operator * (const SparseComplexMatrix& m, const Matrix& a)
 {
-  SPARSE_FULL_MUL (ComplexMatrix, double, Complex (0.,0.));
+  SPARSE_FULL_MUL (ComplexMatrix, double);
 }
 
 ComplexMatrix
 operator * (const SparseMatrix& m, const ComplexMatrix& a)
 {
-  SPARSE_FULL_MUL (ComplexMatrix, Complex, Complex (0.,0.));
+  SPARSE_FULL_MUL (ComplexMatrix, Complex);
 }
 
 ComplexMatrix
 operator * (const SparseComplexMatrix& m, const ComplexMatrix& a)
 {
-  SPARSE_FULL_MUL (ComplexMatrix, Complex, Complex (0.,0.));
+  SPARSE_FULL_MUL (ComplexMatrix, Complex);
 }
 
 ComplexMatrix
 trans_mul (const SparseComplexMatrix& m, const ComplexMatrix& a)
 {
-  SPARSE_FULL_TRANS_MUL (ComplexMatrix, Complex, Complex (0.,0.), );
+  SPARSE_FULL_TRANS_MUL (ComplexMatrix, Complex, );
 }
 
 ComplexMatrix
 herm_mul (const SparseComplexMatrix& m, const ComplexMatrix& a)
 {
-  SPARSE_FULL_TRANS_MUL (ComplexMatrix, Complex, Complex (0.,0.), conj);
+  SPARSE_FULL_TRANS_MUL (ComplexMatrix, Complex, conj);
 }
 
 // diag * sparse and sparse * diag
@@ -7932,14 +7933,11 @@
   return r;
 }
 
-SPARSE_SMS_CMP_OPS (SparseComplexMatrix, 0.0, real, Complex,
-                    0.0, real)
-SPARSE_SMS_BOOL_OPS (SparseComplexMatrix, Complex, 0.0)
-
-SPARSE_SSM_CMP_OPS (Complex, 0.0, real, SparseComplexMatrix,
-                    0.0, real)
-SPARSE_SSM_BOOL_OPS (Complex, SparseComplexMatrix, 0.0)
-
-SPARSE_SMSM_CMP_OPS (SparseComplexMatrix, 0.0, real, SparseComplexMatrix,
-                     0.0, real)
-SPARSE_SMSM_BOOL_OPS (SparseComplexMatrix, SparseComplexMatrix, 0.0)
+SPARSE_SMS_CMP_OPS (SparseComplexMatrix, Complex)
+SPARSE_SMS_BOOL_OPS (SparseComplexMatrix, Complex)
+
+SPARSE_SSM_CMP_OPS (Complex, SparseComplexMatrix)
+SPARSE_SSM_BOOL_OPS (Complex, SparseComplexMatrix)
+
+SPARSE_SMSM_CMP_OPS (SparseComplexMatrix, SparseComplexMatrix)
+SPARSE_SMSM_BOOL_OPS (SparseComplexMatrix, SparseComplexMatrix)
--- a/liboctave/array/DiagArray2.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/DiagArray2.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,8 +27,6 @@
 
 #include <cassert>
 
-#include <iostream>
-
 #include <algorithm>
 
 #include "DiagArray2.h"
--- a/liboctave/array/MArray-i.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/MArray-i.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,15 +36,6 @@
 template class OCTAVE_API MArray<int64_t>;
 #endif
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-// Explicit instantiation, as this seems to be required by weird compilers
-// like MSVC.  This should be harmless on other compilers.
-template int xmin<int> (int, int);
-template int xmax<int> (int, int);
-template long xmin<long> (long, long);
-template long xmax<long> (long, long);
-#endif
-
 INSTANTIATE_MARRAY_FRIENDS (int, OCTAVE_API)
 #if defined (OCTAVE_ENABLE_64)
 INSTANTIATE_MARRAY_FRIENDS (int64_t, OCTAVE_API)
--- a/liboctave/array/MArray-s.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/MArray-s.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -31,13 +31,6 @@
 
 template class OCTAVE_API MArray<short>;
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-// Explicit instantiation, as this seems to be required by weird compilers
-// like MSVC.  This should be harmless on other compilers.
-template short xmin<short> (short, short);
-template short xmax<short> (short, short);
-#endif
-
 INSTANTIATE_MARRAY_FRIENDS (short, OCTAVE_API)
 
 #include "MDiagArray2.h"
--- a/liboctave/array/MArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/MArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -134,8 +134,6 @@
                                                          vals.data ()));
 }
 
-#include <iostream>
-
 template <typename T>
 void MArray<T>::idx_add_nd (const idx_vector& idx, const MArray<T>& vals,
                             int dim)
--- a/liboctave/array/MDiagArray2.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/MDiagArray2.h	Thu Dec 20 17:18:56 2018 -0500
@@ -91,10 +91,10 @@
 
     octave_idx_type nel = this->length ();
 
-    const T zero = T ();
+    static constexpr T zero = T ();
 
     return std::count_if (d, d + nel,
-                          [zero] (T elem) { return elem != zero; });
+                          [] (T elem) { return elem != zero; });
   }
 
   MArray<T> diag (octave_idx_type k = 0) const
--- a/liboctave/array/MatrixType.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/MatrixType.h	Thu Dec 20 17:18:56 2018 -0500
@@ -192,7 +192,7 @@
   MatrixType transpose (void) const;
 
 private:
-  void type (int new_typ) { typ = static_cast<matrix_type>(new_typ); }
+  void type (int new_typ) { typ = static_cast<matrix_type> (new_typ); }
 
   matrix_type typ;
   double sp_bandden;
--- a/liboctave/array/Range.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/Range.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,8 +26,9 @@
 
 #include <cmath>
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "Range.h"
@@ -38,9 +39,9 @@
 bool
 Range::all_elements_are_ints (void) const
 {
-  // If the base and increment are ints, the final value in the range
-  // will also be an integer, even if the limit is not.  If there is one
-  // or fewer elements only the base needs to be an integer
+  // If the base and increment are ints, the final value in the range will also
+  // be an integer, even if the limit is not.  If 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)
@@ -63,10 +64,13 @@
       else if (rng_inc != 0.0)
         {
           if (rng_base == 0.0 || rng_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))
+            // Range crosses negative/positive without hitting zero.
             retval = rng_numel;
           else
+            // Range crosses negative/positive and hits zero.
             retval = rng_numel - 1;
         }
       else
@@ -94,9 +98,9 @@
       double b = rng_base;
       double increment = rng_inc;
       for (octave_idx_type i = 1; i < rng_numel - 1; i++)
-        cache(i) = b + i * increment;
+        cache.xelem (i) = b + i * increment;
 
-      cache(rng_numel - 1) = rng_limit;
+      cache.xelem (rng_numel - 1) = rng_limit;
     }
 
   return cache;
@@ -105,8 +109,6 @@
 double
 Range::checkelem (octave_idx_type i) const
 {
-  // Ranges are row vectors.
-
   if (i < 0 || i >= rng_numel)
     octave::err_index_out_of_range (2, 2, i+1, rng_numel);
 
@@ -121,6 +123,7 @@
 double
 Range::checkelem (octave_idx_type i, octave_idx_type j) const
 {
+  // Ranges are *always* row vectors.
   if (i != 0)
     octave::err_index_out_of_range (1, 1, i+1, rng_numel);
 
@@ -283,7 +286,6 @@
 
   for (octave_idx_type i = 0; i < nel; i++, tmp += stp)
     psidx[i] = tmp;
-
 }
 
 Matrix
@@ -380,17 +382,17 @@
 {
   double b = a.base ();
   double increment = a.inc ();
-  octave_idx_type num_elem = a.numel ();
+  octave_idx_type nel = a.numel ();
 
-  if (num_elem > 1)
+  if (nel > 1)
     {
-      // First element must be the base *exactly* (-0).
+      // First element must be the base *exactly* (e.g., -0).
       os << b << ' ';
-      for (octave_idx_type i = 1; i < num_elem-1; i++)
+      for (octave_idx_type i = 1; i < nel-1; i++)
         os << b + i * increment << ' ';
     }
 
-  // Print out exactly the last element, rather than a calculated last element.
+  // Print out the last element exactly, rather than a calculated last element.
   os << a.rng_limit << "\n";
 
   return os;
@@ -408,7 +410,7 @@
       if (is)
         is >> a.rng_inc;
 
-      // Clip the rng_limit to the true limit and rebuild numel, clear cache
+      // Clip the rng_limit to the true limit, rebuild numel, clear cache
       a.set_limit (tmp_rng_limit);
     }
 
@@ -424,6 +426,9 @@
 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 ();
 
@@ -541,10 +546,10 @@
 teq (double u, double v,
      double ct = 3.0 * std::numeric_limits<double>::epsilon ())
 {
-  double tu = fabs (u);
-  double tv = fabs (v);
+  double tu = std::abs (u);
+  double tv = std::abs (v);
 
-  return fabs (u - v) < ((tu > tv ? tu : tv) * ct);
+  return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
 }
 
 octave_idx_type
@@ -567,16 +572,14 @@
       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, accept it.  Otherwise, try a range with one
-      // fewer element.  If that fails, try again with one more
-      // element.
+      // 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].
+      // 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 (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
         {
@@ -596,14 +599,18 @@
 double
 Range::limit_internal (void) const
 {
-  double tmp_limit = rng_limit;
+  double new_limit = rng_limit;
 
   if (rng_inc > 0)
-    tmp_limit = max ();
+    new_limit = max ();
   else
-    tmp_limit = min ();
+    new_limit = min ();
 
-  return (tmp_limit != rng_limit) ? tmp_limit : rng_limit;
+  // If result must be an integer then force the new_limit to be one.
+  if (all_elements_are_ints ())
+    new_limit = std::round (new_limit);
+
+  return new_limit;
 }
 
 void
--- a/liboctave/array/Range.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/Range.h	Thu Dec 20 17:18:56 2018 -0500
@@ -70,7 +70,6 @@
         // 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 ();
       }
   }
@@ -79,11 +78,11 @@
   double limit (void) const { return rng_limit; }
   double inc (void) const { return rng_inc; }
 
+  octave_idx_type numel (void) const { return rng_numel; }
+
   OCTAVE_DEPRECATED (4.4, "use 'numel' instead")
   octave_idx_type nelem (void) const { return numel (); }
 
-  octave_idx_type numel (void) const { return rng_numel; }
-
   octave_idx_type rows (void) const { return 1; }
 
   octave_idx_type cols (void) const { return numel (); }
@@ -108,7 +107,6 @@
   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,
               sortmode mode = ASCENDING) const;
 
@@ -185,17 +183,11 @@
 };
 
 extern OCTAVE_API Range operator - (const Range& r);
-
 extern OCTAVE_API Range operator + (double x, const Range& r);
-
 extern OCTAVE_API Range operator + (const Range& r, double x);
-
 extern OCTAVE_API Range operator - (double x, const Range& r);
-
 extern OCTAVE_API Range operator - (const Range& r, double x);
-
 extern OCTAVE_API Range operator * (double x, const Range& r);
-
 extern OCTAVE_API Range operator * (const Range& r, double x);
 
 #endif
--- a/liboctave/array/Sparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/Sparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -29,8 +29,8 @@
 #include <cassert>
 
 #include <algorithm>
-#include <iostream>
-#include <limits>
+#include <istream>
+#include <ostream>
 #include <sstream>
 #include <vector>
 
--- a/liboctave/array/boolMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/boolMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "boolMatrix.h"
--- a/liboctave/array/boolSparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/boolSparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 #include <vector>
 
 #include "quit.h"
@@ -320,11 +321,11 @@
   return Sparse<bool>::ipermute (vec);
 }
 
-SPARSE_SMS_EQNE_OPS (SparseBoolMatrix, false, , bool, false, )
-SPARSE_SMS_BOOL_OPS (SparseBoolMatrix, bool, false)
+SPARSE_SMS_EQNE_OPS (SparseBoolMatrix, bool)
+SPARSE_SMS_BOOL_OPS (SparseBoolMatrix, bool)
 
-SPARSE_SSM_EQNE_OPS (bool, false, , SparseBoolMatrix, false, )
-SPARSE_SSM_BOOL_OPS (bool, SparseBoolMatrix, false)
+SPARSE_SSM_EQNE_OPS (bool, SparseBoolMatrix)
+SPARSE_SSM_BOOL_OPS (bool, SparseBoolMatrix)
 
-SPARSE_SMSM_EQNE_OPS (SparseBoolMatrix, false, , SparseBoolMatrix, false, )
-SPARSE_SMSM_BOOL_OPS (SparseBoolMatrix, SparseBoolMatrix, false)
+SPARSE_SMSM_EQNE_OPS (SparseBoolMatrix, SparseBoolMatrix)
+SPARSE_SMSM_BOOL_OPS (SparseBoolMatrix, SparseBoolMatrix)
--- a/liboctave/array/chMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/chMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,7 @@
 
 #include <cstring>
 
-#include <iostream>
+#include <ostream>
 #include <string>
 
 #include "lo-error.h"
--- a/liboctave/array/chNDArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/chNDArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -128,7 +128,7 @@
         // FIXME: is there something better to do? Should we warn the user?
         ival = 0;
 
-      tmp.elem (i) = static_cast<char>(ival);
+      tmp.elem (i) = static_cast<char> (ival);
     }
 
   insert (tmp, ra_idx);
--- a/liboctave/array/dColVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dColVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
--- a/liboctave/array/dDiagMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dDiagMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "lo-error.h"
@@ -184,7 +184,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return row (static_cast<octave_idx_type>(0));
+    return row (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return row (rows () - 1);
   else
@@ -214,7 +214,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return column (static_cast<octave_idx_type>(0));
+    return column (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return column (cols () - 1);
   else
--- a/liboctave/array/dMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,8 +27,9 @@
 #endif
 
 #include <algorithm>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "CColVector.h"
@@ -429,7 +430,7 @@
 norm1 (const Matrix& a)
 {
   double anorm = 0.0;
-  ColumnVector colsum = a.abs ().sum ().row (0);
+  RowVector colsum = a.abs ().sum ().row (0);
 
   for (octave_idx_type i = 0; i < colsum.numel (); i++)
     {
@@ -572,8 +573,6 @@
   F77_XFCN (dgetri, DGETRI, (nc, tmp_data, nr, pipvt,
                              z.fortran_vec (), lwork, tmp_info));
 
-  info = tmp_info;
-
   lwork = static_cast<F77_INT> (z(0));
   lwork = (lwork < 4 * nc ? 4 * nc : lwork);
   z.resize (dim_vector (lwork, 1));
@@ -582,8 +581,8 @@
   info = 0;
   tmp_info = 0;
 
-  // Calculate the norm of the matrix, for later use.
-  double anorm = 0;
+  // Calculate the norm of the matrix for later use when determining rcon.
+  double anorm;
   if (calc_cond)
     anorm = norm1 (retval);
 
@@ -663,8 +662,8 @@
       if (! mattype.ishermitian ())
         ret = finverse (mattype, info, rcon, force, calc_cond);
 
-      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.
-          && ! (numel () == 1))
+      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0
+          && (numel () != 1))
         ret = Matrix (rows (), columns (),
                       octave::numeric_limits<double>::Inf ());
     }
@@ -799,234 +798,40 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 ComplexMatrix
 Matrix::fourier (void) const
 {
-  ComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = ComplexMatrix (*this);
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 Matrix::ifourier (void) const
 {
-  ComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = ComplexMatrix (*this);
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  for (octave_idx_type j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 Matrix::fourier2d (void) const
 {
-  ComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = ComplexMatrix (*this);
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<Complex> tmp (dim_vector (npts, 1));
-  Complex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i];
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 ComplexMatrix
 Matrix::ifourier2d (void) const
 {
-  ComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  retval = ComplexMatrix (*this);
-  Complex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-    }
-
-  for (F77_INT j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<double> (npts);
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<Complex> tmp (dim_vector (npts, 1));
-  Complex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                               F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i] / static_cast<double> (npts);
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return ComplexMatrix ();
 }
 
 #endif
@@ -1088,7 +893,8 @@
       Matrix atmp = *this;
       double *tmp_data = atmp.fortran_vec ();
 
-      double anorm = 0;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      double anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1109,23 +915,26 @@
         }
       else
         {
-          Array<double> z (dim_vector (3 * nc, 1));
-          double *pz = z.fortran_vec ();
-          Array<F77_INT> iz (dim_vector (nc, 1));
-          F77_INT *piz = iz.fortran_vec ();
-
-          F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
-                                     nr, tmp_data, nr, anorm,
-                                     rcon, pz, piz, tmp_info
-                                     F77_CHAR_ARG_LEN (1)));
-
-          info = tmp_info;
-
-          if (info != 0)
-            rcon = 0.0;
+          if (calc_cond)
+            {
+              Array<double> z (dim_vector (3 * nc, 1));
+              double *pz = z.fortran_vec ();
+              Array<F77_INT> iz (dim_vector (nc, 1));
+              F77_INT *piz = iz.fortran_vec ();
+
+              F77_XFCN (dpocon, DPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
+                                         nr, tmp_data, nr, anorm,
+                                         rcon, pz, piz, tmp_info
+                                         F77_CHAR_ARG_LEN (1)));
+
+              info = tmp_info;
+
+              if (info != 0)
+                rcon = 0.0;
+            }
 
           for (F77_INT i = 0; i < nc; i++)
-            retval *= atmp (i,i);
+            retval *= atmp(i,i);
 
           retval = retval.square ();
         }
@@ -1144,8 +953,8 @@
       info = 0;
       F77_INT tmp_info = 0;
 
-      // Calculate the norm of the matrix, for later use.
-      double anorm = 0;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      double anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1175,10 +984,10 @@
                                          nc, tmp_data, nr, anorm,
                                          rcon, pz, piz, tmp_info
                                          F77_CHAR_ARG_LEN (1)));
+
+              info = tmp_info;
             }
 
-          info = tmp_info;
-
           if (info != 0)
             {
               info = -1;
@@ -1332,7 +1141,7 @@
               Array<F77_INT> ipvt (dim_vector (nr, 1));
               F77_INT *pipvt = ipvt.fortran_vec ();
 
-              if (anorm < 0.)
+              if (anorm < 0.0)
                 anorm = norm1 (atmp);
 
               Array<double> z (dim_vector (4 * nc, 1));
@@ -1393,7 +1202,7 @@
       if (typ != MatrixType::Permuted_Upper && typ != MatrixType::Upper)
         (*current_liboctave_error_handler) ("incorrect matrix type");
 
-      rcon = 1.;
+      rcon = 1.0;
       info = 0;
 
       if (typ == MatrixType::Permuted_Upper)
@@ -1447,6 +1256,7 @@
           if (info != 0)
             info = -2;
 
+          // FIXME: Why calculate this, rather than just compare to 0.0?
           volatile double rcond_plus_one = rcon + 1.0;
 
           if (rcond_plus_one == 1.0 || octave::math::isnan (rcon))
@@ -1490,7 +1300,7 @@
       if (typ != MatrixType::Permuted_Lower && typ != MatrixType::Lower)
         (*current_liboctave_error_handler) ("incorrect matrix type");
 
-      rcon = 1.;
+      rcon = 1.0;
       info = 0;
 
       if (typ == MatrixType::Permuted_Lower)
@@ -1581,8 +1391,8 @@
     {
       volatile int typ = mattype.type ();
 
-      // Calculate the norm of the matrix, for later use.
-      double anorm = -1.;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      double anorm = -1.0;
 
       if (typ == MatrixType::Hermitian)
         {
@@ -1592,7 +1402,9 @@
           Matrix atmp = *this;
           double *tmp_data = atmp.fortran_vec ();
 
-          anorm = norm1 (atmp);
+          // The norm of the matrix for later use when determining rcon.
+          if (calc_cond)
+            anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
 
@@ -1676,7 +1488,7 @@
           Matrix atmp = *this;
           double *tmp_data = atmp.fortran_vec ();
 
-          if (anorm < 0.)
+          if (calc_cond && anorm < 0.0)
             anorm = norm1 (atmp);
 
           Array<double> z (dim_vector (4 * nc, 1));
@@ -1707,8 +1519,7 @@
             {
               if (calc_cond)
                 {
-                  // Now calculate the condition number for
-                  // non-singular matrix.
+                  // Calculate the condition number for non-singular matrix.
                   char job = '1';
                   F77_XFCN (dgecon, DGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
                                              nc, tmp_data, nr, anorm,
@@ -2102,13 +1913,12 @@
 {
   Matrix retval;
 
-  F77_INT nrhs = octave::to_f77_int (b.cols ());
-
   F77_INT m = octave::to_f77_int (rows ());
   F77_INT n = octave::to_f77_int (cols ());
 
   F77_INT b_nr = octave::to_f77_int (b.rows ());
   F77_INT b_nc = octave::to_f77_int (b.cols ());
+  F77_INT nrhs = b_nc;  // alias for code readability
 
   if (m != b_nr)
     (*current_liboctave_error_handler)
@@ -2163,7 +1973,6 @@
       double dminmn = static_cast<double> (minmn);
       double dsmlsizp1 = static_cast<double> (smlsiz+1);
       double tmp = octave::math::log2 (dminmn / dsmlsizp1);
-      double anorm = 0.0;
 
       F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
       if (nlvl < 0)
@@ -2225,12 +2034,11 @@
       lwork = static_cast<F77_INT> (work(0));
       work.resize (dim_vector (lwork, 1));
 
-      anorm = norm1 (*this);
+      double anorm = norm1 (*this);
 
       if (octave::math::isinf (anorm))
         {
           rcon = 0.0;
-          octave::warn_singular_matrix ();
           retval = Matrix (n, b_nc, 0.0);
         }
       else if (octave::math::isnan (anorm))
@@ -3210,7 +3018,7 @@
   // The last column is unused so temporarily store delta there
   double *delta = &retval(0, n-1);
   for (octave_idx_type i = 0; i < m; i++)
-    delta[i] = (x2(i) - x1(i)) / (n - 1);
+    delta[i] = (x1(i) == x2(i)) ? 0 : (x2(i) - x1(i)) / (n - 1);
 
   for (octave_idx_type j = 1; j < n-1; j++)
     for (octave_idx_type i = 0; i < m; i++)
--- a/liboctave/array/dNDArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dNDArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "dNDArray.h"
@@ -227,299 +228,58 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 ComplexNDArray
 NDArray::fourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return ComplexNDArray ();
-
-  ComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (Complex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (tmp),
-                                   F77_DBLE_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i];
-        }
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 NDArray::ifourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return ComplexNDArray ();
-
-  ComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<Complex> wsave (dim_vector (nn, 1));
-  Complex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (Complex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (tmp),
-                                   F77_DBLE_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i] /
-                                                   static_cast<double> (npts);
-        }
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 NDArray::fourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 NDArray::ifourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<double> (npts);
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 NDArray::fourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftf, ZFFTF) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 ComplexNDArray
 NDArray::ifourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  ComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<Complex> wsave (dim_vector (nn, 1));
-      Complex *pwsave = wsave.fortran_vec ();
-      Array<Complex> row (dim_vector (npts, 1));
-      Complex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (zffti, ZFFTI) (npts, F77_DBLE_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (zfftb, ZFFTB) (npts, F77_DBLE_CMPLX_ARG (prow),
-                                       F77_DBLE_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<double> (npts);
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return ComplexNDArray ();
 }
 
 #endif
@@ -765,7 +525,7 @@
         // FIXME: is there something better to do? Should we warn the user?
         ival = 0;
 
-      retval.elem (i) = static_cast<char>(ival);
+      retval.elem (i) = static_cast<char> (ival);
     }
 
   if (rb.isempty ())
--- a/liboctave/array/dRowVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dRowVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
@@ -275,7 +276,7 @@
 
   retval(0) = x1;
 
-  double delta = (x2 - x1) / (n - 1);
+  double delta = (x1 == x2) ? 0 : ((x2 - x1) / (n - 1));
   for (octave_idx_type i = 1; i < n-1; i++)
     retval(i) = x1 + i*delta;
 
--- a/liboctave/array/dSparse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/dSparse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "quit.h"
 #include "lo-ieee.h"
@@ -6058,14 +6059,14 @@
               X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
-              retval = SparseMatrix (static_cast<octave_idx_type>(X->nrow),
-                                     static_cast<octave_idx_type>(X->ncol),
-                                     static_cast<octave_idx_type>(X->nzmax));
+              retval = SparseMatrix (static_cast<octave_idx_type> (X->nrow),
+                                     static_cast<octave_idx_type> (X->ncol),
+                                     static_cast<octave_idx_type> (X->nzmax));
               for (octave_idx_type j = 0;
-                   j <= static_cast<octave_idx_type>(X->ncol); j++)
+                   j <= static_cast<octave_idx_type> (X->ncol); j++)
                 retval.xcidx (j) = static_cast<octave_idx_type *>(X->p)[j];
               for (octave_idx_type j = 0;
-                   j < static_cast<octave_idx_type>(X->nzmax); j++)
+                   j < static_cast<octave_idx_type> (X->nzmax); j++)
                 {
                   retval.xridx (j) = static_cast<octave_idx_type *>(X->i)[j];
                   retval.xdata (j) = static_cast<double *>(X->x)[j];
@@ -6577,14 +6578,14 @@
               END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               retval = SparseComplexMatrix
-                       (static_cast<octave_idx_type>(X->nrow),
-                        static_cast<octave_idx_type>(X->ncol),
-                        static_cast<octave_idx_type>(X->nzmax));
+                       (static_cast<octave_idx_type> (X->nrow),
+                        static_cast<octave_idx_type> (X->ncol),
+                        static_cast<octave_idx_type> (X->nzmax));
               for (octave_idx_type j = 0;
-                   j <= static_cast<octave_idx_type>(X->ncol); j++)
+                   j <= static_cast<octave_idx_type> (X->ncol); j++)
                 retval.xcidx (j) = static_cast<octave_idx_type *>(X->p)[j];
               for (octave_idx_type j = 0;
-                   j < static_cast<octave_idx_type>(X->nzmax); j++)
+                   j < static_cast<octave_idx_type> (X->nzmax); j++)
                 {
                   retval.xridx (j) = static_cast<octave_idx_type *>(X->i)[j];
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
@@ -7544,25 +7545,25 @@
 Matrix
 operator * (const Matrix& m, const SparseMatrix& a)
 {
-  FULL_SPARSE_MUL (Matrix, double, 0.);
+  FULL_SPARSE_MUL (Matrix, double);
 }
 
 Matrix
 mul_trans (const Matrix& m, const SparseMatrix& a)
 {
-  FULL_SPARSE_MUL_TRANS (Matrix, double, 0., );
+  FULL_SPARSE_MUL_TRANS (Matrix, double, );
 }
 
 Matrix
 operator * (const SparseMatrix& m, const Matrix& a)
 {
-  SPARSE_FULL_MUL (Matrix, double, 0.);
+  SPARSE_FULL_MUL (Matrix, double);
 }
 
 Matrix
 trans_mul (const SparseMatrix& m, const Matrix& a)
 {
-  SPARSE_FULL_TRANS_MUL (Matrix, double, 0., );
+  SPARSE_FULL_TRANS_MUL (Matrix, double, );
 }
 
 // diag * sparse and sparse * diag
@@ -7923,11 +7924,11 @@
   return r;
 }
 
-SPARSE_SMS_CMP_OPS (SparseMatrix, 0.0, , double, 0.0, )
-SPARSE_SMS_BOOL_OPS (SparseMatrix, double, 0.0)
-
-SPARSE_SSM_CMP_OPS (double, 0.0, , SparseMatrix, 0.0, )
-SPARSE_SSM_BOOL_OPS (double, SparseMatrix, 0.0)
-
-SPARSE_SMSM_CMP_OPS (SparseMatrix, 0.0, , SparseMatrix, 0.0, )
-SPARSE_SMSM_BOOL_OPS (SparseMatrix, SparseMatrix, 0.0)
+SPARSE_SMS_CMP_OPS (SparseMatrix, double)
+SPARSE_SMS_BOOL_OPS (SparseMatrix, double)
+
+SPARSE_SSM_CMP_OPS (double, SparseMatrix)
+SPARSE_SSM_BOOL_OPS (double, SparseMatrix)
+
+SPARSE_SMSM_CMP_OPS (SparseMatrix, SparseMatrix)
+SPARSE_SMSM_BOOL_OPS (SparseMatrix, SparseMatrix)
--- a/liboctave/array/fCColVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fCColVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
--- a/liboctave/array/fCDiagMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fCDiagMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "lo-error.h"
@@ -265,7 +265,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return row (static_cast<octave_idx_type>(0));
+    return row (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return row (rows () - 1);
   else
@@ -295,7 +295,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return column (static_cast<octave_idx_type>(0));
+    return column (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return column (cols () - 1);
   else
--- a/liboctave/array/fCMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fCMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,8 +28,9 @@
 
 #include <algorithm>
 #include <complex>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "DET.h"
@@ -718,7 +719,7 @@
 norm1 (const FloatComplexMatrix& a)
 {
   float anorm = 0.0;
-  FloatColumnVector colsum = a.abs ().sum ().row (0);
+  FloatRowVector colsum = a.abs ().sum ().row (0);
 
   for (octave_idx_type i = 0; i < colsum.numel (); i++)
     {
@@ -863,8 +864,6 @@
                              F77_CMPLX_ARG (z.fortran_vec ()), lwork,
                              tmp_info));
 
-  info = tmp_info;
-
   lwork = static_cast<F77_INT> (std::real (z(0)));
   lwork = (lwork < 2 * nc ? 2 * nc : lwork);
   z.resize (dim_vector (lwork, 1));
@@ -961,13 +960,13 @@
       if (! mattype.ishermitian ())
         ret = finverse (mattype, info, rcon, force, calc_cond);
 
-      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.)
+      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0)
         {
           if (numel () == 1)
-            ret = FloatComplexMatrix (1, 1, 0.);
+            ret = FloatComplexMatrix (1, 1, 0.0);
           else
             ret = FloatComplexMatrix (rows (), columns (),
-                                      FloatComplex (octave::numeric_limits<float>::Inf (), 0.));
+                                      FloatComplex (octave::numeric_limits<float>::Inf (), 0.0));
         }
     }
 
@@ -1107,232 +1106,40 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 FloatComplexMatrix
 FloatComplexMatrix::fourier (void) const
 {
-  FloatComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatComplexMatrix::ifourier (void) const
 {
-  FloatComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  for (octave_idx_type j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<float> (npts);
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatComplexMatrix::fourier2d (void) const
 {
-  FloatComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<FloatComplex> tmp (dim_vector (npts, 1));
-  FloatComplex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i];
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatComplexMatrix::ifourier2d (void) const
 {
-  FloatComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = *this;
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  for (F77_INT j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<float> (npts);
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<FloatComplex> tmp (dim_vector (npts, 1));
-  FloatComplex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i] / static_cast<float> (npts);
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 #endif
@@ -1397,7 +1204,7 @@
       FloatComplexMatrix atmp = *this;
       FloatComplex *tmp_data = atmp.fortran_vec ();
 
-      float anorm = 0;
+      float anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1418,23 +1225,26 @@
         }
       else
         {
-          Array<FloatComplex> z (dim_vector (2 * nc, 1));
-          FloatComplex *pz = z.fortran_vec ();
-          Array<float> rz (dim_vector (nc, 1));
-          float *prz = rz.fortran_vec ();
-
-          F77_XFCN (cpocon, CPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
-                                     nr, F77_CMPLX_ARG (tmp_data), nr, anorm,
-                                     rcon, F77_CMPLX_ARG (pz), prz, tmp_info
-                                     F77_CHAR_ARG_LEN (1)));
-
-          info = tmp_info;
-
-          if (info != 0)
-            rcon = 0.0;
+          if (calc_cond)
+            {
+              Array<FloatComplex> z (dim_vector (2 * nc, 1));
+              FloatComplex *pz = z.fortran_vec ();
+              Array<float> rz (dim_vector (nc, 1));
+              float *prz = rz.fortran_vec ();
+
+              F77_XFCN (cpocon, CPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
+                                         nr, F77_CMPLX_ARG (tmp_data), nr, anorm,
+                                         rcon, F77_CMPLX_ARG (pz), prz, tmp_info
+                                         F77_CHAR_ARG_LEN (1)));
+
+              info = tmp_info;
+
+              if (info != 0)
+                rcon = 0.0;
+            }
 
           for (F77_INT i = 0; i < nc; i++)
-            retval *= atmp (i,i);
+            retval *= atmp(i,i);
 
           retval = retval.square ();
         }
@@ -1648,7 +1458,7 @@
               Array<F77_INT> ipvt (dim_vector (nr, 1));
               F77_INT *pipvt = ipvt.fortran_vec ();
 
-              if (anorm < 0.)
+              if (anorm < 0.0)
                 anorm = norm1 (atmp);
 
               Array<FloatComplex> z (dim_vector (2 * nc, 1));
@@ -1660,7 +1470,8 @@
               if (octave::math::isnan (anorm))
                 info = -1;
               else
-                F77_XFCN (cgetrf, CGETRF, (nr, nr, F77_CMPLX_ARG (tmp_data), nr, pipvt, info));
+                F77_XFCN (cgetrf, CGETRF, (nr, nr, F77_CMPLX_ARG (tmp_data),
+                                           nr, pipvt, info));
 
               if (info != 0)
                 {
@@ -1713,7 +1524,7 @@
 
       if (typ == MatrixType::Permuted_Upper || typ == MatrixType::Upper)
         {
-          rcon = 1.;
+          rcon = 1.0;
           info = 0;
 
           if (typ == MatrixType::Permuted_Upper)
@@ -1815,7 +1626,7 @@
 
       if (typ == MatrixType::Permuted_Lower || typ == MatrixType::Lower)
         {
-          rcon = 1.;
+          rcon = 1.0;
           info = 0;
 
           if (typ == MatrixType::Permuted_Lower)
@@ -1915,8 +1726,8 @@
     {
       volatile int typ = mattype.type ();
 
-      // Calculate the norm of the matrix, for later use.
-      float anorm = -1.;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      float anorm = -1.0;
 
       if (typ == MatrixType::Hermitian)
         {
@@ -1926,7 +1737,9 @@
           FloatComplexMatrix atmp = *this;
           FloatComplex *tmp_data = atmp.fortran_vec ();
 
-          anorm = norm1 (atmp);
+          // The norm of the matrix for later use when determining rcon.
+          if (calc_cond)
+            anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
 
@@ -2013,7 +1826,7 @@
           float *prz = rz.fortran_vec ();
 
           // Calculate the norm of the matrix, for later use.
-          if (anorm < 0.)
+          if (calc_cond && anorm < 0.0)
             anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
@@ -2024,8 +1837,8 @@
             info = -2;
           else
             {
-              F77_XFCN (cgetrf, CGETRF, (nr, nr, F77_CMPLX_ARG (tmp_data), nr, pipvt,
-                                         tmp_info));
+              F77_XFCN (cgetrf, CGETRF, (nr, nr, F77_CMPLX_ARG (tmp_data),
+                                         nr, pipvt, tmp_info));
 
               info = tmp_info;
             }
@@ -2047,8 +1860,7 @@
             {
               if (calc_cond)
                 {
-                  // Now calculate the condition number for
-                  // non-singular matrix.
+                  // Calculate the condition number for non-singular matrix.
                   char job = '1';
                   F77_XFCN (cgecon, CGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
                                              nc, F77_CMPLX_ARG (tmp_data), nr, anorm,
@@ -2469,13 +2281,12 @@
 {
   FloatComplexMatrix retval;
 
-  F77_INT nrhs = octave::to_f77_int (b.cols ());
-
   F77_INT m = octave::to_f77_int (rows ());
   F77_INT n = octave::to_f77_int (cols ());
 
   F77_INT b_nr = octave::to_f77_int (b.rows ());
   F77_INT b_nc = octave::to_f77_int (b.cols ());
+  F77_INT nrhs = b_nc;  // alias for code readability
 
   if (m != b_nr)
     (*current_liboctave_error_handler)
@@ -2532,7 +2343,6 @@
       float dminmn = static_cast<float> (minmn);
       float dsmlsizp1 = static_cast<float> (smlsiz+1);
       float tmp = octave::math::log2 (dminmn / dsmlsizp1);
-      float anorm = 0.0;
 
       F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
       if (nlvl < 0)
@@ -2597,12 +2407,11 @@
       lwork = static_cast<F77_INT> (std::real (work(0)));
       work.resize (dim_vector (lwork, 1));
 
-      anorm = norm1 (*this);
+      float anorm = norm1 (*this);
 
       if (octave::math::isinf (anorm))
         {
           rcon = 0.0;
-          octave::warn_singular_matrix ();
           retval = FloatComplexMatrix (n, b_nc, 0.0);
         }
       else if (octave::math::isnan (anorm))
@@ -3848,7 +3657,7 @@
   // The last column is unused so temporarily store delta there
   FloatComplex *delta = &retval(0, n-1);
   for (octave_idx_type i = 0; i < m; i++)
-    delta[i] = (x2(i) - x1(i)) / (n - 1.0f);
+    delta[i] = (x1(i) == x2(i)) ? 0 : (x2(i) - x1(i)) / (n - 1.0f);
 
   for (octave_idx_type j = 1; j < n-1; j++)
     for (octave_idx_type i = 0; i < m; i++)
--- a/liboctave/array/fCNDArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fCNDArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,8 @@
 #endif
 
 #include <complex>
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "f77-fcn.h"
@@ -186,293 +187,58 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 FloatComplexNDArray
 FloatComplexNDArray::fourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return FloatComplexNDArray ();
-
-  FloatComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (FloatComplex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (tmp), F77_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i];
-        }
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatComplexNDArray::ifourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return FloatComplexNDArray ();
-
-  FloatComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (FloatComplex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (tmp), F77_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i] /
-                                                   static_cast<float> (npts);
-        }
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatComplexNDArray::fourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatComplexNDArray::ifourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<float> (npts);
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatComplexNDArray::fourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatComplexNDArray::ifourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<float> (npts);
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 #endif
--- a/liboctave/array/fCRowVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fCRowVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
@@ -434,7 +435,7 @@
 
   retval(0) = x1;
 
-  FloatComplex delta = (x2 - x1) / (n - 1.0f);
+  FloatComplex delta = (x1 == x2) ? 0 : (x2 - x1) / (n - 1.0f);
   for (octave_idx_type i = 1; i < n-1; i++)
     retval(i) = x1 + static_cast<float> (i)*delta;
 
--- a/liboctave/array/fColVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fColVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
--- a/liboctave/array/fDiagMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fDiagMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "lo-error.h"
@@ -184,7 +184,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return row (static_cast<octave_idx_type>(0));
+    return row (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return row (rows () - 1);
   else
@@ -214,7 +214,7 @@
 
   char c = *s;
   if (c == 'f' || c == 'F')
-    return column (static_cast<octave_idx_type>(0));
+    return column (static_cast<octave_idx_type> (0));
   else if (c == 'l' || c == 'L')
     return column (cols () - 1);
   else
--- a/liboctave/array/fMatrix.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fMatrix.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,8 +27,9 @@
 #endif
 
 #include <algorithm>
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "DET.h"
@@ -435,7 +436,7 @@
 norm1 (const FloatMatrix& a)
 {
   float anorm = 0.0;
-  FloatColumnVector colsum = a.abs ().sum ().row (0);
+  FloatRowVector colsum = a.abs ().sum ().row (0);
 
   for (octave_idx_type i = 0; i < colsum.numel (); i++)
     {
@@ -578,8 +579,6 @@
   F77_XFCN (sgetri, SGETRI, (nc, tmp_data, nr, pipvt,
                              z.fortran_vec (), lwork, tmp_info));
 
-  info = tmp_info;
-
   lwork = static_cast<F77_INT> (z(0));
   lwork = (lwork < 4 * nc ? 4 * nc : lwork);
   z.resize (dim_vector (lwork, 1));
@@ -588,8 +587,8 @@
   info = 0;
   tmp_info = 0;
 
-  // Calculate the norm of the matrix, for later use.
-  float anorm = 0;
+  // Calculate the norm of the matrix for later use when determining rcon.
+  float anorm;
   if (calc_cond)
     anorm = norm1 (retval);
 
@@ -669,8 +668,8 @@
       if (! mattype.ishermitian ())
         ret = finverse (mattype, info, rcon, force, calc_cond);
 
-      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.
-          && ! (numel () == 1))
+      if ((calc_cond || mattype.ishermitian ()) && rcon == 0.0
+          && (numel () != 1))
         ret = FloatMatrix (rows (), columns (),
                            octave::numeric_limits<float>::Inf ());
     }
@@ -805,232 +804,40 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 FloatComplexMatrix
 FloatMatrix::fourier (void) const
 {
-  FloatComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = octave::to_f77_int (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = FloatComplexMatrix (*this);
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatMatrix::ifourier (void) const
 {
-  FloatComplexMatrix retval;
-
-  octave_idx_type nr = rows ();
-  octave_idx_type nc = cols ();
-  octave_idx_type nsamples;
-
-  F77_INT npts;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = octave::to_f77_int (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = F77_INT (nr);
-      nsamples = nc;
-    }
-
-  octave_idx_type nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = FloatComplexMatrix (*this);
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  for (octave_idx_type j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<float> (npts);
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatMatrix::fourier2d (void) const
 {
-  FloatComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = FloatComplexMatrix (*this);
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<FloatComplex> tmp (dim_vector (npts, 1));
-  FloatComplex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i];
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 FloatComplexMatrix
 FloatMatrix::ifourier2d (void) const
 {
-  FloatComplexMatrix retval;
-
-  F77_INT nr = octave::to_f77_int (rows ());
-  F77_INT nc = octave::to_f77_int (cols ());
-
-  F77_INT npts, nsamples;
-
-  if (nr == 1 || nc == 1)
-    {
-      npts = (nr > nc ? nr : nc);
-      nsamples = 1;
-    }
-  else
-    {
-      npts = nr;
-      nsamples = nc;
-    }
-
-  F77_INT nn = 4*npts+15;
-
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  retval = FloatComplexMatrix (*this);
-  FloatComplex *tmp_data = retval.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (&tmp_data[npts*j]),
-                               F77_CMPLX_ARG (pwsave));
-    }
-
-  for (F77_INT j = 0; j < npts*nsamples; j++)
-    tmp_data[j] = tmp_data[j] / static_cast<float> (npts);
-
-  npts = nc;
-  nsamples = nr;
-  nn = 4*npts+15;
-
-  wsave.resize (dim_vector (nn, 1));
-  pwsave = wsave.fortran_vec ();
-
-  Array<FloatComplex> tmp (dim_vector (npts, 1));
-  FloatComplex *prow = tmp.fortran_vec ();
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (F77_INT j = 0; j < nsamples; j++)
-    {
-      octave_quit ();
-
-      for (F77_INT i = 0; i < npts; i++)
-        prow[i] = tmp_data[i*nr + j];
-
-      F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-      for (F77_INT i = 0; i < npts; i++)
-        tmp_data[i*nr + j] = prow[i] / static_cast<float> (npts);
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+
+  return FloatComplexMatrix ();
 }
 
 #endif
@@ -1095,7 +902,8 @@
       FloatMatrix atmp = *this;
       float *tmp_data = atmp.fortran_vec ();
 
-      float anorm = 0;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      float anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1116,23 +924,26 @@
         }
       else
         {
-          Array<float> z (dim_vector (3 * nc, 1));
-          float *pz = z.fortran_vec ();
-          Array<F77_INT> iz (dim_vector (nc, 1));
-          F77_INT *piz = iz.fortran_vec ();
-
-          F77_XFCN (spocon, SPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
-                                     nr, tmp_data, nr, anorm,
-                                     rcon, pz, piz, tmp_info
-                                     F77_CHAR_ARG_LEN (1)));
-
-          info = tmp_info;
-
-          if (info != 0)
-            rcon = 0.0;
+          if (calc_cond)
+            {
+              Array<float> z (dim_vector (3 * nc, 1));
+              float *pz = z.fortran_vec ();
+              Array<F77_INT> iz (dim_vector (nc, 1));
+              F77_INT *piz = iz.fortran_vec ();
+
+              F77_XFCN (spocon, SPOCON, (F77_CONST_CHAR_ARG2 (&job, 1),
+                                         nr, tmp_data, nr, anorm,
+                                         rcon, pz, piz, tmp_info
+                                         F77_CHAR_ARG_LEN (1)));
+
+              info = tmp_info;
+
+              if (info != 0)
+                rcon = 0.0;
+            }
 
           for (F77_INT i = 0; i < nc; i++)
-            retval *= atmp (i,i);
+            retval *= atmp(i,i);
 
           retval = retval.square ();
         }
@@ -1151,8 +962,8 @@
       info = 0;
       F77_INT tmp_info = 0;
 
-      // Calculate the norm of the matrix, for later use.
-      float anorm = 0;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      float anorm;
       if (calc_cond)
         anorm = norm1 (*this);
 
@@ -1339,7 +1150,7 @@
               Array<F77_INT> ipvt (dim_vector (nr, 1));
               F77_INT *pipvt = ipvt.fortran_vec ();
 
-              if (anorm < 0.)
+              if (anorm < 0.0)
                 anorm = norm1 (atmp);
 
               Array<float> z (dim_vector (4 * nc, 1));
@@ -1400,7 +1211,7 @@
 
       if (typ == MatrixType::Permuted_Upper || typ == MatrixType::Upper)
         {
-          rcon = 1.;
+          rcon = 1.0;
           info = 0;
 
           if (typ == MatrixType::Permuted_Upper)
@@ -1503,7 +1314,7 @@
 
       if (typ == MatrixType::Permuted_Lower || typ == MatrixType::Lower)
         {
-          rcon = 1.;
+          rcon = 1.0;
           info = 0;
 
           if (typ == MatrixType::Permuted_Lower)
@@ -1603,8 +1414,8 @@
     {
       volatile int typ = mattype.type ();
 
-      // Calculate the norm of the matrix, for later use.
-      float anorm = -1.;
+      // Calculate the norm of the matrix for later use when determining rcon.
+      float anorm = -1.0;
 
       if (typ == MatrixType::Hermitian)
         {
@@ -1614,7 +1425,9 @@
           FloatMatrix atmp = *this;
           float *tmp_data = atmp.fortran_vec ();
 
-          anorm = norm1 (atmp);
+          // The norm of the matrix for later use when determining rcon.
+          if (calc_cond)
+            anorm = norm1 (atmp);
 
           F77_INT tmp_info = 0;
 
@@ -1695,7 +1508,7 @@
           FloatMatrix atmp = *this;
           float *tmp_data = atmp.fortran_vec ();
 
-          if (anorm < 0.0)
+          if (calc_cond && anorm < 0.0)
             anorm = norm1 (atmp);
 
           Array<float> z (dim_vector (4 * nc, 1));
@@ -1726,8 +1539,7 @@
             {
               if (calc_cond)
                 {
-                  // Now calculate the condition number for
-                  // non-singular matrix.
+                  // Calculate the condition number for non-singular matrix.
                   char job = '1';
                   F77_XFCN (sgecon, SGECON, (F77_CONST_CHAR_ARG2 (&job, 1),
                                              nc, tmp_data, nr, anorm,
@@ -2127,13 +1939,12 @@
 {
   FloatMatrix retval;
 
-  F77_INT nrhs = octave::to_f77_int (b.cols ());
-
   F77_INT m = octave::to_f77_int (rows ());
   F77_INT n = octave::to_f77_int (cols ());
 
   F77_INT b_nr = octave::to_f77_int (b.rows ());
   F77_INT b_nc = octave::to_f77_int (b.cols ());
+  F77_INT nrhs = b_nc;  // alias for code readability
 
   if (m != b_nr)
     (*current_liboctave_error_handler)
@@ -2188,7 +1999,6 @@
       float dminmn = static_cast<float> (minmn);
       float dsmlsizp1 = static_cast<float> (smlsiz+1);
       float tmp = octave::math::log2 (dminmn / dsmlsizp1);
-      float anorm = 0.0;
 
       F77_INT nlvl = static_cast<F77_INT> (tmp) + 1;
       if (nlvl < 0)
@@ -2250,12 +2060,11 @@
       lwork = static_cast<F77_INT> (work(0));
       work.resize (dim_vector (lwork, 1));
 
-      anorm = norm1 (*this);
+      float anorm = norm1 (*this);
 
       if (octave::math::isinf (anorm))
         {
           rcon = 0.0;
-          octave::warn_singular_matrix ();
           retval = FloatMatrix (n, b_nc, 0.0);
         }
       else if (octave::math::isnan (anorm))
@@ -3215,7 +3024,7 @@
   // The last column is unused so temporarily store delta there
   float *delta = &retval(0, n-1);
   for (octave_idx_type i = 0; i < m; i++)
-    delta[i] = (x2(i) - x1(i)) / (n - 1);
+    delta[i] = (x1(i) == x2(i)) ? 0 : (x2(i) - x1(i)) / (n - 1);
 
   for (octave_idx_type j = 1; j < n-1; j++)
     for (octave_idx_type i = 0; i < m; i++)
--- a/liboctave/array/fNDArray.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fNDArray.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,9 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 
 #include "Array-util.h"
 #include "f77-fcn.h"
@@ -185,293 +186,57 @@
 
 #else
 
-#include "lo-fftpack-proto.h"
-
 FloatComplexNDArray
 FloatNDArray::fourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return FloatComplexNDArray ();
-
-  FloatComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (FloatComplex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (tmp), F77_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i];
-        }
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatNDArray::ifourier (int dim) const
 {
-  dim_vector dv = dims ();
-
-  if (dim > dv.ndims () || dim < 0)
-    return FloatComplexNDArray ();
-
-  FloatComplexNDArray retval (dv);
-  octave_idx_type npts = dv(dim);
-  octave_idx_type nn = 4*npts+15;
-  Array<FloatComplex> wsave (dim_vector (nn, 1));
-  FloatComplex *pwsave = wsave.fortran_vec ();
-
-  OCTAVE_LOCAL_BUFFER (FloatComplex, tmp, npts);
-
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < dim; i++)
-    stride *= dv(i);
-
-  octave_idx_type howmany = numel () / npts;
-  howmany = (stride == 1 ? howmany : (howmany > stride ? stride : howmany));
-  octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-  octave_idx_type dist = (stride == 1 ? npts : 1);
-
-  F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-  for (octave_idx_type k = 0; k < nloop; k++)
-    {
-      for (octave_idx_type j = 0; j < howmany; j++)
-        {
-          octave_quit ();
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            tmp[i] = elem ((i + k*npts)*stride + j*dist);
-
-          F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (tmp), F77_CMPLX_ARG (pwsave));
-
-          for (octave_idx_type i = 0; i < npts; i++)
-            retval((i + k*npts)*stride + j*dist) = tmp[i] /
-                                                   static_cast<float> (npts);
-        }
-    }
-
-  return retval;
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatNDArray::fourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatNDArray::ifourier2d (void) const
 {
-  dim_vector dv = dims ();
-  dim_vector dv2 (dv(0), dv(1));
-  int rank = 2;
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv2(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<float> (npts);
-            }
-        }
-
-      stride *= dv2(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatNDArray::fourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
-
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftf, CFFTF) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) = prow[l];
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 FloatComplexNDArray
 FloatNDArray::ifourierNd (void) const
 {
-  dim_vector dv = dims ();
-  int rank = dv.ndims ();
-  FloatComplexNDArray retval (*this);
-  octave_idx_type stride = 1;
-
-  for (int i = 0; i < rank; i++)
-    {
-      octave_idx_type npts = dv(i);
-      octave_idx_type nn = 4*npts+15;
-      Array<FloatComplex> wsave (dim_vector (nn, 1));
-      FloatComplex *pwsave = wsave.fortran_vec ();
-      Array<FloatComplex> row (dim_vector (npts, 1));
-      FloatComplex *prow = row.fortran_vec ();
-
-      octave_idx_type howmany = numel () / npts;
-      howmany = (stride == 1 ? howmany
-                             : (howmany > stride ? stride : howmany));
-      octave_idx_type nloop = (stride == 1 ? 1 : numel () / npts / stride);
-      octave_idx_type dist = (stride == 1 ? npts : 1);
-
-      F77_FUNC (cffti, CFFTI) (npts, F77_CMPLX_ARG (pwsave));
+  (*current_liboctave_error_handler)
+    ("support for FFTW was unavailable or disabled when liboctave was built");
 
-      for (octave_idx_type k = 0; k < nloop; k++)
-        {
-          for (octave_idx_type j = 0; j < howmany; j++)
-            {
-              octave_quit ();
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                prow[l] = retval((l + k*npts)*stride + j*dist);
-
-              F77_FUNC (cfftb, CFFTB) (npts, F77_CMPLX_ARG (prow), F77_CMPLX_ARG (pwsave));
-
-              for (octave_idx_type l = 0; l < npts; l++)
-                retval((l + k*npts)*stride + j*dist) =
-                  prow[l] / static_cast<float> (npts);
-            }
-        }
-
-      stride *= dv(i);
-    }
-
-  return retval;
+  return FloatComplexNDArray ();
 }
 
 #endif
@@ -726,7 +491,7 @@
         // FIXME: is there something better to do?  Should we warn the user?
         ival = 0;
 
-      retval.elem (i) = static_cast<char>(ival);
+      retval.elem (i) = static_cast<char> (ival);
     }
 
   if (rb.isempty ())
--- a/liboctave/array/fRowVector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/fRowVector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,8 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <istream>
+#include <ostream>
 
 #include "Array-util.h"
 #include "functor.h"
@@ -275,7 +276,7 @@
 
   retval(0) = x1;
 
-  float delta = (x2 - x1) / (n - 1);
+  float delta = (x1 == x2) ? 0 : (x2 - x1) / (n - 1);
   for (octave_idx_type i = 1; i < n-1; i++)
     retval(i) = x1 + i*delta;
 
--- a/liboctave/array/idx-vector.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/idx-vector.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,7 @@
 
 #include <cstdlib>
 
-#include <iostream>
+#include <ostream>
 
 #include "idx-vector.h"
 #include "Array.h"
--- a/liboctave/array/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/array/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -132,8 +132,4 @@
   $(FFTW_XCPPFLAGS) \
   $(SPARSE_XCPPFLAGS)
 
-%canon_reldir%_libarray_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_libarray_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/libarray.la
--- a/liboctave/external/blas-xtra/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/external/blas-xtra/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
   %reldir%/zdconv2.f
 
 XERBLA_SRC = \
-  %reldir%/xerbla.c
+  %reldir%/xerbla.cc
 
 %canon_reldir%_libxerbla_la_SOURCES = $(XERBLA_SRC)
 
--- a/liboctave/external/blas-xtra/xerbla.c	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
-
-Copyright (C) 1996-2018 John W. Eaton
-
-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 <stdio.h>
-
-#include "f77-fcn.h"
-
-typedef void (*xerbla_handler_fptr) (void);
-
-/* Pointer to function to call to handle error.  In the Octave
-   interpreter we set this to a function that throws an exception and
-   transfers control to the enclosing try/catch block.  That is
-   typically at the top-level REPL.
-
-   We must use a function pointer instead of simply calling error
-   directly here because this function is called by LAPACK and BLAS
-   subroutines.  To build shared libraries of those packages on Windows
-   requires that all symbols be known when the shared library is
-   constructed.  If we call error directly, that would mean that the
-   BLAS and LAPACK libraries would have to depend on Octave...  */
-
-static xerbla_handler_fptr xerbla_handler = NULL;
-
-void
-octave_set_xerbla_handler (xerbla_handler_fptr fcn)
-{
-  xerbla_handler = fcn;
-}
-
-/* Replacement for BLAS and LAPACK XERBLA subroutine that calls an
-   optionally installed handler function.  */
-
-F77_RET_T
-F77_FUNC (xerbla, XERBLA) (F77_CONST_CHAR_ARG_DEF (s_arg, len),
-                           const F77_INT *info
-                           F77_CHAR_ARG_LEN_DEF (len))
-{
-  const char *s = F77_CHAR_ARG_USE (s_arg);
-  int slen = F77_CHAR_ARG_LEN_USE (s_arg, len);
-
-  fprintf (stderr, "%.*s: parameter number %ld is invalid\n", slen, s,
-           (long) (*info));
-
-   if (xerbla_handler)
-     (*xerbla_handler) ();
-
-  F77_RETURN (0)
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/blas-xtra/xerbla.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,72 @@
+/*
+
+Copyright (C) 1996-2018 John W. Eaton
+
+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 "f77-fcn.h"
+#include "lo-blas-proto.h"
+
+typedef void (*xerbla_handler_fptr) (void);
+
+/* Pointer to function to call to handle error.  In the Octave
+   interpreter we set this to a function that throws an exception and
+   transfers control to the enclosing try/catch block.  That is
+   typically at the top-level REPL.
+
+   We must use a function pointer instead of simply calling error
+   directly here because this function is called by LAPACK and BLAS
+   subroutines.  To build shared libraries of those packages on Windows
+   requires that all symbols be known when the shared library is
+   constructed.  If we call error directly, that would mean that the
+   BLAS and LAPACK libraries would have to depend on Octave...  */
+
+static xerbla_handler_fptr xerbla_handler = nullptr;
+
+extern "C" void
+octave_set_xerbla_handler (xerbla_handler_fptr fcn)
+{
+  xerbla_handler = fcn;
+}
+
+/* Replacement for BLAS and LAPACK XERBLA subroutine that calls an
+   optionally installed handler function.  */
+
+F77_RET_T
+F77_FUNC (xerbla, XERBLA) (F77_CONST_CHAR_ARG_DEF (s_arg, len),
+                           const F77_INT& info
+                           F77_CHAR_ARG_LEN_DEF (len))
+{
+  const char *s = F77_CHAR_ARG_USE (s_arg);
+  int slen = F77_CHAR_ARG_LEN_USE (s_arg, len);
+
+  std::cerr << std::string (s, slen) << ": parameter number " << info
+            << " is invalid" << std::endl;
+
+   if (xerbla_handler)
+     (*xerbla_handler) ();
+
+  F77_RETURN (0)
+}
--- a/liboctave/external/fftpack/cfftb.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-      subroutine cfftb (n,c,wsave)
-      dimension       c(*)       ,wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call cfftb1 (n,c,wsave,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/cfftb1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-      subroutine cfftb1 (n,c,ch,wa,ifac)
-      dimension       ch(*)      ,c(*)       ,wa(*)      ,ifac(*)
-      nf = ifac(2)
-      na = 0
-      l1 = 1
-      iw = 1
-      do 116 k1=1,nf
-         ip = ifac(k1+2)
-         l2 = ip*l1
-         ido = n/l2
-         idot = ido+ido
-         idl1 = idot*l1
-         if (ip .ne. 4) go to 103
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         if (na .ne. 0) go to 101
-         call passb4 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3))
-         go to 102
-  101    call passb4 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3))
-  102    na = 1-na
-         go to 115
-  103    if (ip .ne. 2) go to 106
-         if (na .ne. 0) go to 104
-         call passb2 (idot,l1,c,ch,wa(iw))
-         go to 105
-  104    call passb2 (idot,l1,ch,c,wa(iw))
-  105    na = 1-na
-         go to 115
-  106    if (ip .ne. 3) go to 109
-         ix2 = iw+idot
-         if (na .ne. 0) go to 107
-         call passb3 (idot,l1,c,ch,wa(iw),wa(ix2))
-         go to 108
-  107    call passb3 (idot,l1,ch,c,wa(iw),wa(ix2))
-  108    na = 1-na
-         go to 115
-  109    if (ip .ne. 5) go to 112
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         ix4 = ix3+idot
-         if (na .ne. 0) go to 110
-         call passb5 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-         go to 111
-  110    call passb5 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-  111    na = 1-na
-         go to 115
-  112    if (na .ne. 0) go to 113
-         call passb (nac,idot,ip,l1,idl1,c,c,c,ch,ch,wa(iw))
-         go to 114
-  113    call passb (nac,idot,ip,l1,idl1,ch,ch,ch,c,c,wa(iw))
-  114    if (nac .ne. 0) na = 1-na
-  115    l1 = l2
-         iw = iw+(ip-1)*idot
-  116 continue
-      if (na .eq. 0) return
-      n2 = n+n
-      do 117 i=1,n2
-         c(i) = ch(i)
-  117 continue
-      return
-      end
--- a/liboctave/external/fftpack/cfftf.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-      subroutine cfftf (n,c,wsave)
-      dimension       c(*)       ,wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call cfftf1 (n,c,wsave,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/cfftf1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-      subroutine cfftf1 (n,c,ch,wa,ifac)
-      dimension       ch(*)      ,c(*)       ,wa(*)      ,ifac(*)
-      nf = ifac(2)
-      na = 0
-      l1 = 1
-      iw = 1
-      do 116 k1=1,nf
-         ip = ifac(k1+2)
-         l2 = ip*l1
-         ido = n/l2
-         idot = ido+ido
-         idl1 = idot*l1
-         if (ip .ne. 4) go to 103
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         if (na .ne. 0) go to 101
-         call passf4 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3))
-         go to 102
-  101    call passf4 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3))
-  102    na = 1-na
-         go to 115
-  103    if (ip .ne. 2) go to 106
-         if (na .ne. 0) go to 104
-         call passf2 (idot,l1,c,ch,wa(iw))
-         go to 105
-  104    call passf2 (idot,l1,ch,c,wa(iw))
-  105    na = 1-na
-         go to 115
-  106    if (ip .ne. 3) go to 109
-         ix2 = iw+idot
-         if (na .ne. 0) go to 107
-         call passf3 (idot,l1,c,ch,wa(iw),wa(ix2))
-         go to 108
-  107    call passf3 (idot,l1,ch,c,wa(iw),wa(ix2))
-  108    na = 1-na
-         go to 115
-  109    if (ip .ne. 5) go to 112
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         ix4 = ix3+idot
-         if (na .ne. 0) go to 110
-         call passf5 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-         go to 111
-  110    call passf5 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-  111    na = 1-na
-         go to 115
-  112    if (na .ne. 0) go to 113
-         call passf (nac,idot,ip,l1,idl1,c,c,c,ch,ch,wa(iw))
-         go to 114
-  113    call passf (nac,idot,ip,l1,idl1,ch,ch,ch,c,c,wa(iw))
-  114    if (nac .ne. 0) na = 1-na
-  115    l1 = l2
-         iw = iw+(ip-1)*idot
-  116 continue
-      if (na .eq. 0) return
-      n2 = n+n
-      do 117 i=1,n2
-         c(i) = ch(i)
-  117 continue
-      return
-      end
--- a/liboctave/external/fftpack/cffti.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-      subroutine cffti (n,wsave)
-      dimension       wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call cffti1 (n,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/cffti1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-      subroutine cffti1 (n,wa,ifac)
-      dimension       wa(*)      ,ifac(*)    ,ntryh(4)
-      data ntryh(1),ntryh(2),ntryh(3),ntryh(4)/3,4,2,5/
-      nl = n
-      nf = 0
-      j = 0
-  101 j = j+1
-      if (j-4) 102,102,103
-  102 ntry = ntryh(j)
-      go to 104
-  103 ntry = ntry+2
-  104 nq = nl/ntry
-      nr = nl-ntry*nq
-      if (nr) 101,105,101
-  105 nf = nf+1
-      ifac(nf+2) = ntry
-      nl = nq
-      if (ntry .ne. 2) go to 107
-      if (nf .eq. 1) go to 107
-      do 106 i=2,nf
-         ib = nf-i+2
-         ifac(ib+2) = ifac(ib+1)
-  106 continue
-      ifac(3) = 2
-  107 if (nl .ne. 1) go to 104
-      ifac(1) = n
-      ifac(2) = nf
-      tpi = 6.28318530717959
-      argh = tpi/dble(n)
-      i = 2
-      l1 = 1
-      do 110 k1=1,nf
-         ip = ifac(k1+2)
-         ld = 0
-         l2 = l1*ip
-         ido = n/l2
-         idot = ido+ido+2
-         ipm = ip-1
-         do 109 j=1,ipm
-            i1 = i
-            wa(i-1) = 1.
-            wa(i) = 0.
-            ld = ld+l1
-            fi = 0.
-            argld = dble(ld)*argh
-            do 108 ii=4,idot,2
-               i = i+2
-               fi = fi+1.
-               arg = fi*argld
-               wa(i-1) = cos(arg)
-               wa(i) = sin(arg)
-  108       continue
-            if (ip .le. 5) go to 109
-            wa(i1-1) = wa(i-1)
-            wa(i1) = wa(i)
-  109    continue
-         l1 = l2
-  110 continue
-      return
-      end
--- a/liboctave/external/fftpack/fftpack.doc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,865 +0,0 @@
-
-                      FFTPACK
-
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-                  version 4  april 1985
-
-     a package of fortran subprograms for the fast fourier
-      transform of periodic and other symmetric sequences
-
-                         by
-
-                  paul n swarztrauber
-
-  national center for atmospheric research  boulder,colorado 80307
-
-   which is sponsored by the national science foundation
-
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-
-this package consists of programs which perform fast fourier
-transforms for both complex and real periodic sequences and
-certain other symmetric sequences that are listed below.
-
-1.   rffti     initialize  rfftf and rfftb
-2.   rfftf     forward transform of a real periodic sequence
-3.   rfftb     backward transform of a real coefficient array
-
-4.   ezffti    initialize ezfftf and ezfftb
-5.   ezfftf    a simplified real periodic forward transform
-6.   ezfftb    a simplified real periodic backward transform
-
-7.   sinti     initialize sint
-8.   sint      sine transform of a real odd sequence
-
-9.   costi     initialize cost
-10.  cost      cosine transform of a real even sequence
-
-11.  sinqi     initialize sinqf and sinqb
-12.  sinqf     forward sine transform with odd wave numbers
-13.  sinqb     unnormalized inverse of sinqf
-
-14.  cosqi     initialize cosqf and cosqb
-15.  cosqf     forward cosine transform with odd wave numbers
-16.  cosqb     unnormalized inverse of cosqf
-
-17.  cffti     initialize cfftf and cfftb
-18.  cfftf     forward transform of a complex periodic sequence
-19.  cfftb     unnormalized inverse of cfftf
-
-
-******************************************************************
-
-subroutine rffti(n,wsave)
-
-  ****************************************************************
-
-subroutine rffti initializes the array wsave which is used in
-both rfftf and rfftb. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed.
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 2*n+15.
-        the same work array can be used for both rfftf and rfftb
-        as long as n remains unchanged. different wsave arrays
-        are required for different values of n. the contents of
-        wsave must not be changed between calls of rfftf or rfftb.
-
-******************************************************************
-
-subroutine rfftf(n,r,wsave)
-
-******************************************************************
-
-subroutine rfftf computes the fourier coefficients of a real
-perodic sequence (fourier analysis). the transform is defined
-below at output parameter r.
-
-input parameters
-
-n       the length of the array r to be transformed.  the method
-        is most efficient when n is a product of small primes.
-        n may change so long as different work arrays are provided
-
-r       a real array of length n which contains the sequence
-        to be transformed
-
-wsave   a work array which must be dimensioned at least 2*n+15.
-        in the program that calls rfftf. the wsave array must be
-        initialized by calling subroutine rffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by rfftf and rfftb.
-
-
-output parameters
-
-r       r(1) = the sum from i=1 to i=n of r(i)
-
-        if n is even set l =n/2   , if n is odd set l = (n+1)/2
-
-          then for k = 2,...,l
-
-             r(2*k-2) = the sum from i = 1 to i = n of
-
-                  r(i)*cos((k-1)*(i-1)*2*pi/n)
-
-             r(2*k-1) = the sum from i = 1 to i = n of
-
-                 -r(i)*sin((k-1)*(i-1)*2*pi/n)
-
-        if n is even
-
-             r(n) = the sum from i = 1 to i = n of
-
-                  (-1)**(i-1)*r(i)
-
- *****  note
-             this transform is unnormalized since a call of rfftf
-             followed by a call of rfftb will multiply the input
-             sequence by n.
-
-wsave   contains results which must not be destroyed between
-        calls of rfftf or rfftb.
-
-
-******************************************************************
-
-subroutine rfftb(n,r,wsave)
-
-******************************************************************
-
-subroutine rfftb computes the real perodic sequence from its
-fourier coefficients (fourier synthesis). the transform is defined
-below at output parameter r.
-
-input parameters
-
-n       the length of the array r to be transformed.  the method
-        is most efficient when n is a product of small primes.
-        n may change so long as different work arrays are provided
-
-r       a real array of length n which contains the sequence
-        to be transformed
-
-wsave   a work array which must be dimensioned at least 2*n+15.
-        in the program that calls rfftb. the wsave array must be
-        initialized by calling subroutine rffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by rfftf and rfftb.
-
-
-output parameters
-
-r       for n even and for i = 1,...,n
-
-             r(i) = r(1)+(-1)**(i-1)*r(n)
-
-                  plus the sum from k=2 to k=n/2 of
-
-                   2.*r(2*k-2)*cos((k-1)*(i-1)*2*pi/n)
-
-                  -2.*r(2*k-1)*sin((k-1)*(i-1)*2*pi/n)
-
-        for n odd and for i = 1,...,n
-
-             r(i) = r(1) plus the sum from k=2 to k=(n+1)/2 of
-
-                  2.*r(2*k-2)*cos((k-1)*(i-1)*2*pi/n)
-
-                 -2.*r(2*k-1)*sin((k-1)*(i-1)*2*pi/n)
-
- *****  note
-             this transform is unnormalized since a call of rfftf
-             followed by a call of rfftb will multiply the input
-             sequence by n.
-
-wsave   contains results which must not be destroyed between
-        calls of rfftb or rfftf.
-
-
-******************************************************************
-
-subroutine ezffti(n,wsave)
-
-******************************************************************
-
-subroutine ezffti initializes the array wsave which is used in
-both ezfftf and ezfftb. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed.
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        the same work array can be used for both ezfftf and ezfftb
-        as long as n remains unchanged. different wsave arrays
-        are required for different values of n.
-
-
-******************************************************************
-
-subroutine ezfftf(n,r,azero,a,b,wsave)
-
-******************************************************************
-
-subroutine ezfftf computes the fourier coefficients of a real
-perodic sequence (fourier analysis). the transform is defined
-below at output parameters azero,a and b. ezfftf is a simplified
-but slower version of rfftf.
-
-input parameters
-
-n       the length of the array r to be transformed.  the method
-        is must efficient when n is the product of small primes.
-
-r       a real array of length n which contains the sequence
-        to be transformed. r is not destroyed.
-
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        in the program that calls ezfftf. the wsave array must be
-        initialized by calling subroutine ezffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by ezfftf and ezfftb.
-
-output parameters
-
-azero   the sum from i=1 to i=n of r(i)/n
-
-a,b     for n even b(n/2)=0. and a(n/2) is the sum from i=1 to
-        i=n of (-1)**(i-1)*r(i)/n
-
-        for n even define kmax=n/2-1
-        for n odd  define kmax=(n-1)/2
-
-        then for  k=1,...,kmax
-
-             a(k) equals the sum from i=1 to i=n of
-
-                  2./n*r(i)*cos(k*(i-1)*2*pi/n)
-
-             b(k) equals the sum from i=1 to i=n of
-
-                  2./n*r(i)*sin(k*(i-1)*2*pi/n)
-
-
-******************************************************************
-
-subroutine ezfftb(n,r,azero,a,b,wsave)
-
-******************************************************************
-
-subroutine ezfftb computes a real perodic sequence from its
-fourier coefficients (fourier synthesis). the transform is
-defined below at output parameter r. ezfftb is a simplified
-but slower version of rfftb.
-
-input parameters
-
-n       the length of the output array r.  the method is most
-        efficient when n is the product of small primes.
-
-azero   the constant fourier coefficient
-
-a,b     arrays which contain the remaining fourier coefficients
-        these arrays are not destroyed.
-
-        the length of these arrays depends on whether n is even or
-        odd.
-
-        if n is even n/2    locations are required
-        if n is odd (n-1)/2 locations are required
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        in the program that calls ezfftb. the wsave array must be
-        initialized by calling subroutine ezffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by ezfftf and ezfftb.
-
-
-output parameters
-
-r       if n is even define kmax=n/2
-        if n is odd  define kmax=(n-1)/2
-
-        then for i=1,...,n
-
-             r(i)=azero plus the sum from k=1 to k=kmax of
-
-             a(k)*cos(k*(i-1)*2*pi/n)+b(k)*sin(k*(i-1)*2*pi/n)
-
-********************* complex notation **************************
-
-        for j=1,...,n
-
-        r(j) equals the sum from k=-kmax to k=kmax of
-
-             c(k)*exp(i*k*(j-1)*2*pi/n)
-
-        where
-
-             c(k) = .5*cmplx(a(k),-b(k))   for k=1,...,kmax
-
-             c(-k) = conjg(c(k))
-
-             c(0) = azero
-
-                  and i=sqrt(-1)
-
-*************** amplitude - phase notation ***********************
-
-        for i=1,...,n
-
-        r(i) equals azero plus the sum from k=1 to k=kmax of
-
-             alpha(k)*cos(k*(i-1)*2*pi/n+beta(k))
-
-        where
-
-             alpha(k) = sqrt(a(k)*a(k)+b(k)*b(k))
-
-             cos(beta(k))=a(k)/alpha(k)
-
-             sin(beta(k))=-b(k)/alpha(k)
-
-******************************************************************
-
-subroutine sinti(n,wsave)
-
-******************************************************************
-
-subroutine sinti initializes the array wsave which is used in
-subroutine sint. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed.  the method
-        is most efficient when n+1 is a product of small primes.
-
-output parameter
-
-wsave   a work array with at least int(2.5*n+15) locations.
-        different wsave arrays are required for different values
-        of n. the contents of wsave must not be changed between
-        calls of sint.
-
-******************************************************************
-
-subroutine sint(n,x,wsave)
-
-******************************************************************
-
-subroutine sint computes the discrete fourier sine transform
-of an odd sequence x(i). the transform is defined below at
-output parameter x.
-
-sint is the unnormalized inverse of itself since a call of sint
-followed by another call of sint will multiply the input sequence
-x by 2*(n+1).
-
-the array wsave which is used by subroutine sint must be
-initialized by calling subroutine sinti(n,wsave).
-
-input parameters
-
-n       the length of the sequence to be transformed.  the method
-        is most efficient when n+1 is the product of small primes.
-
-x       an array which contains the sequence to be transformed
-
-
-wsave   a work array with dimension at least int(2.5*n+15)
-        in the program that calls sint. the wsave array must be
-        initialized by calling subroutine sinti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-             x(i)= the sum from k=1 to k=n
-
-                  2*x(k)*sin(k*i*pi/(n+1))
-
-             a call of sint followed by another call of
-             sint will multiply the sequence x by 2*(n+1).
-             hence sint is the unnormalized inverse
-             of itself.
-
-wsave   contains initialization calculations which must not be
-        destroyed between calls of sint.
-
-******************************************************************
-
-subroutine costi(n,wsave)
-
-******************************************************************
-
-subroutine costi initializes the array wsave which is used in
-subroutine cost. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed.  the method
-        is most efficient when n-1 is a product of small primes.
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        different wsave arrays are required for different values
-        of n. the contents of wsave must not be changed between
-        calls of cost.
-
-******************************************************************
-
-subroutine cost(n,x,wsave)
-
-******************************************************************
-
-subroutine cost computes the discrete fourier cosine transform
-of an even sequence x(i). the transform is defined below at output
-parameter x.
-
-cost is the unnormalized inverse of itself since a call of cost
-followed by another call of cost will multiply the input sequence
-x by 2*(n-1). the transform is defined below at output parameter x
-
-the array wsave which is used by subroutine cost must be
-initialized by calling subroutine costi(n,wsave).
-
-input parameters
-
-n       the length of the sequence x. n must be greater than 1.
-        the method is most efficient when n-1 is a product of
-        small primes.
-
-x       an array which contains the sequence to be transformed
-
-wsave   a work array which must be dimensioned at least 3*n+15
-        in the program that calls cost. the wsave array must be
-        initialized by calling subroutine costi(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-            x(i) = x(1)+(-1)**(i-1)*x(n)
-
-             + the sum from k=2 to k=n-1
-
-                 2*x(k)*cos((k-1)*(i-1)*pi/(n-1))
-
-             a call of cost followed by another call of
-             cost will multiply the sequence x by 2*(n-1)
-             hence cost is the unnormalized inverse
-             of itself.
-
-wsave   contains initialization calculations which must not be
-        destroyed between calls of cost.
-
-******************************************************************
-
-subroutine sinqi(n,wsave)
-
-******************************************************************
-
-subroutine sinqi initializes the array wsave which is used in
-both sinqf and sinqb. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed. the method
-        is most efficient when n is a product of small primes.
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        the same work array can be used for both sinqf and sinqb
-        as long as n remains unchanged. different wsave arrays
-        are required for different values of n. the contents of
-        wsave must not be changed between calls of sinqf or sinqb.
-
-******************************************************************
-
-subroutine sinqf(n,x,wsave)
-
-******************************************************************
-
-subroutine sinqf computes the fast fourier transform of quarter
-wave data. that is , sinqf computes the coefficients in a sine
-series representation with only odd wave numbers. the transform
-is defined below at output parameter x.
-
-sinqb is the unnormalized inverse of sinqf since a call of sinqf
-followed by a call of sinqb will multiply the input sequence x
-by 4*n.
-
-the array wsave which is used by subroutine sinqf must be
-initialized by calling subroutine sinqi(n,wsave).
-
-
-input parameters
-
-n       the length of the array x to be transformed.  the method
-        is most efficient when n is a product of small primes.
-
-x       an array which contains the sequence to be transformed
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        in the program that calls sinqf. the wsave array must be
-        initialized by calling subroutine sinqi(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-             x(i) = (-1)**(i-1)*x(n)
-
-                + the sum from k=1 to k=n-1 of
-
-                2*x(k)*sin((2*i-1)*k*pi/(2*n))
-
-             a call of sinqf followed by a call of
-             sinqb will multiply the sequence x by 4*n.
-             therefore sinqb is the unnormalized inverse
-             of sinqf.
-
-wsave   contains initialization calculations which must not
-        be destroyed between calls of sinqf or sinqb.
-
-******************************************************************
-
-subroutine sinqb(n,x,wsave)
-
-******************************************************************
-
-subroutine sinqb computes the fast fourier transform of quarter
-wave data. that is , sinqb computes a sequence from its
-representation in terms of a sine series with odd wave numbers.
-the transform is defined below at output parameter x.
-
-sinqf is the unnormalized inverse of sinqb since a call of sinqb
-followed by a call of sinqf will multiply the input sequence x
-by 4*n.
-
-the array wsave which is used by subroutine sinqb must be
-initialized by calling subroutine sinqi(n,wsave).
-
-
-input parameters
-
-n       the length of the array x to be transformed.  the method
-        is most efficient when n is a product of small primes.
-
-x       an array which contains the sequence to be transformed
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        in the program that calls sinqb. the wsave array must be
-        initialized by calling subroutine sinqi(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-             x(i)= the sum from k=1 to k=n of
-
-               4*x(k)*sin((2k-1)*i*pi/(2*n))
-
-             a call of sinqb followed by a call of
-             sinqf will multiply the sequence x by 4*n.
-             therefore sinqf is the unnormalized inverse
-             of sinqb.
-
-wsave   contains initialization calculations which must not
-        be destroyed between calls of sinqb or sinqf.
-
-******************************************************************
-
-subroutine cosqi(n,wsave)
-
-******************************************************************
-
-subroutine cosqi initializes the array wsave which is used in
-both cosqf and cosqb. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the array to be transformed.  the method
-        is most efficient when n is a product of small primes.
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 3*n+15.
-        the same work array can be used for both cosqf and cosqb
-        as long as n remains unchanged. different wsave arrays
-        are required for different values of n. the contents of
-        wsave must not be changed between calls of cosqf or cosqb.
-
-******************************************************************
-
-subroutine cosqf(n,x,wsave)
-
-******************************************************************
-
-subroutine cosqf computes the fast fourier transform of quarter
-wave data. that is , cosqf computes the coefficients in a cosine
-series representation with only odd wave numbers. the transform
-is defined below at output parameter x
-
-cosqf is the unnormalized inverse of cosqb since a call of cosqf
-followed by a call of cosqb will multiply the input sequence x
-by 4*n.
-
-the array wsave which is used by subroutine cosqf must be
-initialized by calling subroutine cosqi(n,wsave).
-
-
-input parameters
-
-n       the length of the array x to be transformed.  the method
-        is most efficient when n is a product of small primes.
-
-x       an array which contains the sequence to be transformed
-
-wsave   a work array which must be dimensioned at least 3*n+15
-        in the program that calls cosqf. the wsave array must be
-        initialized by calling subroutine cosqi(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-             x(i) = x(1) plus the sum from k=2 to k=n of
-
-                2*x(k)*cos((2*i-1)*(k-1)*pi/(2*n))
-
-             a call of cosqf followed by a call of
-             cosqb will multiply the sequence x by 4*n.
-             therefore cosqb is the unnormalized inverse
-             of cosqf.
-
-wsave   contains initialization calculations which must not
-        be destroyed between calls of cosqf or cosqb.
-
-******************************************************************
-
-subroutine cosqb(n,x,wsave)
-
-******************************************************************
-
-subroutine cosqb computes the fast fourier transform of quarter
-wave data. that is , cosqb computes a sequence from its
-representation in terms of a cosine series with odd wave numbers.
-the transform is defined below at output parameter x.
-
-cosqb is the unnormalized inverse of cosqf since a call of cosqb
-followed by a call of cosqf will multiply the input sequence x
-by 4*n.
-
-the array wsave which is used by subroutine cosqb must be
-initialized by calling subroutine cosqi(n,wsave).
-
-
-input parameters
-
-n       the length of the array x to be transformed.  the method
-        is most efficient when n is a product of small primes.
-
-x       an array which contains the sequence to be transformed
-
-wsave   a work array that must be dimensioned at least 3*n+15
-        in the program that calls cosqb. the wsave array must be
-        initialized by calling subroutine cosqi(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-
-output parameters
-
-x       for i=1,...,n
-
-             x(i)= the sum from k=1 to k=n of
-
-               4*x(k)*cos((2*k-1)*(i-1)*pi/(2*n))
-
-             a call of cosqb followed by a call of
-             cosqf will multiply the sequence x by 4*n.
-             therefore cosqf is the unnormalized inverse
-             of cosqb.
-
-wsave   contains initialization calculations which must not
-        be destroyed between calls of cosqb or cosqf.
-
-******************************************************************
-
-subroutine cffti(n,wsave)
-
-******************************************************************
-
-subroutine cffti initializes the array wsave which is used in
-both cfftf and cfftb. the prime factorization of n together with
-a tabulation of the trigonometric functions are computed and
-stored in wsave.
-
-input parameter
-
-n       the length of the sequence to be transformed
-
-output parameter
-
-wsave   a work array which must be dimensioned at least 4*n+15
-        the same work array can be used for both cfftf and cfftb
-        as long as n remains unchanged. different wsave arrays
-        are required for different values of n. the contents of
-        wsave must not be changed between calls of cfftf or cfftb.
-
-******************************************************************
-
-subroutine cfftf(n,c,wsave)
-
-******************************************************************
-
-subroutine cfftf computes the forward complex discrete fourier
-transform (the fourier analysis). equivalently , cfftf computes
-the fourier coefficients of a complex periodic sequence.
-the transform is defined below at output parameter c.
-
-the transform is not normalized. to obtain a normalized transform
-the output must be divided by n. otherwise a call of cfftf
-followed by a call of cfftb will multiply the sequence by n.
-
-the array wsave which is used by subroutine cfftf must be
-initialized by calling subroutine cffti(n,wsave).
-
-input parameters
-
-
-n      the length of the complex sequence c. the method is
-       more efficient when n is the product of small primes. n
-
-c      a complex array of length n which contains the sequence
-
-wsave   a real work array which must be dimensioned at least 4n+15
-        in the program that calls cfftf. the wsave array must be
-        initialized by calling subroutine cffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by cfftf and cfftb.
-
-output parameters
-
-c      for j=1,...,n
-
-           c(j)=the sum from k=1,...,n of
-
-                 c(k)*exp(-i*(j-1)*(k-1)*2*pi/n)
-
-                       where i=sqrt(-1)
-
-wsave   contains initialization calculations which must not be
-        destroyed between calls of subroutine cfftf or cfftb
-
-******************************************************************
-
-subroutine cfftb(n,c,wsave)
-
-******************************************************************
-
-subroutine cfftb computes the backward complex discrete fourier
-transform (the fourier synthesis). equivalently , cfftb computes
-a complex periodic sequence from its fourier coefficients.
-the transform is defined below at output parameter c.
-
-a call of cfftf followed by a call of cfftb will multiply the
-sequence by n.
-
-the array wsave which is used by subroutine cfftb must be
-initialized by calling subroutine cffti(n,wsave).
-
-input parameters
-
-
-n      the length of the complex sequence c. the method is
-       more efficient when n is the product of small primes.
-
-c      a complex array of length n which contains the sequence
-
-wsave   a real work array which must be dimensioned at least 4n+15
-        in the program that calls cfftb. the wsave array must be
-        initialized by calling subroutine cffti(n,wsave) and a
-        different wsave array must be used for each different
-        value of n. this initialization does not have to be
-        repeated so long as n remains unchanged thus subsequent
-        transforms can be obtained faster than the first.
-        the same wsave array can be used by cfftf and cfftb.
-
-output parameters
-
-c      for j=1,...,n
-
-           c(j)=the sum from k=1,...,n of
-
-                 c(k)*exp(i*(j-1)*(k-1)*2*pi/n)
-
-                       where i=sqrt(-1)
-
-wsave   contains initialization calculations which must not be
-        destroyed between calls of subroutine cfftf or cfftb
-
-
-
-["send index for vfftpk" describes a vectorized version of fftpack]
--- a/liboctave/external/fftpack/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-FFTPACK_SRC = \
-  %reldir%/cfftb.f \
-  %reldir%/cfftb1.f \
-  %reldir%/cfftf.f \
-  %reldir%/cfftf1.f \
-  %reldir%/cffti.f \
-  %reldir%/cffti1.f \
-  %reldir%/passb.f \
-  %reldir%/passb2.f \
-  %reldir%/passb3.f \
-  %reldir%/passb4.f \
-  %reldir%/passb5.f \
-  %reldir%/passf.f \
-  %reldir%/passf2.f \
-  %reldir%/passf3.f \
-  %reldir%/passf4.f \
-  %reldir%/passf5.f \
-  %reldir%/zfftb.f \
-  %reldir%/zfftb1.f \
-  %reldir%/zfftf.f \
-  %reldir%/zfftf1.f \
-  %reldir%/zffti.f \
-  %reldir%/zffti1.f \
-  %reldir%/zpassb.f \
-  %reldir%/zpassb2.f \
-  %reldir%/zpassb3.f \
-  %reldir%/zpassb4.f \
-  %reldir%/zpassb5.f \
-  %reldir%/zpassf.f \
-  %reldir%/zpassf2.f \
-  %reldir%/zpassf3.f \
-  %reldir%/zpassf4.f \
-  %reldir%/zpassf5.f
-
-if AMCOND_HAVE_FFTW
-  liboctave_EXTRA_DIST += $(FFTPACK_SRC)
-else
-  EXTERNAL_SOURCES += $(FFTPACK_SRC)
-endif
-
-liboctave_EXTRA_DIST += \
-  %reldir%/fftpack.doc
--- a/liboctave/external/fftpack/passb.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-      subroutine passb (nac,ido,ip,l1,idl1,cc,c1,c2,ch,ch2,wa)
-      dimension       ch(ido,l1,ip)          ,cc(ido,ip,l1)          ,
-     1                c1(ido,l1,ip)          ,wa(1)      ,c2(idl1,ip),
-     2                ch2(idl1,ip)
-      idot = ido/2
-      nt = ip*idl1
-      ipp2 = ip+2
-      ipph = (ip+1)/2
-      idp = ip*ido
-c
-      if (ido .lt. l1) go to 106
-      do 103 j=2,ipph
-         jc = ipp2-j
-         do 102 k=1,l1
-            do 101 i=1,ido
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  101       continue
-  102    continue
-  103 continue
-      do 105 k=1,l1
-         do 104 i=1,ido
-            ch(i,k,1) = cc(i,1,k)
-  104    continue
-  105 continue
-      go to 112
-  106 do 109 j=2,ipph
-         jc = ipp2-j
-         do 108 i=1,ido
-            do 107 k=1,l1
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  107       continue
-  108    continue
-  109 continue
-      do 111 i=1,ido
-         do 110 k=1,l1
-            ch(i,k,1) = cc(i,1,k)
-  110    continue
-  111 continue
-  112 idl = 2-ido
-      inc = 0
-      do 116 l=2,ipph
-         lc = ipp2-l
-         idl = idl+ido
-         do 113 ik=1,idl1
-            c2(ik,l) = ch2(ik,1)+wa(idl-1)*ch2(ik,2)
-            c2(ik,lc) = wa(idl)*ch2(ik,ip)
-  113    continue
-         idlj = idl
-         inc = inc+ido
-         do 115 j=3,ipph
-            jc = ipp2-j
-            idlj = idlj+inc
-            if (idlj .gt. idp) idlj = idlj-idp
-            war = wa(idlj-1)
-            wai = wa(idlj)
-            do 114 ik=1,idl1
-               c2(ik,l) = c2(ik,l)+war*ch2(ik,j)
-               c2(ik,lc) = c2(ik,lc)+wai*ch2(ik,jc)
-  114       continue
-  115    continue
-  116 continue
-      do 118 j=2,ipph
-         do 117 ik=1,idl1
-            ch2(ik,1) = ch2(ik,1)+ch2(ik,j)
-  117    continue
-  118 continue
-      do 120 j=2,ipph
-         jc = ipp2-j
-         do 119 ik=2,idl1,2
-            ch2(ik-1,j) = c2(ik-1,j)-c2(ik,jc)
-            ch2(ik-1,jc) = c2(ik-1,j)+c2(ik,jc)
-            ch2(ik,j) = c2(ik,j)+c2(ik-1,jc)
-            ch2(ik,jc) = c2(ik,j)-c2(ik-1,jc)
-  119    continue
-  120 continue
-      nac = 1
-      if (ido .eq. 2) return
-      nac = 0
-      do 121 ik=1,idl1
-         c2(ik,1) = ch2(ik,1)
-  121 continue
-      do 123 j=2,ip
-         do 122 k=1,l1
-            c1(1,k,j) = ch(1,k,j)
-            c1(2,k,j) = ch(2,k,j)
-  122    continue
-  123 continue
-      if (idot .gt. l1) go to 127
-      idij = 0
-      do 126 j=2,ip
-         idij = idij+2
-         do 125 i=4,ido,2
-            idij = idij+2
-            do 124 k=1,l1
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)-wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)+wa(idij)*ch(i-1,k,j)
-  124       continue
-  125    continue
-  126 continue
-      return
-  127 idj = 2-ido
-      do 130 j=2,ip
-         idj = idj+ido
-         do 129 k=1,l1
-            idij = idj
-            do 128 i=4,ido,2
-               idij = idij+2
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)-wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)+wa(idij)*ch(i-1,k,j)
-  128       continue
-  129    continue
-  130 continue
-      return
-      end
--- a/liboctave/external/fftpack/passb2.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-      subroutine passb2 (ido,l1,cc,ch,wa1)
-      dimension       cc(ido,2,l1)           ,ch(ido,l1,2)           ,
-     1                wa1(1)
-      if (ido .gt. 2) go to 102
-      do 101 k=1,l1
-         ch(1,k,1) = cc(1,1,k)+cc(1,2,k)
-         ch(1,k,2) = cc(1,1,k)-cc(1,2,k)
-         ch(2,k,1) = cc(2,1,k)+cc(2,2,k)
-         ch(2,k,2) = cc(2,1,k)-cc(2,2,k)
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ch(i-1,k,1) = cc(i-1,1,k)+cc(i-1,2,k)
-            tr2 = cc(i-1,1,k)-cc(i-1,2,k)
-            ch(i,k,1) = cc(i,1,k)+cc(i,2,k)
-            ti2 = cc(i,1,k)-cc(i,2,k)
-            ch(i,k,2) = wa1(i-1)*ti2+wa1(i)*tr2
-            ch(i-1,k,2) = wa1(i-1)*tr2-wa1(i)*ti2
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passb3.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-      subroutine passb3 (ido,l1,cc,ch,wa1,wa2)
-      dimension       cc(ido,3,l1)           ,ch(ido,l1,3)           ,
-     1                wa1(1)     ,wa2(1)
-      data taur,taui /-.5,.866025403784439/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         tr2 = cc(1,2,k)+cc(1,3,k)
-         cr2 = cc(1,1,k)+taur*tr2
-         ch(1,k,1) = cc(1,1,k)+tr2
-         ti2 = cc(2,2,k)+cc(2,3,k)
-         ci2 = cc(2,1,k)+taur*ti2
-         ch(2,k,1) = cc(2,1,k)+ti2
-         cr3 = taui*(cc(1,2,k)-cc(1,3,k))
-         ci3 = taui*(cc(2,2,k)-cc(2,3,k))
-         ch(1,k,2) = cr2-ci3
-         ch(1,k,3) = cr2+ci3
-         ch(2,k,2) = ci2+cr3
-         ch(2,k,3) = ci2-cr3
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            tr2 = cc(i-1,2,k)+cc(i-1,3,k)
-            cr2 = cc(i-1,1,k)+taur*tr2
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2
-            ti2 = cc(i,2,k)+cc(i,3,k)
-            ci2 = cc(i,1,k)+taur*ti2
-            ch(i,k,1) = cc(i,1,k)+ti2
-            cr3 = taui*(cc(i-1,2,k)-cc(i-1,3,k))
-            ci3 = taui*(cc(i,2,k)-cc(i,3,k))
-            dr2 = cr2-ci3
-            dr3 = cr2+ci3
-            di2 = ci2+cr3
-            di3 = ci2-cr3
-            ch(i,k,2) = wa1(i-1)*di2+wa1(i)*dr2
-            ch(i-1,k,2) = wa1(i-1)*dr2-wa1(i)*di2
-            ch(i,k,3) = wa2(i-1)*di3+wa2(i)*dr3
-            ch(i-1,k,3) = wa2(i-1)*dr3-wa2(i)*di3
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passb4.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-      subroutine passb4 (ido,l1,cc,ch,wa1,wa2,wa3)
-      dimension       cc(ido,4,l1)           ,ch(ido,l1,4)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti1 = cc(2,1,k)-cc(2,3,k)
-         ti2 = cc(2,1,k)+cc(2,3,k)
-         tr4 = cc(2,4,k)-cc(2,2,k)
-         ti3 = cc(2,2,k)+cc(2,4,k)
-         tr1 = cc(1,1,k)-cc(1,3,k)
-         tr2 = cc(1,1,k)+cc(1,3,k)
-         ti4 = cc(1,2,k)-cc(1,4,k)
-         tr3 = cc(1,2,k)+cc(1,4,k)
-         ch(1,k,1) = tr2+tr3
-         ch(1,k,3) = tr2-tr3
-         ch(2,k,1) = ti2+ti3
-         ch(2,k,3) = ti2-ti3
-         ch(1,k,2) = tr1+tr4
-         ch(1,k,4) = tr1-tr4
-         ch(2,k,2) = ti1+ti4
-         ch(2,k,4) = ti1-ti4
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti1 = cc(i,1,k)-cc(i,3,k)
-            ti2 = cc(i,1,k)+cc(i,3,k)
-            ti3 = cc(i,2,k)+cc(i,4,k)
-            tr4 = cc(i,4,k)-cc(i,2,k)
-            tr1 = cc(i-1,1,k)-cc(i-1,3,k)
-            tr2 = cc(i-1,1,k)+cc(i-1,3,k)
-            ti4 = cc(i-1,2,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,2,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = tr2+tr3
-            cr3 = tr2-tr3
-            ch(i,k,1) = ti2+ti3
-            ci3 = ti2-ti3
-            cr2 = tr1+tr4
-            cr4 = tr1-tr4
-            ci2 = ti1+ti4
-            ci4 = ti1-ti4
-            ch(i-1,k,2) = wa1(i-1)*cr2-wa1(i)*ci2
-            ch(i,k,2) = wa1(i-1)*ci2+wa1(i)*cr2
-            ch(i-1,k,3) = wa2(i-1)*cr3-wa2(i)*ci3
-            ch(i,k,3) = wa2(i-1)*ci3+wa2(i)*cr3
-            ch(i-1,k,4) = wa3(i-1)*cr4-wa3(i)*ci4
-            ch(i,k,4) = wa3(i-1)*ci4+wa3(i)*cr4
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passb5.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-      subroutine passb5 (ido,l1,cc,ch,wa1,wa2,wa3,wa4)
-      dimension       cc(ido,5,l1)           ,ch(ido,l1,5)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)     ,wa4(1)
-      data tr11,ti11,tr12,ti12 /.309016994374947,.951056516295154,
-     1-.809016994374947,.587785252292473/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti5 = cc(2,2,k)-cc(2,5,k)
-         ti2 = cc(2,2,k)+cc(2,5,k)
-         ti4 = cc(2,3,k)-cc(2,4,k)
-         ti3 = cc(2,3,k)+cc(2,4,k)
-         tr5 = cc(1,2,k)-cc(1,5,k)
-         tr2 = cc(1,2,k)+cc(1,5,k)
-         tr4 = cc(1,3,k)-cc(1,4,k)
-         tr3 = cc(1,3,k)+cc(1,4,k)
-         ch(1,k,1) = cc(1,1,k)+tr2+tr3
-         ch(2,k,1) = cc(2,1,k)+ti2+ti3
-         cr2 = cc(1,1,k)+tr11*tr2+tr12*tr3
-         ci2 = cc(2,1,k)+tr11*ti2+tr12*ti3
-         cr3 = cc(1,1,k)+tr12*tr2+tr11*tr3
-         ci3 = cc(2,1,k)+tr12*ti2+tr11*ti3
-         cr5 = ti11*tr5+ti12*tr4
-         ci5 = ti11*ti5+ti12*ti4
-         cr4 = ti12*tr5-ti11*tr4
-         ci4 = ti12*ti5-ti11*ti4
-         ch(1,k,2) = cr2-ci5
-         ch(1,k,5) = cr2+ci5
-         ch(2,k,2) = ci2+cr5
-         ch(2,k,3) = ci3+cr4
-         ch(1,k,3) = cr3-ci4
-         ch(1,k,4) = cr3+ci4
-         ch(2,k,4) = ci3-cr4
-         ch(2,k,5) = ci2-cr5
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti5 = cc(i,2,k)-cc(i,5,k)
-            ti2 = cc(i,2,k)+cc(i,5,k)
-            ti4 = cc(i,3,k)-cc(i,4,k)
-            ti3 = cc(i,3,k)+cc(i,4,k)
-            tr5 = cc(i-1,2,k)-cc(i-1,5,k)
-            tr2 = cc(i-1,2,k)+cc(i-1,5,k)
-            tr4 = cc(i-1,3,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,3,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2+tr3
-            ch(i,k,1) = cc(i,1,k)+ti2+ti3
-            cr2 = cc(i-1,1,k)+tr11*tr2+tr12*tr3
-            ci2 = cc(i,1,k)+tr11*ti2+tr12*ti3
-            cr3 = cc(i-1,1,k)+tr12*tr2+tr11*tr3
-            ci3 = cc(i,1,k)+tr12*ti2+tr11*ti3
-            cr5 = ti11*tr5+ti12*tr4
-            ci5 = ti11*ti5+ti12*ti4
-            cr4 = ti12*tr5-ti11*tr4
-            ci4 = ti12*ti5-ti11*ti4
-            dr3 = cr3-ci4
-            dr4 = cr3+ci4
-            di3 = ci3+cr4
-            di4 = ci3-cr4
-            dr5 = cr2+ci5
-            dr2 = cr2-ci5
-            di5 = ci2-cr5
-            di2 = ci2+cr5
-            ch(i-1,k,2) = wa1(i-1)*dr2-wa1(i)*di2
-            ch(i,k,2) = wa1(i-1)*di2+wa1(i)*dr2
-            ch(i-1,k,3) = wa2(i-1)*dr3-wa2(i)*di3
-            ch(i,k,3) = wa2(i-1)*di3+wa2(i)*dr3
-            ch(i-1,k,4) = wa3(i-1)*dr4-wa3(i)*di4
-            ch(i,k,4) = wa3(i-1)*di4+wa3(i)*dr4
-            ch(i-1,k,5) = wa4(i-1)*dr5-wa4(i)*di5
-            ch(i,k,5) = wa4(i-1)*di5+wa4(i)*dr5
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passf.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-      subroutine passf (nac,ido,ip,l1,idl1,cc,c1,c2,ch,ch2,wa)
-      dimension       ch(ido,l1,ip)          ,cc(ido,ip,l1)          ,
-     1                c1(ido,l1,ip)          ,wa(1)      ,c2(idl1,ip),
-     2                ch2(idl1,ip)
-      idot = ido/2
-      nt = ip*idl1
-      ipp2 = ip+2
-      ipph = (ip+1)/2
-      idp = ip*ido
-c
-      if (ido .lt. l1) go to 106
-      do 103 j=2,ipph
-         jc = ipp2-j
-         do 102 k=1,l1
-            do 101 i=1,ido
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  101       continue
-  102    continue
-  103 continue
-      do 105 k=1,l1
-         do 104 i=1,ido
-            ch(i,k,1) = cc(i,1,k)
-  104    continue
-  105 continue
-      go to 112
-  106 do 109 j=2,ipph
-         jc = ipp2-j
-         do 108 i=1,ido
-            do 107 k=1,l1
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  107       continue
-  108    continue
-  109 continue
-      do 111 i=1,ido
-         do 110 k=1,l1
-            ch(i,k,1) = cc(i,1,k)
-  110    continue
-  111 continue
-  112 idl = 2-ido
-      inc = 0
-      do 116 l=2,ipph
-         lc = ipp2-l
-         idl = idl+ido
-         do 113 ik=1,idl1
-            c2(ik,l) = ch2(ik,1)+wa(idl-1)*ch2(ik,2)
-            c2(ik,lc) = -wa(idl)*ch2(ik,ip)
-  113    continue
-         idlj = idl
-         inc = inc+ido
-         do 115 j=3,ipph
-            jc = ipp2-j
-            idlj = idlj+inc
-            if (idlj .gt. idp) idlj = idlj-idp
-            war = wa(idlj-1)
-            wai = wa(idlj)
-            do 114 ik=1,idl1
-               c2(ik,l) = c2(ik,l)+war*ch2(ik,j)
-               c2(ik,lc) = c2(ik,lc)-wai*ch2(ik,jc)
-  114       continue
-  115    continue
-  116 continue
-      do 118 j=2,ipph
-         do 117 ik=1,idl1
-            ch2(ik,1) = ch2(ik,1)+ch2(ik,j)
-  117    continue
-  118 continue
-      do 120 j=2,ipph
-         jc = ipp2-j
-         do 119 ik=2,idl1,2
-            ch2(ik-1,j) = c2(ik-1,j)-c2(ik,jc)
-            ch2(ik-1,jc) = c2(ik-1,j)+c2(ik,jc)
-            ch2(ik,j) = c2(ik,j)+c2(ik-1,jc)
-            ch2(ik,jc) = c2(ik,j)-c2(ik-1,jc)
-  119    continue
-  120 continue
-      nac = 1
-      if (ido .eq. 2) return
-      nac = 0
-      do 121 ik=1,idl1
-         c2(ik,1) = ch2(ik,1)
-  121 continue
-      do 123 j=2,ip
-         do 122 k=1,l1
-            c1(1,k,j) = ch(1,k,j)
-            c1(2,k,j) = ch(2,k,j)
-  122    continue
-  123 continue
-      if (idot .gt. l1) go to 127
-      idij = 0
-      do 126 j=2,ip
-         idij = idij+2
-         do 125 i=4,ido,2
-            idij = idij+2
-            do 124 k=1,l1
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)+wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)-wa(idij)*ch(i-1,k,j)
-  124       continue
-  125    continue
-  126 continue
-      return
-  127 idj = 2-ido
-      do 130 j=2,ip
-         idj = idj+ido
-         do 129 k=1,l1
-            idij = idj
-            do 128 i=4,ido,2
-               idij = idij+2
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)+wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)-wa(idij)*ch(i-1,k,j)
-  128       continue
-  129    continue
-  130 continue
-      return
-      end
--- a/liboctave/external/fftpack/passf2.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-      subroutine passf2 (ido,l1,cc,ch,wa1)
-      dimension       cc(ido,2,l1)           ,ch(ido,l1,2)           ,
-     1                wa1(1)
-      if (ido .gt. 2) go to 102
-      do 101 k=1,l1
-         ch(1,k,1) = cc(1,1,k)+cc(1,2,k)
-         ch(1,k,2) = cc(1,1,k)-cc(1,2,k)
-         ch(2,k,1) = cc(2,1,k)+cc(2,2,k)
-         ch(2,k,2) = cc(2,1,k)-cc(2,2,k)
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ch(i-1,k,1) = cc(i-1,1,k)+cc(i-1,2,k)
-            tr2 = cc(i-1,1,k)-cc(i-1,2,k)
-            ch(i,k,1) = cc(i,1,k)+cc(i,2,k)
-            ti2 = cc(i,1,k)-cc(i,2,k)
-            ch(i,k,2) = wa1(i-1)*ti2-wa1(i)*tr2
-            ch(i-1,k,2) = wa1(i-1)*tr2+wa1(i)*ti2
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passf3.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-      subroutine passf3 (ido,l1,cc,ch,wa1,wa2)
-      dimension       cc(ido,3,l1)           ,ch(ido,l1,3)           ,
-     1                wa1(1)     ,wa2(1)
-      data taur,taui /-.5,-.866025403784439/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         tr2 = cc(1,2,k)+cc(1,3,k)
-         cr2 = cc(1,1,k)+taur*tr2
-         ch(1,k,1) = cc(1,1,k)+tr2
-         ti2 = cc(2,2,k)+cc(2,3,k)
-         ci2 = cc(2,1,k)+taur*ti2
-         ch(2,k,1) = cc(2,1,k)+ti2
-         cr3 = taui*(cc(1,2,k)-cc(1,3,k))
-         ci3 = taui*(cc(2,2,k)-cc(2,3,k))
-         ch(1,k,2) = cr2-ci3
-         ch(1,k,3) = cr2+ci3
-         ch(2,k,2) = ci2+cr3
-         ch(2,k,3) = ci2-cr3
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            tr2 = cc(i-1,2,k)+cc(i-1,3,k)
-            cr2 = cc(i-1,1,k)+taur*tr2
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2
-            ti2 = cc(i,2,k)+cc(i,3,k)
-            ci2 = cc(i,1,k)+taur*ti2
-            ch(i,k,1) = cc(i,1,k)+ti2
-            cr3 = taui*(cc(i-1,2,k)-cc(i-1,3,k))
-            ci3 = taui*(cc(i,2,k)-cc(i,3,k))
-            dr2 = cr2-ci3
-            dr3 = cr2+ci3
-            di2 = ci2+cr3
-            di3 = ci2-cr3
-            ch(i,k,2) = wa1(i-1)*di2-wa1(i)*dr2
-            ch(i-1,k,2) = wa1(i-1)*dr2+wa1(i)*di2
-            ch(i,k,3) = wa2(i-1)*di3-wa2(i)*dr3
-            ch(i-1,k,3) = wa2(i-1)*dr3+wa2(i)*di3
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passf4.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-      subroutine passf4 (ido,l1,cc,ch,wa1,wa2,wa3)
-      dimension       cc(ido,4,l1)           ,ch(ido,l1,4)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti1 = cc(2,1,k)-cc(2,3,k)
-         ti2 = cc(2,1,k)+cc(2,3,k)
-         tr4 = cc(2,2,k)-cc(2,4,k)
-         ti3 = cc(2,2,k)+cc(2,4,k)
-         tr1 = cc(1,1,k)-cc(1,3,k)
-         tr2 = cc(1,1,k)+cc(1,3,k)
-         ti4 = cc(1,4,k)-cc(1,2,k)
-         tr3 = cc(1,2,k)+cc(1,4,k)
-         ch(1,k,1) = tr2+tr3
-         ch(1,k,3) = tr2-tr3
-         ch(2,k,1) = ti2+ti3
-         ch(2,k,3) = ti2-ti3
-         ch(1,k,2) = tr1+tr4
-         ch(1,k,4) = tr1-tr4
-         ch(2,k,2) = ti1+ti4
-         ch(2,k,4) = ti1-ti4
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti1 = cc(i,1,k)-cc(i,3,k)
-            ti2 = cc(i,1,k)+cc(i,3,k)
-            ti3 = cc(i,2,k)+cc(i,4,k)
-            tr4 = cc(i,2,k)-cc(i,4,k)
-            tr1 = cc(i-1,1,k)-cc(i-1,3,k)
-            tr2 = cc(i-1,1,k)+cc(i-1,3,k)
-            ti4 = cc(i-1,4,k)-cc(i-1,2,k)
-            tr3 = cc(i-1,2,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = tr2+tr3
-            cr3 = tr2-tr3
-            ch(i,k,1) = ti2+ti3
-            ci3 = ti2-ti3
-            cr2 = tr1+tr4
-            cr4 = tr1-tr4
-            ci2 = ti1+ti4
-            ci4 = ti1-ti4
-            ch(i-1,k,2) = wa1(i-1)*cr2+wa1(i)*ci2
-            ch(i,k,2) = wa1(i-1)*ci2-wa1(i)*cr2
-            ch(i-1,k,3) = wa2(i-1)*cr3+wa2(i)*ci3
-            ch(i,k,3) = wa2(i-1)*ci3-wa2(i)*cr3
-            ch(i-1,k,4) = wa3(i-1)*cr4+wa3(i)*ci4
-            ch(i,k,4) = wa3(i-1)*ci4-wa3(i)*cr4
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/passf5.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-      subroutine passf5 (ido,l1,cc,ch,wa1,wa2,wa3,wa4)
-      dimension       cc(ido,5,l1)           ,ch(ido,l1,5)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)     ,wa4(1)
-      data tr11,ti11,tr12,ti12 /.309016994374947,-.951056516295154,
-     1-.809016994374947,-.587785252292473/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti5 = cc(2,2,k)-cc(2,5,k)
-         ti2 = cc(2,2,k)+cc(2,5,k)
-         ti4 = cc(2,3,k)-cc(2,4,k)
-         ti3 = cc(2,3,k)+cc(2,4,k)
-         tr5 = cc(1,2,k)-cc(1,5,k)
-         tr2 = cc(1,2,k)+cc(1,5,k)
-         tr4 = cc(1,3,k)-cc(1,4,k)
-         tr3 = cc(1,3,k)+cc(1,4,k)
-         ch(1,k,1) = cc(1,1,k)+tr2+tr3
-         ch(2,k,1) = cc(2,1,k)+ti2+ti3
-         cr2 = cc(1,1,k)+tr11*tr2+tr12*tr3
-         ci2 = cc(2,1,k)+tr11*ti2+tr12*ti3
-         cr3 = cc(1,1,k)+tr12*tr2+tr11*tr3
-         ci3 = cc(2,1,k)+tr12*ti2+tr11*ti3
-         cr5 = ti11*tr5+ti12*tr4
-         ci5 = ti11*ti5+ti12*ti4
-         cr4 = ti12*tr5-ti11*tr4
-         ci4 = ti12*ti5-ti11*ti4
-         ch(1,k,2) = cr2-ci5
-         ch(1,k,5) = cr2+ci5
-         ch(2,k,2) = ci2+cr5
-         ch(2,k,3) = ci3+cr4
-         ch(1,k,3) = cr3-ci4
-         ch(1,k,4) = cr3+ci4
-         ch(2,k,4) = ci3-cr4
-         ch(2,k,5) = ci2-cr5
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti5 = cc(i,2,k)-cc(i,5,k)
-            ti2 = cc(i,2,k)+cc(i,5,k)
-            ti4 = cc(i,3,k)-cc(i,4,k)
-            ti3 = cc(i,3,k)+cc(i,4,k)
-            tr5 = cc(i-1,2,k)-cc(i-1,5,k)
-            tr2 = cc(i-1,2,k)+cc(i-1,5,k)
-            tr4 = cc(i-1,3,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,3,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2+tr3
-            ch(i,k,1) = cc(i,1,k)+ti2+ti3
-            cr2 = cc(i-1,1,k)+tr11*tr2+tr12*tr3
-            ci2 = cc(i,1,k)+tr11*ti2+tr12*ti3
-            cr3 = cc(i-1,1,k)+tr12*tr2+tr11*tr3
-            ci3 = cc(i,1,k)+tr12*ti2+tr11*ti3
-            cr5 = ti11*tr5+ti12*tr4
-            ci5 = ti11*ti5+ti12*ti4
-            cr4 = ti12*tr5-ti11*tr4
-            ci4 = ti12*ti5-ti11*ti4
-            dr3 = cr3-ci4
-            dr4 = cr3+ci4
-            di3 = ci3+cr4
-            di4 = ci3-cr4
-            dr5 = cr2+ci5
-            dr2 = cr2-ci5
-            di5 = ci2-cr5
-            di2 = ci2+cr5
-            ch(i-1,k,2) = wa1(i-1)*dr2+wa1(i)*di2
-            ch(i,k,2) = wa1(i-1)*di2-wa1(i)*dr2
-            ch(i-1,k,3) = wa2(i-1)*dr3+wa2(i)*di3
-            ch(i,k,3) = wa2(i-1)*di3-wa2(i)*dr3
-            ch(i-1,k,4) = wa3(i-1)*dr4+wa3(i)*di4
-            ch(i,k,4) = wa3(i-1)*di4-wa3(i)*dr4
-            ch(i-1,k,5) = wa4(i-1)*dr5+wa4(i)*di5
-            ch(i,k,5) = wa4(i-1)*di5-wa4(i)*dr5
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zfftb.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-      subroutine zfftb (n,c,wsave)
-      implicit double precision (a-h,o-z)
-      dimension       c(*)       ,wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call zfftb1 (n,c,wsave,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/zfftb1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-      subroutine zfftb1 (n,c,ch,wa,ifac)
-      implicit double precision (a-h,o-z)
-      dimension       ch(*)      ,c(*)       ,wa(*)      ,ifac(*)
-      nf = ifac(2)
-      na = 0
-      l1 = 1
-      iw = 1
-      do 116 k1=1,nf
-         ip = ifac(k1+2)
-         l2 = ip*l1
-         ido = n/l2
-         idot = ido+ido
-         idl1 = idot*l1
-         if (ip .ne. 4) go to 103
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         if (na .ne. 0) go to 101
-         call zpassb4 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3))
-         go to 102
-  101    call zpassb4 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3))
-  102    na = 1-na
-         go to 115
-  103    if (ip .ne. 2) go to 106
-         if (na .ne. 0) go to 104
-         call zpassb2 (idot,l1,c,ch,wa(iw))
-         go to 105
-  104    call zpassb2 (idot,l1,ch,c,wa(iw))
-  105    na = 1-na
-         go to 115
-  106    if (ip .ne. 3) go to 109
-         ix2 = iw+idot
-         if (na .ne. 0) go to 107
-         call zpassb3 (idot,l1,c,ch,wa(iw),wa(ix2))
-         go to 108
-  107    call zpassb3 (idot,l1,ch,c,wa(iw),wa(ix2))
-  108    na = 1-na
-         go to 115
-  109    if (ip .ne. 5) go to 112
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         ix4 = ix3+idot
-         if (na .ne. 0) go to 110
-         call zpassb5 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-         go to 111
-  110    call zpassb5 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-  111    na = 1-na
-         go to 115
-  112    if (na .ne. 0) go to 113
-         call zpassb (nac,idot,ip,l1,idl1,c,c,c,ch,ch,wa(iw))
-         go to 114
-  113    call zpassb (nac,idot,ip,l1,idl1,ch,ch,ch,c,c,wa(iw))
-  114    if (nac .ne. 0) na = 1-na
-  115    l1 = l2
-         iw = iw+(ip-1)*idot
-  116 continue
-      if (na .eq. 0) return
-      n2 = n+n
-      do 117 i=1,n2
-         c(i) = ch(i)
-  117 continue
-      return
-      end
--- a/liboctave/external/fftpack/zfftf.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-      subroutine zfftf (n,c,wsave)
-      implicit double precision (a-h,o-z)
-      dimension       c(*)       ,wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call zfftf1 (n,c,wsave,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/zfftf1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-      subroutine zfftf1 (n,c,ch,wa,ifac)
-      implicit double precision (a-h,o-z)
-      dimension       ch(*)      ,c(*)       ,wa(*)      ,ifac(*)
-      nf = ifac(2)
-      na = 0
-      l1 = 1
-      iw = 1
-      do 116 k1=1,nf
-         ip = ifac(k1+2)
-         l2 = ip*l1
-         ido = n/l2
-         idot = ido+ido
-         idl1 = idot*l1
-         if (ip .ne. 4) go to 103
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         if (na .ne. 0) go to 101
-         call zpassf4 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3))
-         go to 102
-  101    call zpassf4 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3))
-  102    na = 1-na
-         go to 115
-  103    if (ip .ne. 2) go to 106
-         if (na .ne. 0) go to 104
-         call zpassf2 (idot,l1,c,ch,wa(iw))
-         go to 105
-  104    call zpassf2 (idot,l1,ch,c,wa(iw))
-  105    na = 1-na
-         go to 115
-  106    if (ip .ne. 3) go to 109
-         ix2 = iw+idot
-         if (na .ne. 0) go to 107
-         call zpassf3 (idot,l1,c,ch,wa(iw),wa(ix2))
-         go to 108
-  107    call zpassf3 (idot,l1,ch,c,wa(iw),wa(ix2))
-  108    na = 1-na
-         go to 115
-  109    if (ip .ne. 5) go to 112
-         ix2 = iw+idot
-         ix3 = ix2+idot
-         ix4 = ix3+idot
-         if (na .ne. 0) go to 110
-         call zpassf5 (idot,l1,c,ch,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-         go to 111
-  110    call zpassf5 (idot,l1,ch,c,wa(iw),wa(ix2),wa(ix3),wa(ix4))
-  111    na = 1-na
-         go to 115
-  112    if (na .ne. 0) go to 113
-         call zpassf (nac,idot,ip,l1,idl1,c,c,c,ch,ch,wa(iw))
-         go to 114
-  113    call zpassf (nac,idot,ip,l1,idl1,ch,ch,ch,c,c,wa(iw))
-  114    if (nac .ne. 0) na = 1-na
-  115    l1 = l2
-         iw = iw+(ip-1)*idot
-  116 continue
-      if (na .eq. 0) return
-      n2 = n+n
-      do 117 i=1,n2
-         c(i) = ch(i)
-  117 continue
-      return
-      end
--- a/liboctave/external/fftpack/zffti.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-      subroutine zffti (n,wsave)
-      implicit double precision (a-h,o-z)
-      dimension       wsave(*)
-      if (n .eq. 1) return
-      iw1 = n+n+1
-      iw2 = iw1+n+n
-      call zffti1 (n,wsave(iw1),wsave(iw2))
-      return
-      end
--- a/liboctave/external/fftpack/zffti1.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-      subroutine zffti1 (n,wa,ifac)
-      implicit double precision (a-h,o-z)
-      dimension       wa(*)      ,ifac(*)    ,ntryh(4)
-      data ntryh(1),ntryh(2),ntryh(3),ntryh(4)/3,4,2,5/
-      nl = n
-      nf = 0
-      j = 0
-  101 j = j+1
-      if (j-4) 102,102,103
-  102 ntry = ntryh(j)
-      go to 104
-  103 ntry = ntry+2
-  104 nq = nl/ntry
-      nr = nl-ntry*nq
-      if (nr) 101,105,101
-  105 nf = nf+1
-      ifac(nf+2) = ntry
-      nl = nq
-      if (ntry .ne. 2) go to 107
-      if (nf .eq. 1) go to 107
-      do 106 i=2,nf
-         ib = nf-i+2
-         ifac(ib+2) = ifac(ib+1)
-  106 continue
-      ifac(3) = 2
-  107 if (nl .ne. 1) go to 104
-      ifac(1) = n
-      ifac(2) = nf
-      tpi = 6.28318530717959d0
-      argh = tpi/dble(n)
-      i = 2
-      l1 = 1
-      do 110 k1=1,nf
-         ip = ifac(k1+2)
-         ld = 0
-         l2 = l1*ip
-         ido = n/l2
-         idot = ido+ido+2
-         ipm = ip-1
-         do 109 j=1,ipm
-            i1 = i
-            wa(i-1) = 1.
-            wa(i) = 0.
-            ld = ld+l1
-            fi = 0.
-            argld = dble(ld)*argh
-            do 108 ii=4,idot,2
-               i = i+2
-               fi = fi+1.
-               arg = fi*argld
-               wa(i-1) = cos(arg)
-               wa(i) = sin(arg)
-  108       continue
-            if (ip .le. 5) go to 109
-            wa(i1-1) = wa(i-1)
-            wa(i1) = wa(i)
-  109    continue
-         l1 = l2
-  110 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassb.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-      subroutine zpassb (nac,ido,ip,l1,idl1,cc,c1,c2,ch,ch2,wa)
-      implicit double precision (a-h,o-z)
-      dimension       ch(ido,l1,ip)          ,cc(ido,ip,l1)          ,
-     1                c1(ido,l1,ip)          ,wa(1)      ,c2(idl1,ip),
-     2                ch2(idl1,ip)
-      idot = ido/2
-      nt = ip*idl1
-      ipp2 = ip+2
-      ipph = (ip+1)/2
-      idp = ip*ido
-c
-      if (ido .lt. l1) go to 106
-      do 103 j=2,ipph
-         jc = ipp2-j
-         do 102 k=1,l1
-            do 101 i=1,ido
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  101       continue
-  102    continue
-  103 continue
-      do 105 k=1,l1
-         do 104 i=1,ido
-            ch(i,k,1) = cc(i,1,k)
-  104    continue
-  105 continue
-      go to 112
-  106 do 109 j=2,ipph
-         jc = ipp2-j
-         do 108 i=1,ido
-            do 107 k=1,l1
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  107       continue
-  108    continue
-  109 continue
-      do 111 i=1,ido
-         do 110 k=1,l1
-            ch(i,k,1) = cc(i,1,k)
-  110    continue
-  111 continue
-  112 idl = 2-ido
-      inc = 0
-      do 116 l=2,ipph
-         lc = ipp2-l
-         idl = idl+ido
-         do 113 ik=1,idl1
-            c2(ik,l) = ch2(ik,1)+wa(idl-1)*ch2(ik,2)
-            c2(ik,lc) = wa(idl)*ch2(ik,ip)
-  113    continue
-         idlj = idl
-         inc = inc+ido
-         do 115 j=3,ipph
-            jc = ipp2-j
-            idlj = idlj+inc
-            if (idlj .gt. idp) idlj = idlj-idp
-            war = wa(idlj-1)
-            wai = wa(idlj)
-            do 114 ik=1,idl1
-               c2(ik,l) = c2(ik,l)+war*ch2(ik,j)
-               c2(ik,lc) = c2(ik,lc)+wai*ch2(ik,jc)
-  114       continue
-  115    continue
-  116 continue
-      do 118 j=2,ipph
-         do 117 ik=1,idl1
-            ch2(ik,1) = ch2(ik,1)+ch2(ik,j)
-  117    continue
-  118 continue
-      do 120 j=2,ipph
-         jc = ipp2-j
-         do 119 ik=2,idl1,2
-            ch2(ik-1,j) = c2(ik-1,j)-c2(ik,jc)
-            ch2(ik-1,jc) = c2(ik-1,j)+c2(ik,jc)
-            ch2(ik,j) = c2(ik,j)+c2(ik-1,jc)
-            ch2(ik,jc) = c2(ik,j)-c2(ik-1,jc)
-  119    continue
-  120 continue
-      nac = 1
-      if (ido .eq. 2) return
-      nac = 0
-      do 121 ik=1,idl1
-         c2(ik,1) = ch2(ik,1)
-  121 continue
-      do 123 j=2,ip
-         do 122 k=1,l1
-            c1(1,k,j) = ch(1,k,j)
-            c1(2,k,j) = ch(2,k,j)
-  122    continue
-  123 continue
-      if (idot .gt. l1) go to 127
-      idij = 0
-      do 126 j=2,ip
-         idij = idij+2
-         do 125 i=4,ido,2
-            idij = idij+2
-            do 124 k=1,l1
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)-wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)+wa(idij)*ch(i-1,k,j)
-  124       continue
-  125    continue
-  126 continue
-      return
-  127 idj = 2-ido
-      do 130 j=2,ip
-         idj = idj+ido
-         do 129 k=1,l1
-            idij = idj
-            do 128 i=4,ido,2
-               idij = idij+2
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)-wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)+wa(idij)*ch(i-1,k,j)
-  128       continue
-  129    continue
-  130 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassb2.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-      subroutine zpassb2 (ido,l1,cc,ch,wa1)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,2,l1)           ,ch(ido,l1,2)           ,
-     1                wa1(1)
-      if (ido .gt. 2) go to 102
-      do 101 k=1,l1
-         ch(1,k,1) = cc(1,1,k)+cc(1,2,k)
-         ch(1,k,2) = cc(1,1,k)-cc(1,2,k)
-         ch(2,k,1) = cc(2,1,k)+cc(2,2,k)
-         ch(2,k,2) = cc(2,1,k)-cc(2,2,k)
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ch(i-1,k,1) = cc(i-1,1,k)+cc(i-1,2,k)
-            tr2 = cc(i-1,1,k)-cc(i-1,2,k)
-            ch(i,k,1) = cc(i,1,k)+cc(i,2,k)
-            ti2 = cc(i,1,k)-cc(i,2,k)
-            ch(i,k,2) = wa1(i-1)*ti2+wa1(i)*tr2
-            ch(i-1,k,2) = wa1(i-1)*tr2-wa1(i)*ti2
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassb3.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-      subroutine zpassb3 (ido,l1,cc,ch,wa1,wa2)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,3,l1)           ,ch(ido,l1,3)           ,
-     1                wa1(1)     ,wa2(1)
-      data taur,taui /-.5,.866025403784439d0/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         tr2 = cc(1,2,k)+cc(1,3,k)
-         cr2 = cc(1,1,k)+taur*tr2
-         ch(1,k,1) = cc(1,1,k)+tr2
-         ti2 = cc(2,2,k)+cc(2,3,k)
-         ci2 = cc(2,1,k)+taur*ti2
-         ch(2,k,1) = cc(2,1,k)+ti2
-         cr3 = taui*(cc(1,2,k)-cc(1,3,k))
-         ci3 = taui*(cc(2,2,k)-cc(2,3,k))
-         ch(1,k,2) = cr2-ci3
-         ch(1,k,3) = cr2+ci3
-         ch(2,k,2) = ci2+cr3
-         ch(2,k,3) = ci2-cr3
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            tr2 = cc(i-1,2,k)+cc(i-1,3,k)
-            cr2 = cc(i-1,1,k)+taur*tr2
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2
-            ti2 = cc(i,2,k)+cc(i,3,k)
-            ci2 = cc(i,1,k)+taur*ti2
-            ch(i,k,1) = cc(i,1,k)+ti2
-            cr3 = taui*(cc(i-1,2,k)-cc(i-1,3,k))
-            ci3 = taui*(cc(i,2,k)-cc(i,3,k))
-            dr2 = cr2-ci3
-            dr3 = cr2+ci3
-            di2 = ci2+cr3
-            di3 = ci2-cr3
-            ch(i,k,2) = wa1(i-1)*di2+wa1(i)*dr2
-            ch(i-1,k,2) = wa1(i-1)*dr2-wa1(i)*di2
-            ch(i,k,3) = wa2(i-1)*di3+wa2(i)*dr3
-            ch(i-1,k,3) = wa2(i-1)*dr3-wa2(i)*di3
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassb4.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-      subroutine zpassb4 (ido,l1,cc,ch,wa1,wa2,wa3)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,4,l1)           ,ch(ido,l1,4)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti1 = cc(2,1,k)-cc(2,3,k)
-         ti2 = cc(2,1,k)+cc(2,3,k)
-         tr4 = cc(2,4,k)-cc(2,2,k)
-         ti3 = cc(2,2,k)+cc(2,4,k)
-         tr1 = cc(1,1,k)-cc(1,3,k)
-         tr2 = cc(1,1,k)+cc(1,3,k)
-         ti4 = cc(1,2,k)-cc(1,4,k)
-         tr3 = cc(1,2,k)+cc(1,4,k)
-         ch(1,k,1) = tr2+tr3
-         ch(1,k,3) = tr2-tr3
-         ch(2,k,1) = ti2+ti3
-         ch(2,k,3) = ti2-ti3
-         ch(1,k,2) = tr1+tr4
-         ch(1,k,4) = tr1-tr4
-         ch(2,k,2) = ti1+ti4
-         ch(2,k,4) = ti1-ti4
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti1 = cc(i,1,k)-cc(i,3,k)
-            ti2 = cc(i,1,k)+cc(i,3,k)
-            ti3 = cc(i,2,k)+cc(i,4,k)
-            tr4 = cc(i,4,k)-cc(i,2,k)
-            tr1 = cc(i-1,1,k)-cc(i-1,3,k)
-            tr2 = cc(i-1,1,k)+cc(i-1,3,k)
-            ti4 = cc(i-1,2,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,2,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = tr2+tr3
-            cr3 = tr2-tr3
-            ch(i,k,1) = ti2+ti3
-            ci3 = ti2-ti3
-            cr2 = tr1+tr4
-            cr4 = tr1-tr4
-            ci2 = ti1+ti4
-            ci4 = ti1-ti4
-            ch(i-1,k,2) = wa1(i-1)*cr2-wa1(i)*ci2
-            ch(i,k,2) = wa1(i-1)*ci2+wa1(i)*cr2
-            ch(i-1,k,3) = wa2(i-1)*cr3-wa2(i)*ci3
-            ch(i,k,3) = wa2(i-1)*ci3+wa2(i)*cr3
-            ch(i-1,k,4) = wa3(i-1)*cr4-wa3(i)*ci4
-            ch(i,k,4) = wa3(i-1)*ci4+wa3(i)*cr4
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassb5.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-      subroutine zpassb5 (ido,l1,cc,ch,wa1,wa2,wa3,wa4)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,5,l1)           ,ch(ido,l1,5)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)     ,wa4(1)
-      data tr11,ti11,tr12,ti12 /.309016994374947d0,.951056516295154d0,
-     1-.809016994374947d0,.587785252292473d0/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti5 = cc(2,2,k)-cc(2,5,k)
-         ti2 = cc(2,2,k)+cc(2,5,k)
-         ti4 = cc(2,3,k)-cc(2,4,k)
-         ti3 = cc(2,3,k)+cc(2,4,k)
-         tr5 = cc(1,2,k)-cc(1,5,k)
-         tr2 = cc(1,2,k)+cc(1,5,k)
-         tr4 = cc(1,3,k)-cc(1,4,k)
-         tr3 = cc(1,3,k)+cc(1,4,k)
-         ch(1,k,1) = cc(1,1,k)+tr2+tr3
-         ch(2,k,1) = cc(2,1,k)+ti2+ti3
-         cr2 = cc(1,1,k)+tr11*tr2+tr12*tr3
-         ci2 = cc(2,1,k)+tr11*ti2+tr12*ti3
-         cr3 = cc(1,1,k)+tr12*tr2+tr11*tr3
-         ci3 = cc(2,1,k)+tr12*ti2+tr11*ti3
-         cr5 = ti11*tr5+ti12*tr4
-         ci5 = ti11*ti5+ti12*ti4
-         cr4 = ti12*tr5-ti11*tr4
-         ci4 = ti12*ti5-ti11*ti4
-         ch(1,k,2) = cr2-ci5
-         ch(1,k,5) = cr2+ci5
-         ch(2,k,2) = ci2+cr5
-         ch(2,k,3) = ci3+cr4
-         ch(1,k,3) = cr3-ci4
-         ch(1,k,4) = cr3+ci4
-         ch(2,k,4) = ci3-cr4
-         ch(2,k,5) = ci2-cr5
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti5 = cc(i,2,k)-cc(i,5,k)
-            ti2 = cc(i,2,k)+cc(i,5,k)
-            ti4 = cc(i,3,k)-cc(i,4,k)
-            ti3 = cc(i,3,k)+cc(i,4,k)
-            tr5 = cc(i-1,2,k)-cc(i-1,5,k)
-            tr2 = cc(i-1,2,k)+cc(i-1,5,k)
-            tr4 = cc(i-1,3,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,3,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2+tr3
-            ch(i,k,1) = cc(i,1,k)+ti2+ti3
-            cr2 = cc(i-1,1,k)+tr11*tr2+tr12*tr3
-            ci2 = cc(i,1,k)+tr11*ti2+tr12*ti3
-            cr3 = cc(i-1,1,k)+tr12*tr2+tr11*tr3
-            ci3 = cc(i,1,k)+tr12*ti2+tr11*ti3
-            cr5 = ti11*tr5+ti12*tr4
-            ci5 = ti11*ti5+ti12*ti4
-            cr4 = ti12*tr5-ti11*tr4
-            ci4 = ti12*ti5-ti11*ti4
-            dr3 = cr3-ci4
-            dr4 = cr3+ci4
-            di3 = ci3+cr4
-            di4 = ci3-cr4
-            dr5 = cr2+ci5
-            dr2 = cr2-ci5
-            di5 = ci2-cr5
-            di2 = ci2+cr5
-            ch(i-1,k,2) = wa1(i-1)*dr2-wa1(i)*di2
-            ch(i,k,2) = wa1(i-1)*di2+wa1(i)*dr2
-            ch(i-1,k,3) = wa2(i-1)*dr3-wa2(i)*di3
-            ch(i,k,3) = wa2(i-1)*di3+wa2(i)*dr3
-            ch(i-1,k,4) = wa3(i-1)*dr4-wa3(i)*di4
-            ch(i,k,4) = wa3(i-1)*di4+wa3(i)*dr4
-            ch(i-1,k,5) = wa4(i-1)*dr5-wa4(i)*di5
-            ch(i,k,5) = wa4(i-1)*di5+wa4(i)*dr5
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassf.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-      subroutine zpassf (nac,ido,ip,l1,idl1,cc,c1,c2,ch,ch2,wa)
-      implicit double precision (a-h,o-z)
-      dimension       ch(ido,l1,ip)          ,cc(ido,ip,l1)          ,
-     1                c1(ido,l1,ip)          ,wa(1)      ,c2(idl1,ip),
-     2                ch2(idl1,ip)
-      idot = ido/2
-      nt = ip*idl1
-      ipp2 = ip+2
-      ipph = (ip+1)/2
-      idp = ip*ido
-c
-      if (ido .lt. l1) go to 106
-      do 103 j=2,ipph
-         jc = ipp2-j
-         do 102 k=1,l1
-            do 101 i=1,ido
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  101       continue
-  102    continue
-  103 continue
-      do 105 k=1,l1
-         do 104 i=1,ido
-            ch(i,k,1) = cc(i,1,k)
-  104    continue
-  105 continue
-      go to 112
-  106 do 109 j=2,ipph
-         jc = ipp2-j
-         do 108 i=1,ido
-            do 107 k=1,l1
-               ch(i,k,j) = cc(i,j,k)+cc(i,jc,k)
-               ch(i,k,jc) = cc(i,j,k)-cc(i,jc,k)
-  107       continue
-  108    continue
-  109 continue
-      do 111 i=1,ido
-         do 110 k=1,l1
-            ch(i,k,1) = cc(i,1,k)
-  110    continue
-  111 continue
-  112 idl = 2-ido
-      inc = 0
-      do 116 l=2,ipph
-         lc = ipp2-l
-         idl = idl+ido
-         do 113 ik=1,idl1
-            c2(ik,l) = ch2(ik,1)+wa(idl-1)*ch2(ik,2)
-            c2(ik,lc) = -wa(idl)*ch2(ik,ip)
-  113    continue
-         idlj = idl
-         inc = inc+ido
-         do 115 j=3,ipph
-            jc = ipp2-j
-            idlj = idlj+inc
-            if (idlj .gt. idp) idlj = idlj-idp
-            war = wa(idlj-1)
-            wai = wa(idlj)
-            do 114 ik=1,idl1
-               c2(ik,l) = c2(ik,l)+war*ch2(ik,j)
-               c2(ik,lc) = c2(ik,lc)-wai*ch2(ik,jc)
-  114       continue
-  115    continue
-  116 continue
-      do 118 j=2,ipph
-         do 117 ik=1,idl1
-            ch2(ik,1) = ch2(ik,1)+ch2(ik,j)
-  117    continue
-  118 continue
-      do 120 j=2,ipph
-         jc = ipp2-j
-         do 119 ik=2,idl1,2
-            ch2(ik-1,j) = c2(ik-1,j)-c2(ik,jc)
-            ch2(ik-1,jc) = c2(ik-1,j)+c2(ik,jc)
-            ch2(ik,j) = c2(ik,j)+c2(ik-1,jc)
-            ch2(ik,jc) = c2(ik,j)-c2(ik-1,jc)
-  119    continue
-  120 continue
-      nac = 1
-      if (ido .eq. 2) return
-      nac = 0
-      do 121 ik=1,idl1
-         c2(ik,1) = ch2(ik,1)
-  121 continue
-      do 123 j=2,ip
-         do 122 k=1,l1
-            c1(1,k,j) = ch(1,k,j)
-            c1(2,k,j) = ch(2,k,j)
-  122    continue
-  123 continue
-      if (idot .gt. l1) go to 127
-      idij = 0
-      do 126 j=2,ip
-         idij = idij+2
-         do 125 i=4,ido,2
-            idij = idij+2
-            do 124 k=1,l1
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)+wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)-wa(idij)*ch(i-1,k,j)
-  124       continue
-  125    continue
-  126 continue
-      return
-  127 idj = 2-ido
-      do 130 j=2,ip
-         idj = idj+ido
-         do 129 k=1,l1
-            idij = idj
-            do 128 i=4,ido,2
-               idij = idij+2
-               c1(i-1,k,j) = wa(idij-1)*ch(i-1,k,j)+wa(idij)*ch(i,k,j)
-               c1(i,k,j) = wa(idij-1)*ch(i,k,j)-wa(idij)*ch(i-1,k,j)
-  128       continue
-  129    continue
-  130 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassf2.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-      subroutine zpassf2 (ido,l1,cc,ch,wa1)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,2,l1)           ,ch(ido,l1,2)           ,
-     1                wa1(1)
-      if (ido .gt. 2) go to 102
-      do 101 k=1,l1
-         ch(1,k,1) = cc(1,1,k)+cc(1,2,k)
-         ch(1,k,2) = cc(1,1,k)-cc(1,2,k)
-         ch(2,k,1) = cc(2,1,k)+cc(2,2,k)
-         ch(2,k,2) = cc(2,1,k)-cc(2,2,k)
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ch(i-1,k,1) = cc(i-1,1,k)+cc(i-1,2,k)
-            tr2 = cc(i-1,1,k)-cc(i-1,2,k)
-            ch(i,k,1) = cc(i,1,k)+cc(i,2,k)
-            ti2 = cc(i,1,k)-cc(i,2,k)
-            ch(i,k,2) = wa1(i-1)*ti2-wa1(i)*tr2
-            ch(i-1,k,2) = wa1(i-1)*tr2+wa1(i)*ti2
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassf3.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-      subroutine zpassf3 (ido,l1,cc,ch,wa1,wa2)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,3,l1)           ,ch(ido,l1,3)           ,
-     1                wa1(1)     ,wa2(1)
-      data taur,taui /-.5d0,-.866025403784439d0/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         tr2 = cc(1,2,k)+cc(1,3,k)
-         cr2 = cc(1,1,k)+taur*tr2
-         ch(1,k,1) = cc(1,1,k)+tr2
-         ti2 = cc(2,2,k)+cc(2,3,k)
-         ci2 = cc(2,1,k)+taur*ti2
-         ch(2,k,1) = cc(2,1,k)+ti2
-         cr3 = taui*(cc(1,2,k)-cc(1,3,k))
-         ci3 = taui*(cc(2,2,k)-cc(2,3,k))
-         ch(1,k,2) = cr2-ci3
-         ch(1,k,3) = cr2+ci3
-         ch(2,k,2) = ci2+cr3
-         ch(2,k,3) = ci2-cr3
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            tr2 = cc(i-1,2,k)+cc(i-1,3,k)
-            cr2 = cc(i-1,1,k)+taur*tr2
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2
-            ti2 = cc(i,2,k)+cc(i,3,k)
-            ci2 = cc(i,1,k)+taur*ti2
-            ch(i,k,1) = cc(i,1,k)+ti2
-            cr3 = taui*(cc(i-1,2,k)-cc(i-1,3,k))
-            ci3 = taui*(cc(i,2,k)-cc(i,3,k))
-            dr2 = cr2-ci3
-            dr3 = cr2+ci3
-            di2 = ci2+cr3
-            di3 = ci2-cr3
-            ch(i,k,2) = wa1(i-1)*di2-wa1(i)*dr2
-            ch(i-1,k,2) = wa1(i-1)*dr2+wa1(i)*di2
-            ch(i,k,3) = wa2(i-1)*di3-wa2(i)*dr3
-            ch(i-1,k,3) = wa2(i-1)*dr3+wa2(i)*di3
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassf4.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-      subroutine zpassf4 (ido,l1,cc,ch,wa1,wa2,wa3)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,4,l1)           ,ch(ido,l1,4)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti1 = cc(2,1,k)-cc(2,3,k)
-         ti2 = cc(2,1,k)+cc(2,3,k)
-         tr4 = cc(2,2,k)-cc(2,4,k)
-         ti3 = cc(2,2,k)+cc(2,4,k)
-         tr1 = cc(1,1,k)-cc(1,3,k)
-         tr2 = cc(1,1,k)+cc(1,3,k)
-         ti4 = cc(1,4,k)-cc(1,2,k)
-         tr3 = cc(1,2,k)+cc(1,4,k)
-         ch(1,k,1) = tr2+tr3
-         ch(1,k,3) = tr2-tr3
-         ch(2,k,1) = ti2+ti3
-         ch(2,k,3) = ti2-ti3
-         ch(1,k,2) = tr1+tr4
-         ch(1,k,4) = tr1-tr4
-         ch(2,k,2) = ti1+ti4
-         ch(2,k,4) = ti1-ti4
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti1 = cc(i,1,k)-cc(i,3,k)
-            ti2 = cc(i,1,k)+cc(i,3,k)
-            ti3 = cc(i,2,k)+cc(i,4,k)
-            tr4 = cc(i,2,k)-cc(i,4,k)
-            tr1 = cc(i-1,1,k)-cc(i-1,3,k)
-            tr2 = cc(i-1,1,k)+cc(i-1,3,k)
-            ti4 = cc(i-1,4,k)-cc(i-1,2,k)
-            tr3 = cc(i-1,2,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = tr2+tr3
-            cr3 = tr2-tr3
-            ch(i,k,1) = ti2+ti3
-            ci3 = ti2-ti3
-            cr2 = tr1+tr4
-            cr4 = tr1-tr4
-            ci2 = ti1+ti4
-            ci4 = ti1-ti4
-            ch(i-1,k,2) = wa1(i-1)*cr2+wa1(i)*ci2
-            ch(i,k,2) = wa1(i-1)*ci2-wa1(i)*cr2
-            ch(i-1,k,3) = wa2(i-1)*cr3+wa2(i)*ci3
-            ch(i,k,3) = wa2(i-1)*ci3-wa2(i)*cr3
-            ch(i-1,k,4) = wa3(i-1)*cr4+wa3(i)*ci4
-            ch(i,k,4) = wa3(i-1)*ci4-wa3(i)*cr4
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/fftpack/zpassf5.f	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-      subroutine zpassf5 (ido,l1,cc,ch,wa1,wa2,wa3,wa4)
-      implicit double precision (a-h,o-z)
-      dimension       cc(ido,5,l1)           ,ch(ido,l1,5)           ,
-     1                wa1(1)     ,wa2(1)     ,wa3(1)     ,wa4(1)
-      data tr11,ti11,tr12,ti12 /.309016994374947d0,-.951056516295154d0,
-     1-.809016994374947d0,-.587785252292473d0/
-      if (ido .ne. 2) go to 102
-      do 101 k=1,l1
-         ti5 = cc(2,2,k)-cc(2,5,k)
-         ti2 = cc(2,2,k)+cc(2,5,k)
-         ti4 = cc(2,3,k)-cc(2,4,k)
-         ti3 = cc(2,3,k)+cc(2,4,k)
-         tr5 = cc(1,2,k)-cc(1,5,k)
-         tr2 = cc(1,2,k)+cc(1,5,k)
-         tr4 = cc(1,3,k)-cc(1,4,k)
-         tr3 = cc(1,3,k)+cc(1,4,k)
-         ch(1,k,1) = cc(1,1,k)+tr2+tr3
-         ch(2,k,1) = cc(2,1,k)+ti2+ti3
-         cr2 = cc(1,1,k)+tr11*tr2+tr12*tr3
-         ci2 = cc(2,1,k)+tr11*ti2+tr12*ti3
-         cr3 = cc(1,1,k)+tr12*tr2+tr11*tr3
-         ci3 = cc(2,1,k)+tr12*ti2+tr11*ti3
-         cr5 = ti11*tr5+ti12*tr4
-         ci5 = ti11*ti5+ti12*ti4
-         cr4 = ti12*tr5-ti11*tr4
-         ci4 = ti12*ti5-ti11*ti4
-         ch(1,k,2) = cr2-ci5
-         ch(1,k,5) = cr2+ci5
-         ch(2,k,2) = ci2+cr5
-         ch(2,k,3) = ci3+cr4
-         ch(1,k,3) = cr3-ci4
-         ch(1,k,4) = cr3+ci4
-         ch(2,k,4) = ci3-cr4
-         ch(2,k,5) = ci2-cr5
-  101 continue
-      return
-  102 do 104 k=1,l1
-         do 103 i=2,ido,2
-            ti5 = cc(i,2,k)-cc(i,5,k)
-            ti2 = cc(i,2,k)+cc(i,5,k)
-            ti4 = cc(i,3,k)-cc(i,4,k)
-            ti3 = cc(i,3,k)+cc(i,4,k)
-            tr5 = cc(i-1,2,k)-cc(i-1,5,k)
-            tr2 = cc(i-1,2,k)+cc(i-1,5,k)
-            tr4 = cc(i-1,3,k)-cc(i-1,4,k)
-            tr3 = cc(i-1,3,k)+cc(i-1,4,k)
-            ch(i-1,k,1) = cc(i-1,1,k)+tr2+tr3
-            ch(i,k,1) = cc(i,1,k)+ti2+ti3
-            cr2 = cc(i-1,1,k)+tr11*tr2+tr12*tr3
-            ci2 = cc(i,1,k)+tr11*ti2+tr12*ti3
-            cr3 = cc(i-1,1,k)+tr12*tr2+tr11*tr3
-            ci3 = cc(i,1,k)+tr12*ti2+tr11*ti3
-            cr5 = ti11*tr5+ti12*tr4
-            ci5 = ti11*ti5+ti12*ti4
-            cr4 = ti12*tr5-ti11*tr4
-            ci4 = ti12*ti5-ti11*ti4
-            dr3 = cr3-ci4
-            dr4 = cr3+ci4
-            di3 = ci3+cr4
-            di4 = ci3-cr4
-            dr5 = cr2+ci5
-            dr2 = cr2-ci5
-            di5 = ci2-cr5
-            di2 = ci2+cr5
-            ch(i-1,k,2) = wa1(i-1)*dr2+wa1(i)*di2
-            ch(i,k,2) = wa1(i-1)*di2-wa1(i)*dr2
-            ch(i-1,k,3) = wa2(i-1)*dr3+wa2(i)*di3
-            ch(i,k,3) = wa2(i-1)*di3-wa2(i)*dr3
-            ch(i-1,k,4) = wa3(i-1)*dr4+wa3(i)*di4
-            ch(i,k,4) = wa3(i-1)*di4-wa3(i)*dr4
-            ch(i-1,k,5) = wa4(i-1)*dr5+wa4(i)*di5
-            ch(i,k,5) = wa4(i-1)*di5-wa4(i)*dr5
-  103    continue
-  104 continue
-      return
-      end
--- a/liboctave/external/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/external/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -14,7 +14,6 @@
 include %reldir%/dasrt/module.mk
 include %reldir%/dassl/module.mk
 include %reldir%/Faddeeva/module.mk
-include %reldir%/fftpack/module.mk
 include %reldir%/lapack-xtra/module.mk
 include %reldir%/odepack/module.mk
 include %reldir%/quadpack/module.mk
@@ -38,10 +37,6 @@
 
 %canon_reldir%_libexternal_la_CPPFLAGS = $(liboctave_liboctave_la_CPPFLAGS)
 
-%canon_reldir%_libexternal_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_libexternal_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/libexternal.la
 
 liboctave_EXTRA_DIST += \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/mk-version-h.in.sh	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,41 @@
+#! /bin/sh
+#
+# Copyright (C) 2016-2018 John W. Eaton
+#
+# 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_API_VERSION="@OCTAVE_API_VERSION@"
+OCTAVE_CANONICAL_HOST_TYPE="@canonical_host_type@"
+OCTAVE_COPYRIGHT="@OCTAVE_COPYRIGHT@"
+OCTAVE_MAJOR_VERSION="@OCTAVE_MAJOR_VERSION@"
+OCTAVE_MINOR_VERSION="@OCTAVE_MINOR_VERSION@"
+OCTAVE_PATCH_VERSION="@OCTAVE_PATCH_VERSION@"
+OCTAVE_RELEASE_DATE="@OCTAVE_RELEASE_DATE@"
+OCTAVE_VERSION="@OCTAVE_VERSION@"
+
+$SED \
+  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by mk-version-h.|" \
+  -e "s|%OCTAVE_API_VERSION%|\"${OCTAVE_API_VERSION}\"|" \
+  -e "s|%OCTAVE_CANONICAL_HOST_TYPE%|\"${OCTAVE_CANONICAL_HOST_TYPE}\"|" \
+  -e "s|%OCTAVE_COPYRIGHT%|\"${OCTAVE_COPYRIGHT}\"|" \
+  -e "s|%OCTAVE_MAJOR_VERSION%|${OCTAVE_MAJOR_VERSION}|" \
+  -e "s|%OCTAVE_MINOR_VERSION%|${OCTAVE_MINOR_VERSION}|" \
+  -e "s|%OCTAVE_PATCH_VERSION%|${OCTAVE_PATCH_VERSION}|" \
+  -e "s|%OCTAVE_RELEASE_DATE%|\"${OCTAVE_RELEASE_DATE}\"|" \
+  -e "s|%OCTAVE_VERSION%|\"${OCTAVE_VERSION}\"|"
--- a/liboctave/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -1,5 +1,11 @@
 %canon_reldir%_EXTRA_DIST = \
-  %reldir%/liboctave-build-info.in.cc
+  %reldir%/liboctave-build-info.in.cc \
+  %reldir%/mk-version-h.in.sh \
+  %reldir%/version.cc \
+  %reldir%/version.in.h
+
+GEN_CONFIG_SHELL += \
+  %reldir%/mk-version-h.sh
 
 %canon_reldir%_CLEANFILES =
 %canon_reldir%_DISTCLEANFILES =
@@ -17,11 +23,9 @@
   -I$(srcdir)/%reldir%/util \
   -I$(srcdir)/%reldir%/wrappers
 
-%canon_reldir%_%canon_reldir%_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
+octlib_LTLIBRARIES += %reldir%/liboctave.la
 
-%canon_reldir%_%canon_reldir%_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
-
-octlib_LTLIBRARIES += %reldir%/liboctave.la
+%canon_reldir%_pkgconfig_DATA = %reldir%/octave.pc
 
 BUILT_INCS = \
   $(BUILT_LIBOCTAVE_OPERATORS_INC) \
@@ -29,10 +33,12 @@
 
 BUILT_SOURCES += \
   $(BUILT_INCS) \
-  $(BUILT_LIBOCTAVE_OPERATORS_SOURCES)
+  $(BUILT_LIBOCTAVE_OPERATORS_SOURCES) \
+  %reldir%/version.h
 
 LIBOCTAVE_BUILT_NODISTFILES = \
-  %reldir%/liboctave-build-info.cc
+  %reldir%/liboctave-build-info.cc \
+  %reldir%/version.h
 
 octinclude_HEADERS += \
   %reldir%/liboctave-build-info.h \
@@ -45,7 +51,9 @@
   $(OTHER_INC) \
   $(LIBOCTAVE_TEMPLATE_SRC)
 
-nodist_octinclude_HEADERS += $(BUILT_INCS)
+nodist_octinclude_HEADERS += \
+  $(BUILT_INCS) \
+  %reldir%/version.h
 
 ## C++ files that are #included, not compiled
 OTHER_INC =
@@ -66,13 +74,17 @@
 include %reldir%/wrappers/module.mk
 
 nodist_%canon_reldir%_%canon_reldir%_la_SOURCES = \
-  %reldir%/liboctave-build-info.cc
+  %reldir%/liboctave-build-info.cc \
+  %reldir%/version.cc \
+  %reldir%/version.h
 
 %canon_reldir%_%canon_reldir%_la_LIBADD += \
   libgnu/libgnu.la \
   $(LIBOCTAVE_LINK_DEPS)
 
-# Increment these as needed and according to the rules in the libtool manual:
+## Increment the following version numbers as needed and according
+## to the rules in the etc/HACKING.md file:
+
 %canon_reldir%_%canon_reldir%_current = 6
 %canon_reldir%_%canon_reldir%_revision = 0
 %canon_reldir%_%canon_reldir%_age = 0
@@ -104,6 +116,9 @@
 
 nobase_liboctavetests_DATA = $(LIBOCTAVE_TST_FILES)
 
+%reldir%/version.h: %reldir%/version.in.h %reldir%/mk-version-h.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,%reldir%/mk-version-h.sh)
+
 %reldir%/liboctave-build-info.cc: %reldir%/liboctave-build-info.in.cc HG-ID | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)$(build-info-commands)
 
@@ -112,12 +127,17 @@
 
 DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
 
+pkgconfig_DATA += $(%canon_reldir%_pkgconfig_DATA)
+
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
 
 %canon_reldir%_CLEANFILES += \
   $(LIBOCTAVE_BUILT_NODISTFILES) \
   $(LIBOCTAVE_TST_FILES)
 
+%canon_reldir%_DISTCLEANFILES += \
+  $(%canon_reldir%_pkgconfig_DATA)
+
 BUILT_NODISTFILES += $(LIBOCTAVE_BUILT_NODISTFILES)
 
 CLEANFILES += $(%canon_reldir%_CLEANFILES)
--- a/liboctave/numeric/CollocWt.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/CollocWt.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,8 +27,8 @@
 #include <cassert>
 #include <cmath>
 
-#include <iostream>
 #include <limits>
+#include <ostream>
 
 #include "Array.h"
 #include "CollocWt.h"
--- a/liboctave/numeric/eigs-base.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/eigs-base.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 #endif
 
 #include <cmath>
-#include <iostream>
+
+#include <ostream>
 
 #include "Array.h"
 #include "CSparse.h"
@@ -56,6 +57,160 @@
      "an eigenvalue so convergence is not guaranteed");
 }
 
+// Conversion from error number to strings
+std::string
+arpack_errno2str (const octave_idx_type& errnum, const std::string& fcn_name)
+{
+  std::string msg;
+  std::string bug_msg = "\nThis should not happen.  Please, see https://www.gnu.org/software/octave/bugs.html, and file a bug report";
+
+  switch (errnum)
+    {
+    case -1:
+      msg = "N must be positive";
+      break;
+
+    case -2:
+      msg = "NEV must be positive";
+      break;
+
+    case -3:
+      msg = "NCV-NEV >= 2 and less than or equal to N";
+      break;
+
+    case -4:
+      msg = "The maximum number of Arnoldi update iterations allowed must be greater than zero";
+      break;
+
+    case -5:
+      msg = "WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI'";
+      break;
+
+    case -6:
+      msg = "BMAT must be one of 'I' or 'G'";
+      break;
+
+    case -7:
+      msg = "Length of private work WORKL array is insufficient";
+      break;
+
+    case -8:
+      msg = "Error return from LAPACK eigenvalue calculation";
+      break;
+
+    case -9:
+      if (fcn_name.compare ("zneupd") == 0)
+        msg = "Error return from calculation of eigenvectors.  Informational error from LAPACK routine ztrevc";
+      else if (fcn_name.compare ("dneupd") == 0)
+        msg = "Error return from calculation of eigenvectors.  Informational error from LAPACK routine dtrevc";
+      else
+        msg = "Starting vector is zero";
+
+      break;
+
+    case -10:
+      if (fcn_name.compare ("dneupd") == 0 ||
+          fcn_name.compare ("dnaupd") == 0)
+        msg = "IPARAM(7) must be 1,2,3,4";
+      else if (fcn_name.compare ("zneupd") == 0 ||
+               fcn_name.compare ("znaupd") == 0)
+        msg = "IPARAM(7) must be 1,2,3";
+      else
+        msg = "IPARAM(7) must be 1,2,3,4,5";
+
+      break;
+
+    case -11:
+      msg = "IPARAM(7) = 1 and BMAT = 'G' are incompatible";
+      break;
+
+    case -12:
+      if (fcn_name.compare ("dnaupd") == 0 ||
+          fcn_name.compare ("znaupd") == 0 ||
+          fcn_name.compare ("dsaupd") == 0)
+        msg = std::string ("IPARAM(1) must be equal to 0 or 1");
+      else if (fcn_name.compare ("dneupd") == 0 ||
+               fcn_name.compare ("zneupd") == 0)
+        msg = "HOWMNY = 'S' not yet implemented";
+      else
+        msg = "NEV and WHICH = 'BE' are incompatible";
+
+      break;
+
+    case -13:
+      if (fcn_name.compare ("dneupd") == 0 ||
+          fcn_name.compare ("zneupd") == 0)
+        msg = "HOWMNY must be one of 'A' or 'P' if RVEC = .true.";
+      else if (fcn_name.compare ("dsaupd") == 0)
+        msg = "NEV and WHICH = 'BE' are incompatible";
+
+      break;
+
+    case -14:
+      if (fcn_name.compare ("dneupd") == 0)
+        msg = "DNAUPD did not find any eigenvalues to sufficient accuracy.";
+      else if (fcn_name.compare ("zneupd") == 0)
+        msg = "ZNAUPD did not find any eigenvalues to sufficient accuracy.";
+      else if (fcn_name.compare ("dseupd") == 0)
+        msg = "DSAUPD did not find any eigenvalues to sufficient accuracy.";
+
+      break;
+
+    case -15:
+      if (fcn_name.compare ("dseupd") == 0)
+        msg = "HOWMNY must be one of 'A' or 'S' if RVEC = .true.";
+
+      break;
+
+    case -16:
+      if (fcn_name.compare ("dseupd") == 0)
+        msg = "HOWMNY = 'S' not yet implemented";
+
+      break;
+
+    case -9999:
+      if (fcn_name.compare ("dnaupd") == 0)
+        msg = "Could not build an Arnoldi factorization.  IPARAM(5) returns the size of the current Arnoldi factorization";
+
+      break;
+
+    case 1:
+      if (fcn_name.compare ("dneupd") == 0)
+        msg = "The Schur form computed by LAPACK routine dlahqr could not be reordered by LAPACK routine dtrsen.  Re-enter subroutine DNEUPD with IPARAM(5)=NCV and increase the size of the arrays DR and DI to have dimension at least dimension NCV and allocate at least NCV columns for Z.  NOTE: Not necessary if Z and V share the same space.  Please notify the authors if this error occurs.";
+      else if (fcn_name.compare ("dnaupd") == 0 ||
+               fcn_name.compare ("znaupd") == 0 ||
+               fcn_name.compare ("dsaupd") == 0)
+        msg = "Maximum number of iterations taken.  All possible eigenvalues of OP has been found.  IPARAM(5) returns the number of wanted converged Ritz values";
+      else if (fcn_name.compare ("znaupd") == 0)
+        msg = "The Schur form computed by LAPACK routine csheqr could not be reordered by LAPACK routine ztrsen.  Re-enter subroutine ZNEUPD with IPARAM(5)=NCV and increase the size of the array D to have dimension at least dimension NCV and allocate at least NCV columns for Z.  NOTE: Not necessary if Z and V share the same space.  Please notify the authors if this error occurs.";
+
+      break;
+
+    case 2:
+      if (fcn_name.compare ("dnaupd") == 0 ||
+          fcn_name.compare ("znaupd") == 0 ||
+          fcn_name.compare ("dsaupd") == 0)
+        msg = "No longer an informational error.  Deprecated starting with release 2 of ARPACK.";
+
+      break;
+
+    case 3:
+      if (fcn_name.compare ("dnaupd") == 0 ||
+          fcn_name.compare ("znaupd") == 0 ||
+          fcn_name.compare ("dsaupd") == 0)
+        msg = "No shifts could be applied during a cycle of the implicitly restarted Arnoldi iteration.  One possibility is to increase the size of NCV relative to NEV.";
+
+      break;
+
+    }
+
+  if ((errno != -9) & (errno != -14) & (errno != -9999))
+    // This is a bug in Octave interface to ARPACK
+    msg.append (bug_msg);
+
+  return msg;
+}
+
 template <typename M, typename SM>
 static octave_idx_type
 lusolve (const SM& L, const SM& U, M& m)
@@ -90,7 +245,7 @@
   for (octave_idx_type j = 0; j < b_nc; j++)
     {
       for (octave_idx_type i = 0; i < n; i++)
-        retval.elem (i,j) = m.elem (static_cast<octave_idx_type>(qv[i]), j);
+        retval.elem (i,j) = m.elem (static_cast<octave_idx_type> (qv[i]), j);
     }
   return L.solve (ltyp, retval, err, rcond, nullptr);
 }
@@ -115,7 +270,7 @@
       for (octave_idx_type j = 0; j < b_nc; j++)
         {
           for (octave_idx_type i = 0; i < n; i++)
-            retval.elem (static_cast<octave_idx_type>(qv[i]), j) =
+            retval.elem (static_cast<octave_idx_type> (qv[i]), j) =
               tmp.elem (i,j);
         }
     }
@@ -272,45 +427,48 @@
   // P * (R \ M) * Q = L * U
   SparseMatrix AminusSigmaB (m);
 
-  if (have_b)
+  if (sigma != 0.0)
     {
-      if (cholB)
+      if (have_b)
         {
-          if (permB.numel ())
+          if (cholB)
             {
-              SparseMatrix tmp (n,n,n);
-              for (octave_idx_type i = 0; i < n; i++)
+              if (permB.numel ())
                 {
-                  tmp.xcidx (i) = i;
-                  tmp.xridx (i) =
-                    static_cast<octave_idx_type>(permB(i));
-                  tmp.xdata (i) = 1;
+                  SparseMatrix tmp (n,n,n);
+                  for (octave_idx_type i = 0; i < n; i++)
+                    {
+                      tmp.xcidx (i) = i;
+                      tmp.xridx (i) =
+                        static_cast<octave_idx_type> (permB(i));
+                      tmp.xdata (i) = 1;
+                    }
+                  tmp.xcidx (n) = n;
+
+                  AminusSigmaB -= sigma * tmp *
+                    b.transpose () * b * tmp.transpose ();
                 }
-              tmp.xcidx (n) = n;
-
-              AminusSigmaB -= sigma * tmp *
-                              b.transpose () * b * tmp.transpose ();
+              else
+                AminusSigmaB -= sigma * b.transpose () * b;
             }
           else
-            AminusSigmaB -= sigma * b.transpose () * b;
+            AminusSigmaB -= sigma * b;
         }
       else
-        AminusSigmaB -= sigma * b;
-    }
-  else
-    {
-      SparseMatrix sigmat (n, n, n);
-
-      // Create sigma * speye (n,n)
-      sigmat.xcidx (0) = 0;
-      for (octave_idx_type i = 0; i < n; i++)
         {
-          sigmat.xdata (i) = sigma;
-          sigmat.xridx (i) = i;
-          sigmat.xcidx (i+1) = i + 1;
+          SparseMatrix sigmat (n, n, n);
+
+          // Create sigma * speye (n,n)
+          sigmat.xcidx (0) = 0;
+          for (octave_idx_type i = 0; i < n; i++)
+            {
+              sigmat.xdata (i) = sigma;
+              sigmat.xridx (i) = i;
+              sigmat.xcidx (i+1) = i + 1;
+            }
+
+          AminusSigmaB -= sigmat;
         }
-
-      AminusSigmaB -= sigmat;
     }
 
   octave::math::sparse_lu<SparseMatrix> fact (AminusSigmaB, Matrix (), true);
@@ -369,40 +527,43 @@
   // P * M = L * U
   Matrix AminusSigmaB (m);
 
-  if (have_b)
+  if (sigma != 0.0)
     {
-      if (cholB)
+      if (have_b)
         {
-          Matrix tmp = sigma * b.transpose () * b;
-          const double *pB = permB.fortran_vec ();
-          double *p = AminusSigmaB.fortran_vec ();
-
-          if (permB.numel ())
+          if (cholB)
             {
-              for (octave_idx_type j = 0;
-                   j < b.cols (); j++)
-                for (octave_idx_type i = 0;
-                     i < b.rows (); i++)
-                  *p++ -= tmp.xelem (static_cast<octave_idx_type>(pB[i]),
-                                     static_cast<octave_idx_type>(pB[j]));
+              Matrix tmp = sigma * b.transpose () * b;
+              const double *pB = permB.fortran_vec ();
+              double *p = AminusSigmaB.fortran_vec ();
+
+              if (permB.numel ())
+                {
+                  for (octave_idx_type j = 0;
+                       j < b.cols (); j++)
+                    for (octave_idx_type i = 0;
+                         i < b.rows (); i++)
+                      *p++ -= tmp.xelem (static_cast<octave_idx_type> (pB[i]),
+                                         static_cast<octave_idx_type> (pB[j]));
+                }
+              else
+                AminusSigmaB -= tmp;
             }
           else
-            AminusSigmaB -= tmp;
+            AminusSigmaB -= sigma * b;
         }
       else
-        AminusSigmaB -= sigma * b;
-    }
-  else
-    {
-      double *p = AminusSigmaB.fortran_vec ();
-
-      for (octave_idx_type i = 0; i < n; i++)
-        p[i*(n+1)] -= sigma;
+        {
+          double *p = AminusSigmaB.fortran_vec ();
+
+          for (octave_idx_type i = 0; i < n; i++)
+            p[i*(n+1)] -= sigma;
+        }
     }
 
   octave::math::lu<Matrix> fact (AminusSigmaB);
 
-  L = fact. L ();
+  L = fact.L ();
   U = fact.U ();
   ColumnVector P2 = fact.P_vec();
 
@@ -448,45 +609,48 @@
   // P * (R \ M) * Q = L * U
   SparseComplexMatrix AminusSigmaB (m);
 
-  if (have_b)
+  if (std::real (sigma) != 0.0 || std::imag (sigma) != 0.0)
     {
-      if (cholB)
+      if (have_b)
         {
-          if (permB.numel ())
+          if (cholB)
             {
-              SparseMatrix tmp (n,n,n);
-              for (octave_idx_type i = 0; i < n; i++)
+              if (permB.numel ())
                 {
-                  tmp.xcidx (i) = i;
-                  tmp.xridx (i) =
-                    static_cast<octave_idx_type>(permB(i));
-                  tmp.xdata (i) = 1;
+                  SparseMatrix tmp (n,n,n);
+                  for (octave_idx_type i = 0; i < n; i++)
+                    {
+                      tmp.xcidx (i) = i;
+                      tmp.xridx (i) =
+                        static_cast<octave_idx_type> (permB(i));
+                      tmp.xdata (i) = 1;
+                    }
+                  tmp.xcidx (n) = n;
+
+                  AminusSigmaB -= tmp * b.hermitian () * b *
+                    tmp.transpose () * sigma;
                 }
-              tmp.xcidx (n) = n;
-
-              AminusSigmaB -= tmp * b.hermitian () * b *
-                              tmp.transpose () * sigma;
+              else
+                AminusSigmaB -= sigma * b.hermitian () * b;
             }
           else
-            AminusSigmaB -= sigma * b.hermitian () * b;
+            AminusSigmaB -= sigma * b;
         }
       else
-        AminusSigmaB -= sigma * b;
-    }
-  else
-    {
-      SparseComplexMatrix sigmat (n, n, n);
-
-      // Create sigma * speye (n,n)
-      sigmat.xcidx (0) = 0;
-      for (octave_idx_type i = 0; i < n; i++)
         {
-          sigmat.xdata (i) = sigma;
-          sigmat.xridx (i) = i;
-          sigmat.xcidx (i+1) = i + 1;
+          SparseComplexMatrix sigmat (n, n, n);
+
+          // Create sigma * speye (n,n)
+          sigmat.xcidx (0) = 0;
+          for (octave_idx_type i = 0; i < n; i++)
+            {
+              sigmat.xdata (i) = sigma;
+              sigmat.xridx (i) = i;
+              sigmat.xcidx (i+1) = i + 1;
+            }
+
+          AminusSigmaB -= sigmat;
         }
-
-      AminusSigmaB -= sigmat;
     }
 
   octave::math::sparse_lu<SparseComplexMatrix> fact (AminusSigmaB, Matrix(),
@@ -546,35 +710,38 @@
   // P * M = L * U
   ComplexMatrix AminusSigmaB (m);
 
-  if (have_b)
+  if (std::real (sigma) != 0.0 || std::imag (sigma) != 0.0)
     {
-      if (cholB)
+      if (have_b)
         {
-          ComplexMatrix tmp = sigma * b.hermitian () * b;
-          const double *pB = permB.fortran_vec ();
-          Complex *p = AminusSigmaB.fortran_vec ();
-
-          if (permB.numel ())
+          if (cholB)
             {
-              for (octave_idx_type j = 0;
-                   j < b.cols (); j++)
-                for (octave_idx_type i = 0;
-                     i < b.rows (); i++)
-                  *p++ -= tmp.xelem (static_cast<octave_idx_type>(pB[i]),
-                                     static_cast<octave_idx_type>(pB[j]));
+              ComplexMatrix tmp = sigma * b.hermitian () * b;
+              const double *pB = permB.fortran_vec ();
+              Complex *p = AminusSigmaB.fortran_vec ();
+
+              if (permB.numel ())
+                {
+                  for (octave_idx_type j = 0;
+                       j < b.cols (); j++)
+                    for (octave_idx_type i = 0;
+                         i < b.rows (); i++)
+                      *p++ -= tmp.xelem (static_cast<octave_idx_type> (pB[i]),
+                                         static_cast<octave_idx_type> (pB[j]));
+                }
+              else
+                AminusSigmaB -= tmp;
             }
           else
-            AminusSigmaB -= tmp;
+            AminusSigmaB -= sigma * b;
         }
       else
-        AminusSigmaB -= sigma * b;
-    }
-  else
-    {
-      Complex *p = AminusSigmaB.fortran_vec ();
-
-      for (octave_idx_type i = 0; i < n; i++)
-        p[i*(n+1)] -= sigma;
+        {
+          Complex *p = AminusSigmaB.fortran_vec ();
+
+          for (octave_idx_type i = 0; i < n; i++)
+            p[i*(n+1)] -= sigma;
+        }
     }
 
   octave::math::lu<ComplexMatrix> fact (AminusSigmaB);
@@ -641,10 +808,10 @@
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -813,7 +980,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dsaupd", info);
+              ("eigs: error in dsaupd: %s",
+               arpack_errno2str (info, "dsaupd").c_str ());
 
           break;
         }
@@ -896,7 +1064,9 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dseupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dseupd: %s",
+       arpack_errno2str (info2, "dseupd").c_str ());
 
   return ip(4);
 }
@@ -933,10 +1103,10 @@
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -1122,7 +1292,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dsaupd", info);
+              ("eigs: error in dsaupd: %s",
+               arpack_errno2str (info, "dsaupd").c_str ());
 
           break;
         }
@@ -1196,35 +1367,43 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dseupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dseupd: %s",
+       arpack_errno2str (info2, "dseupd").c_str ());
 
   return ip(4);
 }
 
+template <typename M>
 octave_idx_type
 EigsRealSymmetricFunc (EigsFunc fun, octave_idx_type n_arg,
                        const std::string& _typ, double sigma,
                        octave_idx_type k_arg, octave_idx_type p_arg,
                        octave_idx_type& info, Matrix& eig_vec,
-                       ColumnVector& eig_val, ColumnVector& resid,
+                       ColumnVector& eig_val, const M& _b,
+                       ColumnVector& permB, ColumnVector& resid,
                        std::ostream& os, double tol, bool rvec,
-                       bool /* cholB */, int disp, int maxit)
+                       bool cholB, int disp, int maxit)
 {
   F77_INT n = octave::to_f77_int (n_arg);
   F77_INT k = octave::to_f77_int (k_arg);
   F77_INT p = octave::to_f77_int (p_arg);
+  M b(_b);
   std::string typ (_typ);
   bool have_sigma = (sigma ? true : false);
+  bool have_b = ! b.isempty ();
+  bool note3 = false;
   char bmat = 'I';
   F77_INT mode = 1;
   int err = 0;
+  M bt;
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (n != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -1253,6 +1432,23 @@
     (*current_liboctave_error_handler)
       ("eigs: opts.p must be greater than k and less than or equal to n");
 
+  if (have_b && cholB && ! permB.isempty ())
+    {
+      // Check the we really have a permutation vector
+      if (permB.numel () != n)
+        (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+
+      Array<bool> checked (dim_vector (n, 1), false);
+      for (F77_INT i = 0; i < n; i++)
+        {
+          octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
+
+          if (checked(bidx) || bidx < 0 || bidx >= n
+              || octave::math::x_nint (bidx) != bidx)
+            (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+        }
+    }
+
   if (! have_sigma)
     {
       if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
@@ -1264,19 +1460,53 @@
         (*current_liboctave_error_handler)
           ("eigs: invalid sigma value for real symmetric problem");
 
+      if (typ != "SM" && have_b)
+        note3 = true;
+
       if (typ == "SM")
         {
           typ = "LM";
           sigma = 0.;
           mode = 3;
+          if (have_b)
+            bmat = 'G';
         }
     }
   else if (! std::abs (sigma))
-    typ = "SM";
+    {
+      typ = "SM";
+      if (have_b)
+        bmat = 'G';
+    }
   else
     {
       typ = "LM";
       mode = 3;
+      if (have_b)
+        bmat = 'G';
+    }
+
+  if (mode == 1 && have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+        {
+          bt = b;
+          b = b.transpose ();
+          if (permB.isempty ())
+            {
+              permB = ColumnVector (n);
+              for (F77_INT i = 0; i < n; i++)
+                permB(i) = i;
+            }
+        }
+      else
+        {
+          if (! make_cholb (b, bt, permB))
+            (*current_liboctave_error_handler)
+              ("eigs: The matrix B is not positive definite");
+        }
     }
 
   Array<F77_INT> ip (dim_vector (11, 1));
@@ -1351,26 +1581,92 @@
 
       if (ido == -1 || ido == 1 || ido == 2)
         {
-          double *ip2 = workd + iptr(0) - 1;
-          ColumnVector x(n);
-
-          for (F77_INT i = 0; i < n; i++)
-            x(i) = *ip2++;
-
-          ColumnVector y = fun (x, err);
-
-          if (err)
-            return false;
-
-          ip2 = workd + iptr(1) - 1;
-          for (F77_INT i = 0; i < n; i++)
-            *ip2++ = y(i);
+          if (have_b)
+            {
+              if (mode == 1) // regular mode with factorized B
+                {
+                  Matrix mtmp (n,1);
+                  for (F77_INT i = 0; i < n; i++)
+                    mtmp(i,0) = workd[i + iptr(0) - 1];
+
+                  mtmp = utsolve (bt, permB, mtmp);
+                  ColumnVector y = fun (mtmp, err);
+
+                  if (err)
+                    return false;
+
+                  mtmp = ltsolve (b, permB, y);
+
+                  for (F77_INT i = 0; i < n; i++)
+                    workd[i+iptr(1)-1] = mtmp(i,0);
+                }
+              else // shift-invert mode
+                {
+                  if (ido == -1)
+                    {
+                      OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                      vector_product (b, workd+iptr(0)-1, dtmp);
+
+                      ColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = dtmp[i];
+
+                      ColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      double *ip2 = workd + iptr(1) - 1;
+                      for (F77_INT i = 0; i < n; i++)
+                        ip2[i] = y(i);
+                    }
+                  else if (ido == 2)
+                    vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
+                  else
+                    {
+                      double *ip2 = workd+iptr(2)-1;
+                      ColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = *ip2++;
+
+                      ColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      ip2 = workd + iptr(1) - 1;
+                      for (F77_INT i = 0; i < n; i++)
+                        *ip2++ = y(i);
+                     }
+                }
+            }
+          else
+            {
+              double *ip2 = workd + iptr(0) - 1;
+              ColumnVector x(n);
+
+              for (F77_INT i = 0; i < n; i++)
+                x(i) = *ip2++;
+
+              ColumnVector y = fun (x, err);
+
+              if (err)
+                return false;
+
+              ip2 = workd + iptr(1) - 1;
+              for (F77_INT i = 0; i < n; i++)
+                *ip2++ = y(i);
+            }
         }
       else
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dsaupd", info);
+              ("eigs: error in dsaupd: %s",
+               arpack_errno2str (info, "dsaupd").c_str ());
 
           break;
         }
@@ -1407,7 +1703,7 @@
       for (F77_INT i = ip(4); i < k; i++)
         d[i] = octave::numeric_limits<double>::NaN ();
       F77_INT k2 = ip(4) / 2;
-      if (typ != "SM" && typ != "BE")
+      if (mode == 3 || (mode == 1 && typ != "SM" && typ != "BE"))
         {
           for (F77_INT i = 0; i < k2; i++)
             {
@@ -1425,7 +1721,7 @@
               for (F77_INT j = 0; j < n; j++)
                 z[off1 + j] = octave::numeric_limits<double>::NaN ();
             }
-          if (typ != "SM" && typ != "BE")
+          if (mode == 3 || (mode == 1 && typ != "SM" && typ != "BE"))
             {
               OCTAVE_LOCAL_BUFFER (double, dtmp, n);
 
@@ -1447,10 +1743,14 @@
                     z[off2 + j] = dtmp[j];
                 }
             }
-        }
+          if (note3)
+            eig_vec = utsolve (bt, permB, eig_vec);
+         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dseupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dseupd: %s",
+       arpack_errno2str (info2, "dseupd").c_str ());
 
   return ip(4);
 }
@@ -1485,10 +1785,10 @@
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -1661,7 +1961,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dnaupd", info);
+              ("eigs: error in dnaupd: %s",
+               arpack_errno2str (info, "dnaupd").c_str ());
 
           break;
         }
@@ -1801,7 +2102,9 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dneupd: %s",
+       arpack_errno2str (info2, "dneupd").c_str ());
 
   return ip(4);
 }
@@ -1840,10 +2143,10 @@
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -2034,7 +2337,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dnaupd", info);
+              ("eigs: error in dnaupd: %s",
+               arpack_errno2str (info, "dnaupd").c_str ());
 
           break;
         }
@@ -2173,36 +2477,44 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dneupd: %s",
+       arpack_errno2str (info2, "dneupd").c_str ());
 
   return ip(4);
 }
 
+template <typename M>
 octave_idx_type
 EigsRealNonSymmetricFunc (EigsFunc fun, octave_idx_type n_arg,
                           const std::string& _typ, double sigmar,
                           octave_idx_type k_arg, octave_idx_type p_arg,
                           octave_idx_type& info, ComplexMatrix& eig_vec,
-                          ComplexColumnVector& eig_val, ColumnVector& resid,
+                          ComplexColumnVector& eig_val, const M& _b,
+                          ColumnVector& permB, ColumnVector& resid,
                           std::ostream& os, double tol, bool rvec,
-                          bool /* cholB */, int disp, int maxit)
+                          bool cholB, int disp, int maxit)
 {
   F77_INT n = octave::to_f77_int (n_arg);
   F77_INT k = octave::to_f77_int (k_arg);
   F77_INT p = octave::to_f77_int (p_arg);
+  M b(_b);
   std::string typ (_typ);
   bool have_sigma = (sigmar ? true : false);
-  char bmat = 'I';
   double sigmai = 0.;
   F77_INT mode = 1;
+  bool have_b = ! b.isempty ();
+  bool note3 = false;
+  char bmat = 'I';
   int err = 0;
+  M bt;
 
   if (resid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      resid = ColumnVector (octave_rand::vector (n));
-      octave_rand::distribution (rand_dist);
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      resid = ColumnVector (octave::rand::vector (n));
+      octave::rand::distribution (rand_dist);
     }
   else if (n != resid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -2231,6 +2543,23 @@
     (*current_liboctave_error_handler)
       ("eigs: opts.p must be greater than k and less than or equal to n");
 
+  if (have_b && cholB && ! permB.isempty ())
+    {
+      // Check the we really have a permutation vector
+      if (permB.numel () != n)
+        (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+
+      Array<bool> checked (dim_vector (n, 1), false);
+      for (F77_INT i = 0; i < n; i++)
+        {
+          octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
+
+          if (checked(bidx) || bidx < 0 || bidx >= n
+              || octave::math::x_nint (bidx) != bidx)
+            (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+        }
+    }
+
   if (! have_sigma)
     {
       if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
@@ -2242,19 +2571,53 @@
         (*current_liboctave_error_handler)
           ("eigs: invalid sigma value for unsymmetric problem");
 
+      if (typ != "SM" && have_b)
+        note3 = true;
+
       if (typ == "SM")
         {
           typ = "LM";
           sigmar = 0.;
           mode = 3;
+          if (have_b)
+            bmat = 'G';
         }
+   }
+  else if (! std::abs (sigmar))
+    {
+      typ = "SM";
+      if (have_b)
+        bmat = 'G';
     }
-  else if (! std::abs (sigmar))
-    typ = "SM";
   else
     {
       typ = "LM";
       mode = 3;
+      if (have_b)
+        bmat = 'G';
+    }
+
+  if (mode == 1 && have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+        {
+          bt = b;
+          b = b.transpose ();
+          if (permB.isempty ())
+            {
+              permB = ColumnVector (n);
+              for (F77_INT i = 0; i < n; i++)
+                permB(i) = i;
+            }
+        }
+      else
+        {
+          if (! make_cholb (b, bt, permB))
+            (*current_liboctave_error_handler)
+              ("eigs: The matrix B is not positive definite");
+        }
     }
 
   Array<F77_INT> ip (dim_vector (11, 1));
@@ -2333,26 +2696,92 @@
 
       if (ido == -1 || ido == 1 || ido == 2)
         {
-          double *ip2 = workd + iptr(0) - 1;
-          ColumnVector x(n);
-
-          for (F77_INT i = 0; i < n; i++)
-            x(i) = *ip2++;
-
-          ColumnVector y = fun (x, err);
-
-          if (err)
-            return false;
-
-          ip2 = workd + iptr(1) - 1;
-          for (F77_INT i = 0; i < n; i++)
-            *ip2++ = y(i);
+          if (have_b)
+            {
+              if (mode == 1) // regular mode with factorized B
+                {
+                  Matrix mtmp (n,1);
+                  for (F77_INT i = 0; i < n; i++)
+                    mtmp(i,0) = workd[i + iptr(0) - 1];
+
+                  mtmp = utsolve (bt, permB, mtmp);
+                  ColumnVector y = fun (mtmp, err);
+
+                  if (err)
+                    return false;
+
+                  mtmp = ltsolve (b, permB, y);
+
+                  for (F77_INT i = 0; i < n; i++)
+                    workd[i+iptr(1)-1] = mtmp(i,0);
+                }
+              else // shift-invert mode
+                {
+                  if (ido == -1)
+                    {
+                      OCTAVE_LOCAL_BUFFER (double, dtmp, n);
+
+                      vector_product (b, workd+iptr(0)-1, dtmp);
+
+                      ColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = dtmp[i];
+
+                      ColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      double *ip2 = workd + iptr(1) - 1;
+                      for (F77_INT i = 0; i < n; i++)
+                        ip2[i] = y(i);
+                    }
+                  else if (ido == 2)
+                    vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
+                  else
+                    {
+                      double *ip2 = workd+iptr(2)-1;
+                      ColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = *ip2++;
+
+                      ColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      ip2 = workd + iptr(1) - 1;
+                      for (F77_INT i = 0; i < n; i++)
+                        *ip2++ = y(i);
+                     }
+                }
+            }
+          else
+            {
+              double *ip2 = workd + iptr(0) - 1;
+              ColumnVector x(n);
+
+              for (F77_INT i = 0; i < n; i++)
+                x(i) = *ip2++;
+
+              ColumnVector y = fun (x, err);
+
+              if (err)
+                return false;
+
+              ip2 = workd + iptr(1) - 1;
+              for (F77_INT i = 0; i < n; i++)
+                *ip2++ = y(i);
+            }
         }
       else
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in dnaupd", info);
+              ("eigs: error in dnaupd: %s",
+               arpack_errno2str (info, "dnaupd").c_str ());
 
           break;
         }
@@ -2428,7 +2857,6 @@
             d[i] = Complex (octave::numeric_limits<double>::NaN (), 0.);
         }
 
-
       if (! rvec)
         {
           // ARPACK seems to give the eigenvalues in reversed order
@@ -2484,6 +2912,8 @@
                   eig_vec(jj,ii) =
                     Complex (octave::numeric_limits<double>::NaN (), 0.);
             }
+          if (note3)
+              eig_vec = utsolve (bt, permB, eig_vec);
         }
       if (k0 < k)
         {
@@ -2492,7 +2922,9 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in dneupd: %s",
+       arpack_errno2str (info2, "dneupd").c_str ());
 
   return ip(4);
 }
@@ -2527,14 +2959,14 @@
 
   if (cresid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      Array<double> rr (octave_rand::vector (n));
-      Array<double> ri (octave_rand::vector (n));
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      Array<double> rr (octave::rand::vector (n));
+      Array<double> ri (octave::rand::vector (n));
       cresid = ComplexColumnVector (n);
       for (F77_INT i = 0; i < n; i++)
         cresid(i) = Complex (rr(i),ri(i));
-      octave_rand::distribution (rand_dist);
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != cresid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -2704,7 +3136,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in znaupd", info);
+              ("eigs: error in znaupd: %s",
+               arpack_errno2str (info, "znaupd").c_str ());
 
           break;
         }
@@ -2792,7 +3225,9 @@
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in zneupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in zneupd: %s",
+       arpack_errno2str (info2, "zneupd").c_str ());
 
   return ip(4);
 }
@@ -2831,14 +3266,14 @@
 
   if (cresid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      Array<double> rr (octave_rand::vector (n));
-      Array<double> ri (octave_rand::vector (n));
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      Array<double> rr (octave::rand::vector (n));
+      Array<double> ri (octave::rand::vector (n));
       cresid = ComplexColumnVector (n);
       for (F77_INT i = 0; i < n; i++)
         cresid(i) = Complex (rr(i),ri(i));
-      octave_rand::distribution (rand_dist);
+      octave::rand::distribution (rand_dist);
     }
   else if (m.cols () != cresid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -3027,7 +3462,8 @@
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in znaupd", info);
+              ("eigs: error in znaupd: %s",
+               arpack_errno2str (info, "znaupd").c_str ());
 
           break;
         }
@@ -3113,40 +3549,46 @@
     }
   else
     (*current_liboctave_error_handler)
-      ("eigs: error %d in zneupd", info2);
+      ("eigs: error in zneupd: %s",
+       arpack_errno2str (info2, "zneupd").c_str ());
 
   return ip(4);
 }
 
+template <typename M>
 octave_idx_type
 EigsComplexNonSymmetricFunc (EigsComplexFunc fun, octave_idx_type n_arg,
                              const std::string& _typ, Complex sigma,
                              octave_idx_type k_arg, octave_idx_type p_arg,
                              octave_idx_type& info, ComplexMatrix& eig_vec,
-                             ComplexColumnVector& eig_val,
-                             ComplexColumnVector& cresid, std::ostream& os,
-                             double tol, bool rvec, bool /* cholB */,
-                             int disp, int maxit)
+                             ComplexColumnVector& eig_val, const M& _b,
+                             ColumnVector& permB, ComplexColumnVector& cresid,
+                             std::ostream& os, double tol, bool rvec,
+                             bool cholB, int disp, int maxit)
 {
   F77_INT n = octave::to_f77_int (n_arg);
   F77_INT k = octave::to_f77_int (k_arg);
   F77_INT p = octave::to_f77_int (p_arg);
+  M b(_b);
   std::string typ (_typ);
   bool have_sigma = (std::abs (sigma) ? true : false);
+  F77_INT mode = 1;
+  bool have_b = ! b.isempty ();
+  bool note3 = false;
   char bmat = 'I';
-  F77_INT mode = 1;
   int err = 0;
+  M bt;
 
   if (cresid.isempty ())
     {
-      std::string rand_dist = octave_rand::distribution ();
-      octave_rand::distribution ("uniform");
-      Array<double> rr (octave_rand::vector (n));
-      Array<double> ri (octave_rand::vector (n));
+      std::string rand_dist = octave::rand::distribution ();
+      octave::rand::distribution ("uniform");
+      Array<double> rr (octave::rand::vector (n));
+      Array<double> ri (octave::rand::vector (n));
       cresid = ComplexColumnVector (n);
       for (F77_INT i = 0; i < n; i++)
         cresid(i) = Complex (rr(i),ri(i));
-      octave_rand::distribution (rand_dist);
+      octave::rand::distribution (rand_dist);
     }
   else if (n != cresid.numel ())
     (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
@@ -3175,6 +3617,23 @@
     (*current_liboctave_error_handler)
       ("eigs: opts.p must be greater than k and less than or equal to n");
 
+  if (have_b && cholB && ! permB.isempty ())
+    {
+      // Check the we really have a permutation vector
+      if (permB.numel () != n)
+        (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+
+      Array<bool> checked (dim_vector (n, 1), false);
+      for (F77_INT i = 0; i < n; i++)
+        {
+          octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
+
+          if (checked(bidx) || bidx < 0 || bidx >= n
+              || octave::math::x_nint (bidx) != bidx)
+            (*current_liboctave_error_handler) ("eigs: permB vector invalid");
+        }
+    }
+
   if (! have_sigma)
     {
       if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
@@ -3186,19 +3645,53 @@
         (*current_liboctave_error_handler)
           ("eigs: invalid sigma value for complex problem");
 
+      if (typ != "SM" && have_b)
+        note3 = true;
+
       if (typ == "SM")
         {
           typ = "LM";
           sigma = 0.;
           mode = 3;
+          if (have_b)
+            bmat ='G';
         }
     }
   else if (! std::abs (sigma))
-    typ = "SM";
+    {
+      typ = "SM";
+      if (have_b)
+        bmat = 'G';
+    }
   else
     {
       typ = "LM";
       mode = 3;
+      if (have_b)
+        bmat = 'G';
+    }
+
+  if (mode == 1 && have_b)
+    {
+      // See Note 3 dsaupd
+      note3 = true;
+      if (cholB)
+        {
+          bt = b;
+          b = b.hermitian ();
+          if (permB.isempty ())
+            {
+              permB = ColumnVector (n);
+              for (F77_INT i = 0; i < n; i++)
+                permB(i) = i;
+            }
+        }
+      else
+        {
+          if (! make_cholb (b, bt, permB))
+            (*current_liboctave_error_handler)
+              ("eigs: The matrix B is not positive definite");
+        }
     }
 
   Array<F77_INT> ip (dim_vector (11, 1));
@@ -3275,26 +3768,92 @@
 
       if (ido == -1 || ido == 1 || ido == 2)
         {
-          Complex *ip2 = workd + iptr(0) - 1;
-          ComplexColumnVector x(n);
-
-          for (F77_INT i = 0; i < n; i++)
-            x(i) = *ip2++;
-
-          ComplexColumnVector y = fun (x, err);
-
-          if (err)
-            return false;
-
-          ip2 = workd + iptr(1) - 1;
-          for (F77_INT i = 0; i < n; i++)
-            *ip2++ = y(i);
+          if (have_b)
+            {
+              if (mode == 1) // regular mode with factorized B
+                {
+                  ComplexMatrix mtmp (n,1);
+                  for (F77_INT i = 0; i < n; i++)
+                    mtmp(i,0) = workd[i + iptr(0) - 1];
+
+                  mtmp = utsolve (bt, permB, mtmp);
+                  ComplexColumnVector y = fun (mtmp, err);
+
+                  if (err)
+                    return false;
+
+                  mtmp = ltsolve (b, permB, y);
+
+                  for (F77_INT i = 0; i < n; i++)
+                    workd[i+iptr(1)-1] = mtmp(i,0);
+                }
+              else // shift-invert mode
+                {
+                  if (ido == -1)
+                    {
+                      OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
+
+                      vector_product (b, workd+iptr(0)-1, ctmp);
+
+                      ComplexColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = ctmp[i];
+
+                      ComplexColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      Complex *ip2 = workd+iptr(1)-1;
+                      for (F77_INT i = 0; i < n; i++)
+                        ip2[i] = y(i);
+                    }
+                  else if (ido == 2)
+                    vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
+                  else
+                    {
+                      Complex *ip2 = workd+iptr(2)-1;
+                      ComplexColumnVector x(n);
+
+                      for (F77_INT i = 0; i < n; i++)
+                        x(i) = *ip2++;
+
+                      ComplexColumnVector y = fun (x, err);
+
+                      if (err)
+                        return false;
+
+                      ip2 = workd + iptr(1) - 1;
+                      for (F77_INT i = 0; i < n; i++)
+                        *ip2++ = y(i);
+                    }
+                }
+            }
+          else
+            {
+              Complex *ip2 = workd + iptr(0) - 1;
+              ComplexColumnVector x(n);
+
+              for (F77_INT i = 0; i < n; i++)
+                x(i) = *ip2++;
+
+              ComplexColumnVector y = fun (x, err);
+
+              if (err)
+                return false;
+
+              ip2 = workd + iptr(1) - 1;
+              for (F77_INT i = 0; i < n; i++)
+                *ip2++ = y(i);
+            }
         }
       else
         {
           if (info < 0)
             (*current_liboctave_error_handler)
-              ("eigs: error %d in znaupd", info);
+              ("eigs: error in znaupd: %s",
+               arpack_errno2str (info, "znaupd").c_str ());
 
           break;
         }
@@ -3376,10 +3935,14 @@
               for (F77_INT j = 0; j < n; j++)
                 z[off2 + j] = ctmp[j];
             }
+          if (note3)
+            eig_vec = utsolve (bt, permB, eig_vec);
         }
     }
   else
-    (*current_liboctave_error_handler) ("eigs: error %d in zneupd", info2);
+    (*current_liboctave_error_handler)
+      ("eigs: error in zneupd: %s",
+       arpack_errno2str (info2, "zneupd").c_str ());
 
   return ip(4);
 }
@@ -3408,6 +3971,15 @@
 
 template
 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,
+   Matrix& eig_vec, ColumnVector& eig_val, const Matrix& _b,
+   ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
+   bool rvec, bool cholB, int disp, int maxit);
+
+template
+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,
@@ -3424,6 +3996,15 @@
    ColumnVector& resid, std::ostream& os, double tol, bool rvec,
    bool cholB, int disp, int maxit);
 
+template
+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,
+   ComplexMatrix& eig_vec, ComplexColumnVector& eig_val, const Matrix& _b,
+   ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
+   bool rvec, bool cholB, int disp, int maxit);
+
 // SparseMatrix
 
 template
@@ -3446,6 +4027,15 @@
 
 template
 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,
+   Matrix& eig_vec, ColumnVector& eig_val, const SparseMatrix& _b,
+   ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
+   bool rvec, bool cholB, int disp, int maxit);
+
+template
+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,
@@ -3462,6 +4052,15 @@
    ColumnVector& resid, std::ostream& os, double tol, bool rvec,
    bool cholB, int disp, int maxit);
 
+template
+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,
+   ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
+   const SparseMatrix& _b, ColumnVector& permB, ColumnVector& resid,
+   std::ostream& os, double tol, bool rvec, bool cholB, int disp, int maxit);
+
 // ComplexMatrix
 
 template
@@ -3482,6 +4081,15 @@
    ComplexColumnVector& cresid, std::ostream& os, double tol,
    bool rvec, bool cholB, int disp, int maxit);
 
+template
+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,
+   ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
+   const ComplexMatrix& _b, ColumnVector& permB, ComplexColumnVector& cresid,
+   std::ostream& os, double tol, bool rvec, bool cholB, int disp, int maxit);
+
 // SparseComplexMatrix
 
 template
@@ -3502,4 +4110,13 @@
    ColumnVector& permB, ComplexColumnVector& cresid, std::ostream& os,
    double tol, bool rvec, bool cholB, int disp, int maxit);
 
+template
+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,
+   ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
+   const SparseComplexMatrix& _b, ColumnVector& permB,
+   ComplexColumnVector& cresid, std::ostream& os, double tol, bool rvec,
+   bool cholB, int disp, int maxit);
 #endif
--- a/liboctave/numeric/eigs-base.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/eigs-base.h	Thu Dec 20 17:18:56 2018 -0500
@@ -60,14 +60,16 @@
                               std::ostream& os, double tol, bool rvec,
                               bool cholB, int disp, int maxit);
 
+template <typename M>
 extern 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,
                        octave_idx_type& info, Matrix& eig_vec,
-                       ColumnVector& eig_val, ColumnVector& resid,
+                       ColumnVector& eig_val, const M& _b,
+                       ColumnVector& permB, ColumnVector& resid,
                        std::ostream& os, double tol, bool rvec,
-                       bool /* cholB */, int disp, int maxit);
+                       bool cholB, int disp, int maxit);
 
 template <typename M>
 octave_idx_type
@@ -90,14 +92,16 @@
                                  std::ostream& os, double tol, bool rvec,
                                  bool cholB, int disp, int maxit);
 
+template <typename M>
 extern 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,
                           octave_idx_type& info, ComplexMatrix& eig_vec,
-                          ComplexColumnVector& eig_val, ColumnVector& resid,
+                          ComplexColumnVector& eig_val, const M& _b,
+                          ColumnVector& permB, ColumnVector& resid,
                           std::ostream& os, double tol, bool rvec,
-                          bool /* cholB */, int disp, int maxit);
+                          bool cholB, int disp, int maxit);
 
 template <typename M>
 octave_idx_type
@@ -122,14 +126,15 @@
                                     std::ostream& os, double tol, bool rvec,
                                     bool cholB, int disp, int maxit);
 
+template <typename M>
 extern 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,
                              octave_idx_type& info, ComplexMatrix& eig_vec,
-                             ComplexColumnVector& eig_val,
-                             ComplexColumnVector& cresid, std::ostream& os,
-                             double tol, bool rvec, bool /* cholB */,
-                             int disp, int maxit);
+                             ComplexColumnVector& eig_val, const M& _b,
+                             ColumnVector& permB, ComplexColumnVector& cresid,
+                             std::ostream& os, double tol, bool rvec,
+                             bool cholB, int disp, int maxit);
 
 #endif
--- a/liboctave/numeric/lo-fftpack-proto.h	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
-
-Copyright (C) 2016-2018 John W. Eaton
-
-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_lo_fftpack_proto_h)
-#define octave_lo_fftpack_proto_h 1
-
-#include "octave-config.h"
-
-#include "f77-fcn.h"
-
-extern "C"
-{
-  // Note that the original complex fft routines were not written for
-  // float or double complex arguments.  They have been modified by
-  // adding an implicit float or double precision (a-h,o-z) statement
-  // at the beginning of each subroutine.
-
-  // FFTB
-
-  F77_RET_T
-  F77_FUNC (cfftb, CFFTB) (const F77_INT&, F77_CMPLX*, F77_CMPLX*);
-
-  F77_RET_T
-  F77_FUNC (zfftb, ZFFTB) (const F77_INT&, F77_DBLE_CMPLX*, F77_DBLE_CMPLX*);
-
-  // FFTF
-
-  F77_RET_T
-  F77_FUNC (cfftf, CFFTF) (const F77_INT&, F77_CMPLX*, F77_CMPLX*);
-
-  F77_RET_T
-  F77_FUNC (zfftf, ZFFTF) (const F77_INT&, F77_DBLE_CMPLX*, F77_DBLE_CMPLX*);
-
-  // FFTI
-
-  F77_RET_T
-  F77_FUNC (cffti, CFFTI) (const F77_INT&, F77_CMPLX*);
-
-  F77_RET_T
-  F77_FUNC (zffti, ZFFTI) (const F77_INT&, F77_DBLE_CMPLX*);
-}
-
-#endif
--- a/liboctave/numeric/lo-mappers.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/lo-mappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -481,248 +481,6 @@
 
 #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
 
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isna' instead")
-inline bool octave_is_NA (double x) { return octave::math::isna (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isna' instead")
-inline bool octave_is_NA (float x) { return octave::math::isna (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isna' instead")
-inline bool octave_is_NA (const Complex& x) { return octave::math::isna (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isna' instead")
-inline bool octave_is_NA (const FloatComplex& x)
-{
-  return octave::math::isna (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acos' instead")
-inline Complex acos (const Complex& x) { return octave::math::acos (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acos' instead")
-inline FloatComplex acos (const FloatComplex& x)
-{
-  return octave::math::acos (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asin' instead")
-inline Complex asin (const Complex& x) { return octave::math::asin (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asin' instead")
-inline FloatComplex asin (const FloatComplex& x)
-{
-  return octave::math::asin (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atan' instead")
-inline Complex atan (const Complex& x) { return octave::math::atan (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atan' instead")
-inline FloatComplex atan (const FloatComplex& x)
-{
-  return octave::math::atan (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'std::arg' instead")
-inline double arg (double x) { return std::arg (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::arg' instead")
-inline float arg (float x) { return std::arg (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::conj' instead")
-inline double conj (double x) { return x; }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::conj' instead")
-inline float conj (float x) { return x; }
-
-OCTAVE_DEPRECATED (4.2, "use 'std::imag' instead")
-inline double imag (double x) { return std::imag (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::imag' instead")
-inline float imag (float x) { return std::imag (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'std::real' instead")
-inline double real (double x) { return std::real (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::real' instead")
-inline float real (float x) { return std::real (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline double xlog2 (double x) { return octave::math::log2 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline float xlog2 (float x) { return octave::math::log2 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline Complex xlog2 (const Complex& x) { return octave::math::log2 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline FloatComplex xlog2 (const FloatComplex& x)
-{
-  return octave::math::log2 (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline double xlog2 (double x, int& exp)
-{
-  return octave::math::log2 (x, exp);
-}
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline float xlog2 (float x, int& exp) { return octave::math::log2 (x, exp); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline Complex xlog2 (const Complex& x, int& exp)
-{
-  return octave::math::log2 (x, exp);
-}
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log2' instead")
-inline FloatComplex xlog2 (const FloatComplex& x, int& exp)
-{
-  return octave::math::log2 (x, exp);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::exp2' instead")
-inline double xexp2 (double x) { return octave::math::exp2 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::exp2' instead")
-inline float xexp2 (float x) { return octave::math::exp2 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'std::ceil' instead")
-inline double xceil (double x) { return std::ceil (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::ceil' instead")
-inline float xceil (float x) { return std::ceil (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::ceil' instead")
-std::complex<T>
-ceil (const std::complex<T>& x)
-{
-  return octave::math::ceil (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::copysign' instead")
-inline double xcopysign (double x, double y)
-{
-  return octave::math::copysign (x, y);
-}
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::copysign' instead")
-inline float xcopysign (float x, float y)
-{
-  return octave::math::copysign (x, y);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::signbit' instead")
-T
-xsignbit (T x)
-{
-  return octave::math::signbit (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::negative_sign' instead")
-inline bool xnegative_sign (double x)
-{
-  return octave::math::negative_sign (x);
-}
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::negative_sign' instead")
-inline bool xnegative_sign (float x)
-{
-  return octave::math::negative_sign (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::positive_sign' instead")
-inline bool xpositive_sign (double x)
-{
-  return octave::math::positive_sign (x);
-}
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::positive_sign' instead")
-inline bool xpositive_sign (float x)
-{
-  return octave::math::positive_sign (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::signum' instead")
-inline double signum (double x) { return octave::math::signum (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::signum' instead")
-inline float signum (float x) { return octave::math::signum (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::signum' instead")
-std::complex<T>
-signum (const std::complex<T>& x)
-{
-  return octave::math::signum (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'std::trunc' instead")
-inline double xtrunc (double x) { return std::trunc (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::trunc' instead")
-inline float xtrunc (float x) { return std::trunc (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::trunc' instead")
-std::complex<T>
-xtrunc (const std::complex<T>& x)
-{
-  return octave::math::trunc (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::fix' instead")
-inline double fix (double x) { return octave::math::fix (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::fix' instead")
-inline float fix (float x) { return octave::math::fix (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::fix' instead")
-std::complex<T>
-fix (const std::complex<T>& x)
-{
-  return octave::math::fix (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'std::floor' instead")
-inline double xfloor (double x) { return std::floor (x); }
-OCTAVE_DEPRECATED (4.2, "use 'std::floor' instead")
-inline float xfloor (float x) { return std::floor (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::floor' instead")
-std::complex<T>
-floor (const std::complex<T>& x)
-{
-  return octave::math::floor (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::round' instead")
-inline double xround (double x) { return octave::math::round (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::round' instead")
-inline float xround (float x) { return octave::math::round (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::round' instead")
-std::complex<T>
-xround (const std::complex<T>& x)
-{
-  return octave::math::round (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::roundb' instead")
-inline double xroundb (double x) { return octave::math::roundb (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::roundb' instead")
-inline float xroundb (float x) { return octave::math::roundb (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::roundb' instead")
-std::complex<T>
-xroundb (const std::complex<T>& x)
-{
-  return octave::math::roundb (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-inline bool xisnan (bool x) { return octave::math::isnan (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-inline bool xisnan (char x) { return octave::math::isnan (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-inline bool xisnan (double x) { return octave::math::isnan (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-inline bool xisnan (float x) { return octave::math::isnan (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-bool
-xisnan (const std::complex<T>& x)
-{
-  return octave::math::isnan (x);
-}
-
 OCTAVE_DEPRECATED (4.4, "use 'octave::math::isfinite' instead")
 inline bool xfinite (double x) { return octave::math::isfinite (x); }
 OCTAVE_DEPRECATED (4.4, "use 'octave::math::isfinite' instead")
@@ -736,187 +494,6 @@
   return octave::math::isfinite (x);
 }
 
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isinf' instead")
-inline bool xisinf (double x) { return octave::math::isinf (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isinf' instead")
-inline bool xisinf (float x) { return octave::math::isinf (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isinf' instead")
-bool
-xisinf (const std::complex<T>& x)
-{
-  return octave::math::isinf (x);
-}
-
-// Some useful tests, that are commonly repeated.
-// Test for a finite integer.
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isinteger' instead")
-inline bool
-xisinteger (double x)
-{
-  return octave::math::isinteger (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isinteger' instead")
-inline bool
-xisinteger (float x)
-{
-  return octave::math::isinteger (x);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::x_nint' instead")
-T
-X_NINT (T x)
-{
-  return octave::math::x_nint (x);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::x_nint (x)' instead")
-inline double D_NINT (double x) { return octave::math::x_nint (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::x_nint (x)' instead")
-inline float F_NINT (float x) { return octave::math::x_nint (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::nint_big' instead")
-inline octave_idx_type NINTbig (double x) { return octave::math::nint_big (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::nint_big' instead")
-inline octave_idx_type NINTbig (float x) { return octave::math::nint_big (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::nint' instead")
-inline int NINT (double x) { return octave::math::nint (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::nint' instead")
-inline int NINT (float x) { return octave::math::nint (x); }
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::mod' instead")
-T
-xmod (T x, T y)
-{
-  return octave::math::mod (x, y);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rem' instead")
-T
-xrem (T x, T y)
-{
-  return octave::math::rem (x, y);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::min' instead")
-T
-xmin (T x, T y)
-{
-  return octave::math::min (x, y);
-}
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::max' instead")
-T
-xmax (T x, T y)
-{
-  return octave::math::max (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::min' instead")
-inline double
-xmin (double x, double y)
-{
-  return octave::math::min (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::max' instead")
-inline double
-xmax (double x, double y)
-{
-  return octave::math::max (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::min' instead")
-inline float
-xmin (float x, float y)
-{
-  return octave::math::min (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::max' instead")
-inline float
-xmax (float x, float y)
-{
-  return octave::math::max (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::min' instead")
-inline Complex
-xmin (const Complex& x, const Complex& y)
-{
-  return octave::math::min (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::max' instead")
-inline Complex
-xmax (const Complex& x, const Complex& y)
-{
-  return octave::math::max (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::min' instead")
-inline OCTAVE_API FloatComplex
-xmin (const FloatComplex& x, const FloatComplex& y)
-{
-  return octave::math::min (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::max' instead")
-inline FloatComplex
-xmax (const FloatComplex& x, const FloatComplex& y)
-{
-  return octave::math::max (x, y);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_acos' instead")
-inline Complex rc_acos (double x) { return octave::math::rc_acos (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_acos' instead")
-inline FloatComplex rc_acos (float x) { return octave::math::rc_acos (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_acosh' instead")
-inline Complex rc_acosh (double x) { return octave::math::rc_acosh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_acosh' instead")
-inline FloatComplex rc_acosh (float x) { return octave::math::rc_acosh (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_asin' instead")
-inline Complex rc_asin (double x) { return octave::math::rc_asin (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_asin' instead")
-inline FloatComplex rc_asin (float x) { return octave::math::rc_asin (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_atanh' instead")
-inline Complex rc_atanh (double x) { return octave::math::rc_atanh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_atanh' instead")
-inline FloatComplex rc_atanh (float x) { return octave::math::rc_atanh (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log' instead")
-inline Complex rc_log (double x) { return octave::math::rc_log (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log' instead")
-inline FloatComplex rc_log (float x) { return octave::math::rc_log (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log2' instead")
-inline Complex rc_log2 (double x) { return octave::math::rc_log2 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log2' instead")
-inline FloatComplex rc_log2 (float x) { return octave::math::rc_log2 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log10' instead")
-inline Complex rc_log10 (double x) { return octave::math::rc_log10 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log10' instead")
-inline FloatComplex rc_log10 (float x) { return octave::math::rc_log10 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_sqrt' instead")
-inline Complex rc_sqrt (double x) { return octave::math::rc_sqrt (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_sqrt' instead")
-inline FloatComplex rc_sqrt (float x) { return octave::math::rc_sqrt (x); }
-
 #endif
 
 #endif
--- a/liboctave/numeric/lo-slatec-proto.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/lo-slatec-proto.h	Thu Dec 20 17:18:56 2018 -0500
@@ -29,26 +29,6 @@
 
 extern "C"
 {
-  // BETAI
-
-  F77_RET_T
-  F77_FUNC (xbetai, XBETAI) (const F77_REAL&, const F77_REAL&,
-                             const F77_REAL&, F77_REAL&);
-
-  F77_RET_T
-  F77_FUNC (xdbetai, XDBETAI) (const F77_DBLE&, const F77_DBLE&,
-                               const F77_DBLE&, F77_DBLE&);
-
-  // GAMMAINC
-
-  F77_RET_T
-  F77_FUNC (xgammainc, XGAMMAINC) (const F77_DBLE&, const F77_DBLE&,
-                                   F77_DBLE&);
-
-  F77_RET_T
-  F77_FUNC (xsgammainc, XSGAMMAINC) (const F77_REAL&, const F77_REAL&,
-                                     F77_REAL&);
-
   // PCHIM
 
   F77_RET_T
--- a/liboctave/numeric/lo-specfun.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/lo-specfun.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -2260,145 +2260,3 @@
     }
   }
 }
-
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-ComplexMatrix besselj (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexMatrix bessely (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexMatrix besseli (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexMatrix besselk (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexMatrix besselh1 (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexMatrix besselh2 (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexMatrix besselj (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexMatrix bessely (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexMatrix besseli (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexMatrix besselk (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexMatrix besselh1 (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexMatrix besselh2 (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexMatrix besselj (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexMatrix bessely (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexMatrix besseli (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexMatrix besselk (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexMatrix besselh1 (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexMatrix besselh2 (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexNDArray besselj (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexNDArray bessely (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexNDArray besseli (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexNDArray besselk (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexNDArray besselh1 (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexNDArray besselh2 (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexNDArray besselj (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexNDArray bessely (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexNDArray besseli (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexNDArray besselk (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexNDArray besselh1 (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexNDArray besselh2 (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexNDArray besselj (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexNDArray bessely (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexNDArray besseli (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexNDArray besselk (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexNDArray besselh1 (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexNDArray besselh2 (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexMatrix besselj (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-ComplexMatrix bessely (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-ComplexMatrix besseli (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-ComplexMatrix besselk (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-ComplexMatrix besselh1 (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-ComplexMatrix besselh2 (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexMatrix besselj (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexMatrix bessely (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexMatrix besseli (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselk (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh1 (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh2 (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexMatrix besselj (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexMatrix bessely (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexMatrix besseli (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselk (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh1 (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh2 (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexMatrix besselj (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexMatrix bessely (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexMatrix besseli (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselk (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh1 (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh2 (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexNDArray besselj (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexNDArray bessely (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexNDArray besseli (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselk (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh1 (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh2 (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexNDArray besselj (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexNDArray bessely (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexNDArray besseli (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselk (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh1 (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh2 (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexNDArray besselj (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexNDArray bessely (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexNDArray besseli (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselk (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh1 (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexNDArray besselh2 (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-FloatComplexMatrix besselj (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-FloatComplexMatrix bessely (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-FloatComplexMatrix besseli (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselk (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh1 (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-FloatComplexMatrix besselh2 (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-ComplexMatrix airy (const ComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-ComplexMatrix biry (const ComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-ComplexNDArray airy (const ComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-ComplexNDArray biry (const ComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-FloatComplexMatrix airy (const FloatComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-FloatComplexMatrix biry (const FloatComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-FloatComplexNDArray airy (const FloatComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-FloatComplexNDArray biry (const FloatComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-<<<<<<< dest
-Array<double> betainc (double x, double a, const Array<double>& b) { return octave::math::betainc (x, a, b); }
-Array<double> betainc (double x, const Array<double>& a, double b) { return octave::math::betainc (x, a, b); }
-Array<double> betainc (double x, const Array<double>& a, const Array<double>& b) { return octave::math::betainc (x, a, b); }
-
-Array<double> betainc (const Array<double>& x, double a, double b) { return octave::math::betainc (x, a, b); }
-Array<double> betainc (const Array<double>& x, double a, const Array<double>& b) { return octave::math::betainc (x, a, b); }
-Array<double> betainc (const Array<double>& x, const Array<double>& a, double b) { return octave::math::betainc (x, a, b); }
-Array<double> betainc (const Array<double>& x, const Array<double>& a, const Array<double>& b) { return octave::math::betainc (x, a, b); }
-
-Array<float> betainc (float x, float a, const Array<float>& b) { return octave::math::betainc (x, a, b); }
-Array<float> betainc (float x, const Array<float>& a, float b) { return octave::math::betainc (x, a, b); }
-Array<float> betainc (float x, const Array<float>& a, const Array<float>& b) { return octave::math::betainc (x, a, b); }
-
-Array<float> betainc (const Array<float>& x, float a, float b) { return octave::math::betainc (x, a, b); }
-Array<float> betainc (const Array<float>& x, float a, const Array<float>& b) { return octave::math::betainc (x, a, b); }
-Array<float> betainc (const Array<float>& x, const Array<float>& a, float b) { return octave::math::betainc (x, a, b); }
-Array<float> betainc (const Array<float>& x, const Array<float>& a, const Array<float>& b) { return octave::math::betainc (x, a, b); }
-
-Array<double> betaincinv (double x, double a, const Array<double>& b) { return octave::math::betaincinv (x, a, b); }
-Array<double> betaincinv (double x, const Array<double>& a, double b) { return octave::math::betaincinv (x, a, b); }
-Array<double> betaincinv (double x, const Array<double>& a, const Array<double>& b) { return octave::math::betaincinv (x, a, b); }
-
-Array<double> betaincinv (const Array<double>& x, double a, double b) { return octave::math::betaincinv (x, a, b); }
-Array<double> betaincinv (const Array<double>& x, double a, const Array<double>& b) { return octave::math::betaincinv (x, a, b); }
-Array<double> betaincinv (const Array<double>& x, const Array<double>& a, double b) { return octave::math::betaincinv (x, a, b); }
-Array<double> betaincinv (const Array<double>& x, const Array<double>& a, const Array<double>& b) { return octave::math::betaincinv (x, a, b); }
-
-#endif
--- a/liboctave/numeric/lo-specfun.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/lo-specfun.h	Thu Dec 20 17:18:56 2018 -0500
@@ -342,38 +342,6 @@
     extern OCTAVE_API double gamma (double x);
     extern OCTAVE_API float gamma (float x);
 
-    extern OCTAVE_API double gammainc (double x, double a, bool& err);
-    inline double gammainc (double x, double a)
-    {
-      bool err;
-      return gammainc (x, a, err);
-    }
-
-    extern OCTAVE_API Matrix gammainc (double x, const Matrix& a);
-    extern OCTAVE_API Matrix gammainc (const Matrix& x, double a);
-    extern OCTAVE_API Matrix gammainc (const Matrix& x, const Matrix& a);
-
-    extern OCTAVE_API NDArray gammainc (double x, const NDArray& a);
-    extern OCTAVE_API NDArray gammainc (const NDArray& x, double a);
-    extern OCTAVE_API NDArray gammainc (const NDArray& x, const NDArray& a);
-
-    extern OCTAVE_API float gammainc (float x, float a, bool& err);
-    inline float gammainc (float x, float a)
-    {
-      bool err;
-      return gammainc (x, a, err);
-    }
-
-    extern OCTAVE_API FloatMatrix gammainc (float x, const FloatMatrix& a);
-    extern OCTAVE_API FloatMatrix gammainc (const FloatMatrix& x, float a);
-    extern OCTAVE_API FloatMatrix gammainc (const FloatMatrix& x,
-                                            const FloatMatrix& a);
-
-    extern OCTAVE_API FloatNDArray gammainc (float x, const FloatNDArray& a);
-    extern OCTAVE_API FloatNDArray gammainc (const FloatNDArray& x, float a);
-    extern OCTAVE_API FloatNDArray gammainc (const FloatNDArray& x,
-                                             const FloatNDArray& a);
-
     inline double lgamma (double x) { return std::lgamma (x); }
     inline float lgamma (float x) { return std::lgammaf (x); }
 
@@ -397,484 +365,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acosh' instead")
-inline double xacosh (double x) { return octave::math::acosh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acosh' instead")
-inline float xacosh (float x) { return octave::math::acosh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acosh' instead")
-inline Complex xacosh (const Complex& x) { return octave::math::acosh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::acosh' instead")
-inline FloatComplex xacosh (const FloatComplex& x) { return octave::math::acosh (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asinh' instead")
-inline double xasinh (double x) { return octave::math::asinh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asinh' instead")
-inline float xasinh (float x) { return octave::math::asinh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asinh' instead")
-inline Complex xasinh (const Complex& x) { return octave::math::asinh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::asinh' instead")
-inline FloatComplex xasinh (const FloatComplex& x) { return octave::math::asinh (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atanh' instead")
-inline double xatanh (double x) { return octave::math::atanh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atanh' instead")
-inline float xatanh (float x) { return octave::math::atanh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atanh' instead")
-inline Complex xatanh (const Complex& x) { return octave::math::atanh (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::atanh' instead")
-inline FloatComplex xatanh (const FloatComplex& x) { return octave::math::atanh (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erf' instead")
-inline double xerf (double x) { return octave::math::erf (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erf' instead")
-inline float xerf (float x) { return octave::math::erf (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erf' instead")
-inline Complex xerf (const Complex& x) { return octave::math::erf (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erf' instead")
-inline FloatComplex xerf (const FloatComplex& x) { return octave::math::erf (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfc' instead")
-inline double xerfc (double x) { return octave::math::erfc (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfc' instead")
-inline float xerfc (float x) { return octave::math::erfc (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfc' instead")
-inline Complex xerfc (const Complex& x) { return octave::math::erfc (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfc' instead")
-inline FloatComplex xerfc (const FloatComplex& x) { return octave::math::erfc (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::expm1' instead")
-inline double xexpm1 (double x) { return octave::math::expm1 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::expm1' instead")
-inline Complex xexpm1 (const Complex& x) { return octave::math::expm1 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::expm1' instead")
-inline float xexpm1 (float x) { return octave::math::expm1 (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::expm1' instead")
-inline FloatComplex xexpm1 (const FloatComplex& x) { return octave::math::expm1 (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log1p' instead")
-inline double xlog1p (double x) { return octave::math::log1p (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log1p' instead")
-inline Complex xlog1p (const Complex& x) { return octave::math::log1p (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log1p' instead")
-inline float xlog1p (float x) { return octave::math::log1p (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::log1p' instead")
-inline FloatComplex xlog1p (const FloatComplex& x) { return octave::math::log1p (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::cbrt' instead")
-inline double xcbrt (double x) { return octave::math::cbrt (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::cbrt' instead")
-inline float xcbrt (float x) { return octave::math::cbrt (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gamma' instead")
-inline double xgamma (double x) { return octave::math::gamma (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::lgamma' instead")
-inline double xlgamma (double x) { return octave::math::lgamma (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_lgamma' instead")
-inline Complex rc_lgamma (double x) { return octave::math::rc_lgamma (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gamma' instead")
-inline float xgamma (float x) { return octave::math::gamma (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::lgamma' instead")
-inline float xlgamma (float x) { return octave::math::lgamma (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_lgamma' instead")
-inline FloatComplex rc_lgamma (float x) { return octave::math::rc_lgamma (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-inline Complex besselj (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-inline Complex bessely (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-inline Complex besseli (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-inline Complex besselk (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-inline Complex besselh1 (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-inline Complex besselh2 (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexMatrix besselj (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexMatrix bessely (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexMatrix besseli (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexMatrix besselk (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexMatrix besselh1 (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexMatrix besselh2 (double alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexMatrix besselj (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexMatrix bessely (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexMatrix besseli (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexMatrix besselk (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexMatrix besselh1 (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexMatrix besselh2 (const Matrix& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexMatrix besselj (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexMatrix bessely (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexMatrix besseli (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexMatrix besselk (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexMatrix besselh1 (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexMatrix besselh2 (const Matrix& alpha, const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexNDArray besselj (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexNDArray bessely (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexNDArray besseli (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexNDArray besselk (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexNDArray besselh1 (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexNDArray besselh2 (double alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexNDArray besselj (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexNDArray bessely (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexNDArray besseli (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexNDArray besselk (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexNDArray besselh1 (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexNDArray besselh2 (const NDArray& alpha, const Complex& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexNDArray besselj (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexNDArray bessely (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexNDArray besseli (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexNDArray besselk (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexNDArray besselh1 (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexNDArray besselh2 (const NDArray& alpha, const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API ComplexMatrix besselj (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API ComplexMatrix bessely (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API ComplexMatrix besseli (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API ComplexMatrix besselk (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API ComplexMatrix besselh1 (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API ComplexMatrix besselh2 (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-inline FloatComplex besselj (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselj (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octavh::bessely' instead")
-inline FloatComplex bessely (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::bessely (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octavh::besseli' instead")
-inline FloatComplex besseli (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besseli (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octavh::besselk' instead")
-inline FloatComplex besselk (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselk (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octavh::besselh1' instead")
-inline FloatComplex besselh1 (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselh1 (alpha, x, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octavh::besselh2' instead")
-inline FloatComplex besselh2 (float alpha, const FloatComplex& x, bool scaled, octave_idx_type& ierr) { return octave::math::besselh2 (alpha, x, scaled, ierr); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexMatrix besselj (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexMatrix bessely (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexMatrix besseli (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexMatrix besselk (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexMatrix besselh1 (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexMatrix besselh2 (float alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexMatrix besselj (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexMatrix bessely (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexMatrix besseli (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexMatrix besselk (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexMatrix besselh1 (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexMatrix besselh2 (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexMatrix besselj (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexMatrix bessely (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexMatrix besseli (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexMatrix besselk (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexMatrix besselh1 (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexMatrix besselh2 (const FloatMatrix& alpha, const FloatComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexNDArray besselj (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexNDArray bessely (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexNDArray besseli (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexNDArray besselk (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexNDArray besselh1 (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexNDArray besselh2 (float alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexNDArray besselj (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexNDArray bessely (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexNDArray besseli (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexNDArray besselk (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexNDArray besselh1 (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexNDArray besselh2 (const FloatNDArray& alpha, const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexNDArray besselj (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexNDArray bessely (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexNDArray besseli (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexNDArray besselk (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexNDArray besselh1 (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexNDArray besselh2 (const FloatNDArray& alpha, const FloatComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselj' instead")
-extern OCTAVE_API FloatComplexMatrix besselj (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::bessely' instead")
-extern OCTAVE_API FloatComplexMatrix bessely (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besseli' instead")
-extern OCTAVE_API FloatComplexMatrix besseli (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselk' instead")
-extern OCTAVE_API FloatComplexMatrix besselk (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh1' instead")
-extern OCTAVE_API FloatComplexMatrix besselh1 (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::besselh2' instead")
-extern OCTAVE_API FloatComplexMatrix besselh2 (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-inline Complex airy (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-inline Complex biry (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-extern OCTAVE_API ComplexMatrix airy (const ComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-extern OCTAVE_API ComplexMatrix biry (const ComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-extern OCTAVE_API ComplexNDArray airy (const ComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-extern OCTAVE_API ComplexNDArray biry (const ComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-inline FloatComplex airy (const FloatComplex& z, bool deriv, bool scaled, octave_idx_type& ierr) { return octave::math::airy (z, deriv, scaled, ierr); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-inline FloatComplex biry (const FloatComplex& z, bool deriv, bool scaled, octave_idx_type& ierr) { return octave::math::biry (z, deriv, scaled, ierr); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-extern OCTAVE_API FloatComplexMatrix airy (const FloatComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-extern OCTAVE_API FloatComplexMatrix biry (const FloatComplexMatrix& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::airy' instead")
-extern OCTAVE_API FloatComplexNDArray airy (const FloatComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::biry' instead")
-extern OCTAVE_API FloatComplexNDArray biry (const FloatComplexNDArray& z, bool deriv, bool scaled, Array<octave_idx_type>& ierr);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-inline double gammainc (double x, double a, bool& err) { return octave::math::gammainc (x, a, err); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-inline double gammainc (double x, double a) { return octave::math::gammainc (x, a); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-extern OCTAVE_API Matrix gammainc (double x, const Matrix& a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-extern OCTAVE_API Matrix gammainc (const Matrix& x, double a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-extern OCTAVE_API Matrix gammainc (const Matrix& x, const Matrix& a);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-extern OCTAVE_API NDArray gammainc (double x, const NDArray& a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-extern OCTAVE_API NDArray gammainc (const NDArray& x, double a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API NDArray gammainc (const NDArray& x, const NDArray& a);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-inline float gammainc (float x, float a, bool& err) { return octave::math::gammainc (x, a, err); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::gammainc' instead")
-inline float gammainc (float x, float a) { return octave::math::gammainc (x, a); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatMatrix gammainc (float x, const FloatMatrix& a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatMatrix gammainc (const FloatMatrix& x, float a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatMatrix gammainc (const FloatMatrix& x, const FloatMatrix& a);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatNDArray gammainc (float x, const FloatNDArray& a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatNDArray gammainc (const FloatNDArray& x, float a);
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-extern OCTAVE_API FloatNDArray gammainc (const FloatNDArray& x, const FloatNDArray& a);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-inline Complex rc_log1p (double x) { return octave::math::rc_log1p (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::rc_log1p' instead")
-inline FloatComplex rc_log1p (float x) { return octave::math::rc_log1p (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfinv' instead")
-inline double erfinv (double x) { return octave::math::erfinv (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfinv' instead")
-inline float erfinv (float x) { return octave::math::erfinv (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcinv' instead")
-inline double erfcinv (double x) { return octave::math::erfcinv (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcinv' instead")
-inline float erfcinv (float x) { return octave::math::erfcinv (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcx' instead")
-inline float erfcx (float x) { return octave::math::erfcx (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcx' instead")
-inline double erfcx (double x) { return octave::math::erfcx (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcx' instead")
-inline Complex erfcx (const Complex& x) { return octave::math::erfcx (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfcx' instead")
-inline FloatComplex erfcx (const FloatComplex& x) { return octave::math::erfcx (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfi' instead")
-inline float erfi (float x) { return octave::math::erfi (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfi' instead")
-inline double erfi (double x) { return octave::math::erfi (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfi' instead")
-inline Complex erfi (const Complex& x) { return octave::math::erfi (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::erfi' instead")
-inline FloatComplex erfi (const FloatComplex& x) { return octave::math::erfi (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::dawson' instead")
-inline float dawson (float x) { return octave::math::dawson (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::dawson' instead")
-inline double dawson (double x) { return octave::math::dawson (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::dawson' instead")
-inline Complex dawson (const Complex& x) { return octave::math::dawson (x); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::dawson' instead")
-inline FloatComplex dawson (const FloatComplex& x) { return octave::math::dawson (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::ellipj' instead")
-inline void ellipj (double u, double m, double& sn, double& cn, double& dn, double& err) { octave::math::ellipj (u, m, sn, cn, dn, err); }
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::ellipj' instead")
-inline void ellipj (const Complex& u, double m, Complex& sn, Complex& cn, Complex& dn, double& err) { octave::math::ellipj (u, m, sn, cn, dn, err); }
-
-//! Digamma function.
-//!
-//! Only defined for double and float.
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::psi' instead")
-T
-psi (T z);
-
-template <>
-inline double
-psi (double z)
-{
-  return octave::math::psi (z);
-}
-
-template <>
-inline float
-psi (float z)
-{
-  return octave::math::psi (z);
-}
-
-//! Digamma function for complex input.
-//!
-//! Only defined for double and float.
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::psi' instead")
-std::complex<T>
-psi (const std::complex<T>& z);
-
-template <>
-inline std::complex<double>
-psi (const std::complex<double>& z)
-{
-  return octave::math::psi (z);
-}
-
-template <>
-inline std::complex<float>
-psi (const std::complex<float>& z)
-{
-  return octave::math::psi (z);
-}
-
-//! Polygamma function.
-//!
-//! Only defined for double and float.
-//! @param n must be non-negative.  If zero, the digamma function is computed.
-//! @param z must be real and non-negative.
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::psi' instead")
-T
-psi (octave_idx_type n, T z);
-
-template<>
-inline double
-psi (octave_idx_type n, double z)
-{
-  return octave::math::psi (n, z);
-}
-
-template<>
-inline float
-psi (octave_idx_type n, float z)
-{
-  return octave::math::psi (n, z);
-}
-
 #endif
-
-#endif
--- a/liboctave/numeric/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -39,7 +39,6 @@
   %reldir%/lo-amos-proto.h \
   %reldir%/lo-arpack-proto.h \
   %reldir%/lo-blas-proto.h \
-  %reldir%/lo-fftpack-proto.h \
   %reldir%/lo-lapack-proto.h \
   %reldir%/lo-mappers.h \
   %reldir%/lo-qrupdate-proto.h \
@@ -121,10 +120,6 @@
   $(FFTW_XCPPFLAGS) \
   $(SPARSE_XCPPFLAGS)
 
-%canon_reldir%_libnumeric_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_libnumeric_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/libnumeric.la
 
 liboctave_EXTRA_DIST += $(LIBOCTAVE_OPT_IN)
--- a/liboctave/numeric/oct-fftw.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/oct-fftw.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -136,6 +136,8 @@
         instance->rplan = instance->plan[0] = instance->plan[1] = nullptr;
       }
 #else
+    octave_unused_parameter (nt);
+
     (*current_liboctave_warning_handler)
       ("unable to change number of threads without FFTW thread support");
 #endif
@@ -242,7 +244,7 @@
             // Create matrix with the same size and 16-byte alignment as input
             OCTAVE_LOCAL_BUFFER (Complex, itmp, nn * howmany + 32);
             itmp = reinterpret_cast<Complex *>
-              (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) +
+              (((reinterpret_cast<ptrdiff_t> (itmp) + 15) & ~ 0xF) +
                ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
             *cur_plan_p =
@@ -361,7 +363,7 @@
             // Create matrix with the same size and 16-byte alignment as input
             OCTAVE_LOCAL_BUFFER (double, itmp, nn + 32);
             itmp = reinterpret_cast<double *>
-              (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) +
+              (((reinterpret_cast<ptrdiff_t> (itmp) + 15) & ~ 0xF) +
                ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
             *cur_plan_p =
@@ -494,6 +496,8 @@
         instance->rplan = instance->plan[0] = instance->plan[1] = nullptr;
       }
 #else
+    octave_unused_parameter (nt);
+
     (*current_liboctave_warning_handler)
       ("unable to change number of threads without FFTW thread support");
 #endif
@@ -598,7 +602,7 @@
             // Create matrix with the same size and 16-byte alignment as input
             OCTAVE_LOCAL_BUFFER (FloatComplex, itmp, nn * howmany + 32);
             itmp = reinterpret_cast<FloatComplex *>
-              (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) +
+              (((reinterpret_cast<ptrdiff_t> (itmp) + 15) & ~ 0xF) +
                ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
             *cur_plan_p =
@@ -717,7 +721,7 @@
             // Create matrix with the same size and 16-byte alignment as input
             OCTAVE_LOCAL_BUFFER (float, itmp, nn + 32);
             itmp = reinterpret_cast<float *>
-              (((reinterpret_cast<ptrdiff_t>(itmp) + 15) & ~ 0xF) +
+              (((reinterpret_cast<ptrdiff_t> (itmp) + 15) & ~ 0xF) +
                ((reinterpret_cast<ptrdiff_t> (in)) & 0xF));
 
             *cur_plan_p =
--- a/liboctave/numeric/oct-rand.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/oct-rand.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -43,747 +43,752 @@
 #include "randpoisson.h"
 #include "singleton-cleanup.h"
 
-octave_rand *octave_rand::instance = nullptr;
-
-octave_rand::octave_rand (void)
-  : current_distribution (uniform_dist), use_old_generators (false),
-    rand_states ()
-{
-  initialize_ranlib_generators ();
-
-  initialize_mersenne_twister ();
-}
-
-bool
-octave_rand::instance_ok (void)
+namespace octave
 {
-  bool retval = true;
-
-  if (! instance)
-    {
-      instance = new octave_rand ();
-
-      if (instance)
-        singleton_cleanup_list::add (cleanup_instance);
-    }
-
-  if (! instance)
-    (*current_liboctave_error_handler)
-      ("unable to create octave_rand object!");
-
-  return retval;
-}
-
-double
-octave_rand::do_seed (void)
-{
-  union d2i { double d; int32_t i[2]; };
-  union d2i u;
-
-  octave::mach_info::float_format ff = octave::mach_info::native_float_format ();
+  rand *rand::instance = nullptr;
 
-  switch (ff)
-    {
-    case octave::mach_info::flt_fmt_ieee_big_endian:
-      F77_FUNC (getsd, GETSD) (u.i[1], u.i[0]);
-      break;
-
-    default:
-      F77_FUNC (getsd, GETSD) (u.i[0], u.i[1]);
-      break;
-    }
-
-  return u.d;
-}
-
-static int32_t
-force_to_fit_range (int32_t i, int32_t lo, int32_t hi)
-{
-  assert (hi > lo && lo >= 0 && hi > lo);
-
-  i = (i > 0 ? i : -i);
+  rand::rand (void)
+    : current_distribution (uniform_dist), use_old_generators (false),
+      rand_states ()
+  {
+    initialize_ranlib_generators ();
 
-  if (i < lo)
-    i = lo;
-  else if (i > hi)
-    i = i % hi;
-
-  return i;
-}
-
-void
-octave_rand::do_seed (double s)
-{
-  use_old_generators = true;
-
-  int i0, i1;
-  union d2i { double d; int32_t i[2]; };
-  union d2i u;
-  u.d = s;
-
-  octave::mach_info::float_format ff = octave::mach_info::native_float_format ();
-
-  switch (ff)
-    {
-    case octave::mach_info::flt_fmt_ieee_big_endian:
-      i1 = force_to_fit_range (u.i[0], 1, 2147483563);
-      i0 = force_to_fit_range (u.i[1], 1, 2147483399);
-      break;
+    initialize_mersenne_twister ();
+  }
 
-    default:
-      i0 = force_to_fit_range (u.i[0], 1, 2147483563);
-      i1 = force_to_fit_range (u.i[1], 1, 2147483399);
-      break;
-    }
-
-  F77_FUNC (setsd, SETSD) (i0, i1);
-}
-
-void
-octave_rand::do_reset (void)
-{
-  use_old_generators = true;
-  initialize_ranlib_generators ();
-}
-
-uint32NDArray
-octave_rand::do_state (const std::string& d)
-{
-  return rand_states[d.empty () ? current_distribution : get_dist_id (d)];
-}
-
-void
-octave_rand::do_state (const uint32NDArray& s, const std::string& d)
-{
-  use_old_generators = false;
-
-  int old_dist = current_distribution;
-
-  int new_dist = (d.empty () ? current_distribution : get_dist_id (d));
-
-  uint32NDArray saved_state;
-
-  if (old_dist != new_dist)
-    saved_state = get_internal_state ();
-
-  set_internal_state (s);
-
-  rand_states[new_dist] = get_internal_state ();
-
-  if (old_dist != new_dist)
-    rand_states[old_dist] = saved_state;
-}
+  bool rand::instance_ok (void)
+  {
+    bool retval = true;
 
-void
-octave_rand::do_reset (const std::string& d)
-{
-  use_old_generators = false;
-
-  int old_dist = current_distribution;
-
-  int new_dist = (d.empty () ? current_distribution : get_dist_id (d));
-
-  uint32NDArray saved_state;
-
-  if (old_dist != new_dist)
-    saved_state = get_internal_state ();
-
-  oct_init_by_entropy ();
-  rand_states[new_dist] = get_internal_state ();
-
-  if (old_dist != new_dist)
-    rand_states[old_dist] = saved_state;
-}
+    if (! instance)
+      {
+        instance = new rand ();
 
-std::string
-octave_rand::do_distribution (void)
-{
-  std::string retval;
-
-  switch (current_distribution)
-    {
-    case uniform_dist:
-      retval = "uniform";
-      break;
+        if (instance)
+          singleton_cleanup_list::add (cleanup_instance);
+      }
 
-    case normal_dist:
-      retval = "normal";
-      break;
-
-    case expon_dist:
-      retval = "exponential";
-      break;
-
-    case poisson_dist:
-      retval = "poisson";
-      break;
-
-    case gamma_dist:
-      retval = "gamma";
-      break;
-
-    default:
+    if (! instance)
       (*current_liboctave_error_handler)
-        ("rand: invalid distribution ID = %d", current_distribution);
-      break;
-    }
+        ("unable to create rand object!");
+
+    return retval;
+  }
 
-  return retval;
-}
+  double rand::do_seed (void)
+  {
+    union d2i { double d; int32_t i[2]; };
+    union d2i u;
+
+    mach_info::float_format ff = mach_info::native_float_format ();
+
+    switch (ff)
+      {
+      case mach_info::flt_fmt_ieee_big_endian:
+        F77_FUNC (getsd, GETSD) (u.i[1], u.i[0]);
+        break;
 
-void
-octave_rand::do_distribution (const std::string& d)
-{
-  int id = get_dist_id (d);
+      default:
+        F77_FUNC (getsd, GETSD) (u.i[0], u.i[1]);
+        break;
+      }
+
+    return u.d;
+  }
 
-  switch (id)
-    {
-    case uniform_dist:
-      octave_rand::uniform_distribution ();
-      break;
+  static int32_t
+  force_to_fit_range (int32_t i, int32_t lo, int32_t hi)
+  {
+    assert (hi > lo && lo >= 0 && hi > lo);
+
+    i = (i > 0 ? i : -i);
+
+    if (i < lo)
+      i = lo;
+    else if (i > hi)
+      i = i % hi;
+
+    return i;
+  }
 
-    case normal_dist:
-      octave_rand::normal_distribution ();
-      break;
+  void rand::do_seed (double s)
+  {
+    use_old_generators = true;
+
+    int i0, i1;
+    union d2i { double d; int32_t i[2]; };
+    union d2i u;
+    u.d = s;
 
-    case expon_dist:
-      octave_rand::exponential_distribution ();
-      break;
+    mach_info::float_format ff = mach_info::native_float_format ();
+
+    switch (ff)
+      {
+      case mach_info::flt_fmt_ieee_big_endian:
+        i1 = force_to_fit_range (u.i[0], 1, 2147483563);
+        i0 = force_to_fit_range (u.i[1], 1, 2147483399);
+        break;
 
-    case poisson_dist:
-      octave_rand::poisson_distribution ();
-      break;
+      default:
+        i0 = force_to_fit_range (u.i[0], 1, 2147483563);
+        i1 = force_to_fit_range (u.i[1], 1, 2147483399);
+        break;
+      }
+
+    F77_FUNC (setsd, SETSD) (i0, i1);
+  }
 
-    case gamma_dist:
-      octave_rand::gamma_distribution ();
-      break;
+  void rand::do_reset (void)
+  {
+    use_old_generators = true;
+    initialize_ranlib_generators ();
+  }
 
-    default:
-      (*current_liboctave_error_handler)
-        ("rand: invalid distribution ID = %d", id);
-      break;
-    }
-}
+  uint32NDArray rand::do_state (const std::string& d)
+  {
+    return rand_states[d.empty () ? current_distribution : get_dist_id (d)];
+  }
+
+  void rand::do_state (const uint32NDArray& s, const std::string& d)
+  {
+    use_old_generators = false;
+
+    int old_dist = current_distribution;
 
-void
-octave_rand::do_uniform_distribution (void)
-{
-  switch_to_generator (uniform_dist);
+    int new_dist = (d.empty () ? current_distribution : get_dist_id (d));
+
+    uint32NDArray saved_state;
+
+    if (old_dist != new_dist)
+      saved_state = get_internal_state ();
+
+    set_internal_state (s);
 
-  F77_FUNC (setcgn, SETCGN) (uniform_dist);
-}
+    rand_states[new_dist] = get_internal_state ();
+
+    if (old_dist != new_dist)
+      rand_states[old_dist] = saved_state;
+  }
+
+  void rand::do_reset (const std::string& d)
+  {
+    use_old_generators = false;
 
-void
-octave_rand::do_normal_distribution (void)
-{
-  switch_to_generator (normal_dist);
+    int old_dist = current_distribution;
+
+    int new_dist = (d.empty () ? current_distribution : get_dist_id (d));
+
+    uint32NDArray saved_state;
+
+    if (old_dist != new_dist)
+      saved_state = get_internal_state ();
 
-  F77_FUNC (setcgn, SETCGN) (normal_dist);
-}
+    init_mersenne_twister ();
+    rand_states[new_dist] = get_internal_state ();
 
-void
-octave_rand::do_exponential_distribution (void)
-{
-  switch_to_generator (expon_dist);
+    if (old_dist != new_dist)
+      rand_states[old_dist] = saved_state;
+  }
+
+  std::string rand::do_distribution (void)
+  {
+    std::string retval;
 
-  F77_FUNC (setcgn, SETCGN) (expon_dist);
-}
+    switch (current_distribution)
+      {
+      case uniform_dist:
+        retval = "uniform";
+        break;
+
+      case normal_dist:
+        retval = "normal";
+        break;
 
-void
-octave_rand::do_poisson_distribution (void)
-{
-  switch_to_generator (poisson_dist);
+      case expon_dist:
+        retval = "exponential";
+        break;
 
-  F77_FUNC (setcgn, SETCGN) (poisson_dist);
-}
+      case poisson_dist:
+        retval = "poisson";
+        break;
+
+      case gamma_dist:
+        retval = "gamma";
+        break;
 
-void
-octave_rand::do_gamma_distribution (void)
-{
-  switch_to_generator (gamma_dist);
+      default:
+        (*current_liboctave_error_handler)
+          ("rand: invalid distribution ID = %d", current_distribution);
+        break;
+      }
+
+    return retval;
+  }
+
+  void rand::do_distribution (const std::string& d)
+  {
+    int id = get_dist_id (d);
 
-  F77_FUNC (setcgn, SETCGN) (gamma_dist);
-}
+    switch (id)
+      {
+      case uniform_dist:
+        rand::uniform_distribution ();
+        break;
 
-double
-octave_rand::do_scalar (double a)
-{
-  double retval = 0.0;
+      case normal_dist:
+        rand::normal_distribution ();
+        break;
+
+      case expon_dist:
+        rand::exponential_distribution ();
+        break;
 
-  if (use_old_generators)
-    {
-      switch (current_distribution)
-        {
-        case uniform_dist:
-          F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, retval);
-          break;
+      case poisson_dist:
+        rand::poisson_distribution ();
+        break;
+
+      case gamma_dist:
+        rand::gamma_distribution ();
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("rand: invalid distribution ID = %d", id);
+        break;
+      }
+  }
+
+  void rand::do_uniform_distribution (void)
+  {
+    switch_to_generator (uniform_dist);
 
-        case normal_dist:
-          F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, retval);
-          break;
+    F77_FUNC (setcgn, SETCGN) (uniform_dist);
+  }
+
+  void rand::do_normal_distribution (void)
+  {
+    switch_to_generator (normal_dist);
+
+    F77_FUNC (setcgn, SETCGN) (normal_dist);
+  }
 
-        case expon_dist:
-          F77_FUNC (dgenexp, DGENEXP) (1.0, retval);
-          break;
+  void rand::do_exponential_distribution (void)
+  {
+    switch_to_generator (expon_dist);
+
+    F77_FUNC (setcgn, SETCGN) (expon_dist);
+  }
+
+  void rand::do_poisson_distribution (void)
+  {
+    switch_to_generator (poisson_dist);
+
+    F77_FUNC (setcgn, SETCGN) (poisson_dist);
+  }
 
-        case poisson_dist:
-          if (a < 0.0 || ! octave::math::isfinite (a))
-            retval = octave::numeric_limits<double>::NaN ();
-          else
-            {
-              // workaround bug in ignpoi, by calling with different Mu
-              F77_FUNC (dignpoi, DIGNPOI) (a + 1, retval);
-              F77_FUNC (dignpoi, DIGNPOI) (a, retval);
-            }
-          break;
+  void rand::do_gamma_distribution (void)
+  {
+    switch_to_generator (gamma_dist);
+
+    F77_FUNC (setcgn, SETCGN) (gamma_dist);
+  }
+
+  template <>
+  double rand::uniform<double> (void)
+  {
+    double retval;
+
+    if (use_old_generators)
+      F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, retval);
+    else
+      retval = octave::rand_uniform<double> ();
+
+    return retval;
+  }
 
-        case gamma_dist:
-          if (a <= 0.0 || ! octave::math::isfinite (a))
-            retval = octave::numeric_limits<double>::NaN ();
-          else
-            F77_FUNC (dgengam, DGENGAM) (1.0, a, retval);
-          break;
+  template <>
+  double rand::normal<double> (void)
+  {
+    double retval;
+
+    if (use_old_generators)
+      F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, retval);
+    else
+      retval = octave::rand_normal<double> ();
 
-        default:
-          (*current_liboctave_error_handler)
-            ("rand: invalid distribution ID = %d", current_distribution);
-          break;
-        }
-    }
-  else
-    {
-      switch (current_distribution)
-        {
-        case uniform_dist:
-          retval = oct_randu ();
-          break;
+    return retval;
+  }
+
+  template <>
+  double rand::exponential<double> (void)
+  {
+    double retval;
+
+    if (use_old_generators)
+      F77_FUNC (dgenexp, DGENEXP) (1.0, retval);
+    else
+      retval = octave::rand_exponential<double> ();
 
-        case normal_dist:
-          retval = oct_randn ();
-          break;
+    return retval;
+  }
 
-        case expon_dist:
-          retval = oct_rande ();
-          break;
+  template <>
+  double rand::poisson<double> (double a)
+  {
+    double retval;
 
-        case poisson_dist:
-          retval = oct_randp (a);
-          break;
+    if (use_old_generators)
+      {
+        if (a < 0.0 || ! math::isfinite (a))
+          retval = numeric_limits<double>::NaN ();
+        else
+          {
+            // workaround bug in ignpoi, by calling with different Mu
+            F77_FUNC (dignpoi, DIGNPOI) (a + 1, retval);
+            F77_FUNC (dignpoi, DIGNPOI) (a, retval);
+          }
+      }
+    else
+      retval = octave::rand_poisson<double> (a);
+
+    return retval;
+  }
 
-        case gamma_dist:
-          retval = oct_randg (a);
-          break;
+  template <>
+  double rand::gamma<double> (double a)
+  {
+    double retval;
 
-        default:
-          (*current_liboctave_error_handler)
-            ("rand: invalid distribution ID = %d", current_distribution);
-          break;
-        }
+    if (use_old_generators)
+      {
+        if (a <= 0.0 || ! math::isfinite (a))
+          retval = numeric_limits<double>::NaN ();
+        else
+          F77_FUNC (dgengam, DGENGAM) (1.0, a, retval);
+      }
+    else
+      retval = octave::rand_gamma<double> (a);
+
+    return retval;
+  }
 
-      save_state ();
-    }
+  template <>
+  float rand::uniform<float> (void)
+  {
+    float retval;
 
-  return retval;
-}
+    if (use_old_generators)
+      F77_FUNC (fgenunf, FGENUNF) (0.0f, 1.0f, retval);
+    else
+      retval = octave::rand_uniform<float> ();
 
-float
-octave_rand::do_float_scalar (float a)
-{
-  float retval = 0.0;
+    return retval;
+  }
+
+  template <>
+  float rand::normal<float> (void)
+  {
+    float retval;
 
-  if (use_old_generators)
-    {
-      switch (current_distribution)
-        {
-        case uniform_dist:
-          F77_FUNC (fgenunf, FGENUNF) (0.0f, 1.0f, retval);
-          break;
+    if (use_old_generators)
+      F77_FUNC (fgennor, FGENNOR) (0.0f, 1.0f, retval);
+    else
+      retval = octave::rand_normal<float> ();
+
+    return retval;
+  }
+
+  template <>
+  float rand::exponential<float> (void)
+  {
+    float retval;
 
-        case normal_dist:
-          F77_FUNC (fgennor, FGENNOR) (0.0f, 1.0f, retval);
-          break;
+    if (use_old_generators)
+      F77_FUNC (fgenexp, FGENEXP) (1.0f, retval);
+    else
+      retval = octave::rand_exponential<float> ();
 
-        case expon_dist:
-          F77_FUNC (fgenexp, FGENEXP) (1.0f, retval);
-          break;
+    return retval;
+  }
+
+  template <>
+  float rand::poisson<float> (float a)
+  {
+    float retval;
 
-        case poisson_dist:
-          if (a < 0.0f || ! octave::math::isfinite (a))
-            retval = octave::numeric_limits<float>::NaN ();
-          else
-            {
-              // workaround bug in ignpoi, by calling with different Mu
-              F77_FUNC (fignpoi, FIGNPOI) (a + 1, retval);
-              F77_FUNC (fignpoi, FIGNPOI) (a, retval);
-            }
-          break;
+    if (use_old_generators)
+      {
+        if (a < 0.0f || ! math::isfinite (a))
+          retval = numeric_limits<float>::NaN ();
+        else
+          {
+            // workaround bug in ignpoi, by calling with different Mu
+            F77_FUNC (fignpoi, FIGNPOI) (a + 1, retval);
+            F77_FUNC (fignpoi, FIGNPOI) (a, retval);
+          }
+      }
+    else
+      {
+        // Keep poisson distribution in double precision for accuracy
+        retval = octave::rand_poisson<double> (a);
+      }
+
+    return retval;
+  }
 
-        case gamma_dist:
-          if (a <= 0.0f || ! octave::math::isfinite (a))
-            retval = octave::numeric_limits<float>::NaN ();
-          else
-            F77_FUNC (fgengam, FGENGAM) (1.0, a, retval);
-          break;
+  template <>
+  float rand::gamma<float> (float a)
+  {
+    float retval;
+
+    if (use_old_generators)
+      {
+        if (a <= 0.0f || ! math::isfinite (a))
+          retval = numeric_limits<float>::NaN ();
+        else
+          F77_FUNC (fgengam, FGENGAM) (1.0f, a, retval);
+      }
+    else
+      retval = octave::rand_gamma<float> (a);
+
+    return retval;
+  }
+
+  template <typename T>
+  T rand::do_scalar (T a)
+  {
+    T retval = 0;
 
-        default:
-          (*current_liboctave_error_handler)
-            ("rand: invalid distribution ID = %d", current_distribution);
-          break;
-        }
-    }
-  else
-    {
-      switch (current_distribution)
-        {
-        case uniform_dist:
-          retval = oct_float_randu ();
-          break;
+    switch (current_distribution)
+      {
+      case uniform_dist:
+        retval = uniform<T> ();
+        break;
+
+      case normal_dist:
+        retval = normal<T> ();
+        break;
+
+      case expon_dist:
+        retval = exponential<T> ();
+        break;
+
+      case poisson_dist:
+        retval = poisson<T> (a);
+        break;
+
+      case gamma_dist:
+        retval = gamma<T> (a);
+        break;
 
-        case normal_dist:
-          retval = oct_float_randn ();
-          break;
+      default:
+        (*current_liboctave_error_handler)
+          ("rand: invalid distribution ID = %d", current_distribution);
+        break;
+      }
+
+    if (! use_old_generators)
+      save_state ();
+
+    return retval;
+  }
 
-        case expon_dist:
-          retval = oct_float_rande ();
-          break;
+  template double rand::do_scalar<double> (double);
+  template float rand::do_scalar<float> (float);
 
-        case poisson_dist:
-          // Keep poisson distribution in double precision for accuracy
-          retval = oct_randp (a);
-          break;
+  template <typename T>
+  Array<T>
+  rand::do_vector (octave_idx_type n, T a)
+  {
+    Array<T> retval;
+
+    if (n > 0)
+      {
+        retval.clear (n, 1);
 
-        case gamma_dist:
-          retval = oct_float_randg (a);
-          break;
+        fill (retval.numel (), retval.fortran_vec (), a);
+      }
+    else if (n < 0)
+      (*current_liboctave_error_handler) ("rand: invalid negative argument");
+
+    return retval;
+  }
+
+  template Array<double> rand::do_vector<double> (octave_idx_type, double);
+  template Array<float> rand::do_vector<float> (octave_idx_type, float);
 
-        default:
-          (*current_liboctave_error_handler)
-            ("rand: invalid distribution ID = %d", current_distribution);
-          break;
-        }
+  NDArray rand::do_nd_array (const dim_vector& dims, double a)
+  {
+    NDArray retval;
+
+    if (! dims.all_zero ())
+      {
+        retval.clear (dims);
+
+        fill (retval.numel (), retval.fortran_vec (), a);
+      }
 
-      save_state ();
-    }
+    return retval;
+  }
 
-  return retval;
-}
+  FloatNDArray rand::do_float_nd_array (const dim_vector& dims, float a)
+  {
+    FloatNDArray retval;
+
+    if (! dims.all_zero ())
+      {
+        retval.clear (dims);
 
-Array<double>
-octave_rand::do_vector (octave_idx_type n, double a)
-{
-  Array<double> retval;
+        fill (retval.numel (), retval.fortran_vec (), a);
+      }
 
-  if (n > 0)
-    {
-      retval.clear (n, 1);
+    return retval;
+  }
+
+  // Make the random number generator give us a different sequence every
+  // time we start octave unless we specifically set the seed.  The
+  // technique used below will cycle monthly, but it does seem to
+  // work ok to give fairly different seeds each time Octave starts.
 
-      fill (retval.numel (), retval.fortran_vec (), a);
-    }
-  else if (n < 0)
-    (*current_liboctave_error_handler) ("rand: invalid negative argument");
+  void rand::initialize_ranlib_generators (void)
+  {
+    sys::localtime tm;
+    int stored_distribution = current_distribution;
+    F77_FUNC (setcgn, SETCGN) (uniform_dist);
+
+    int hour = tm.hour () + 1;
+    int minute = tm.min () + 1;
+    int second = tm.sec () + 1;
 
-  return retval;
-}
+    int32_t s0 = tm.mday () * hour * minute * second;
+    int32_t s1 = hour * minute * second;
+
+    s0 = force_to_fit_range (s0, 1, 2147483563);
+    s1 = force_to_fit_range (s1, 1, 2147483399);
+
+    F77_FUNC (setall, SETALL) (s0, s1);
+    F77_FUNC (setcgn, SETCGN) (stored_distribution);
+  }
+
+  void rand::initialize_mersenne_twister (void)
+  {
+    uint32NDArray s;
 
-Array<float>
-octave_rand::do_float_vector (octave_idx_type n, float a)
-{
-  Array<float> retval;
+    init_mersenne_twister ();
+    s = get_internal_state ();
+    rand_states[uniform_dist] = s;
+
+    init_mersenne_twister ();
+    s = get_internal_state ();
+    rand_states[normal_dist] = s;
+
+    init_mersenne_twister ();
+    s = get_internal_state ();
+    rand_states[expon_dist] = s;
 
-  if (n > 0)
-    {
-      retval.clear (n, 1);
+    init_mersenne_twister ();
+    s = get_internal_state ();
+    rand_states[poisson_dist] = s;
+
+    init_mersenne_twister ();
+    s = get_internal_state ();
+    rand_states[gamma_dist] = s;
 
-      fill (retval.numel (), retval.fortran_vec (), a);
-    }
-  else if (n < 0)
-    (*current_liboctave_error_handler) ("rand: invalid negative argument");
+    // All of the initializations above have messed with the internal state.
+    // Restore the state of the currently selected distribution.
+    set_internal_state (rand_states[current_distribution]);
+  }
 
-  return retval;
-}
+  uint32NDArray rand::get_internal_state (void)
+  {
+    uint32NDArray s (dim_vector (MT_N + 1, 1));
 
-NDArray
-octave_rand::do_nd_array (const dim_vector& dims, double a)
-{
-  NDArray retval;
+    get_mersenne_twister_state (reinterpret_cast<uint32_t *> (s.fortran_vec ()));
+
+    return s;
+  }
 
-  if (! dims.all_zero ())
-    {
-      retval.clear (dims);
+  void rand::save_state (void)
+  {
+    rand_states[current_distribution] = get_internal_state ();;
+  }
+
+  int rand::get_dist_id (const std::string& d)
+  {
+    int retval = unknown_dist;
 
-      fill (retval.numel (), retval.fortran_vec (), a);
-    }
+    if (d == "uniform" || d == "rand")
+      retval = uniform_dist;
+    else if (d == "normal" || d == "randn")
+      retval = normal_dist;
+    else if (d == "exponential" || d == "rande")
+      retval = expon_dist;
+    else if (d == "poisson" || d == "randp")
+      retval = poisson_dist;
+    else if (d == "gamma" || d == "randg")
+      retval = gamma_dist;
+    else
+      (*current_liboctave_error_handler)
+        ("rand: invalid distribution '%s'", d.c_str ());
 
-  return retval;
-}
+    return retval;
+  }
 
-FloatNDArray
-octave_rand::do_float_nd_array (const dim_vector& dims, float a)
-{
-  FloatNDArray retval;
+  void rand::set_internal_state (const uint32NDArray& s)
+  {
+    octave_idx_type len = s.numel ();
+
+    const uint32_t *sdata = reinterpret_cast <const uint32_t *> (s.data ());
 
-  if (! dims.all_zero ())
-    {
-      retval.clear (dims);
+    if (len == MT_N + 1 && sdata[MT_N] <= MT_N && sdata[MT_N] > 0)
+      set_mersenne_twister_state (sdata);
+    else
+      init_mersenne_twister (sdata, len);
+  }
 
-      fill (retval.numel (), retval.fortran_vec (), a);
-    }
+  void rand::switch_to_generator (int dist)
+  {
+    if (dist != current_distribution)
+      {
+        current_distribution = dist;
 
-  return retval;
-}
+        set_internal_state (rand_states[dist]);
+      }
+  }
+
+  void rand::fill (octave_idx_type len, double *v, double a)
+  {
+    if (len < 1)
+      return;
 
-// Make the random number generator give us a different sequence every
-// time we start octave unless we specifically set the seed.  The
-// technique used below will cycle monthly, but it does seem to
-// work ok to give fairly different seeds each time Octave starts.
+    switch (current_distribution)
+      {
+      case uniform_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { double x; F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, x); return x; });
+        else
+          rand_uniform<double> (len, v);
+        break;
 
-void
-octave_rand::initialize_ranlib_generators (void)
-{
-  octave::sys::localtime tm;
-  int stored_distribution = current_distribution;
-  F77_FUNC (setcgn, SETCGN) (uniform_dist);
+      case normal_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { double x; F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, x); return x; });
+        else
+          rand_normal<double> (len, v);
+        break;
 
-  int hour = tm.hour () + 1;
-  int minute = tm.min () + 1;
-  int second = tm.sec () + 1;
+      case expon_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { double x; F77_FUNC (dgenexp, DGENEXP) (1.0, x); return x; });
+        else
+          rand_exponential<double> (len, v);
+        break;
 
-  int32_t s0 = tm.mday () * hour * minute * second;
-  int32_t s1 = hour * minute * second;
-
-  s0 = force_to_fit_range (s0, 1, 2147483563);
-  s1 = force_to_fit_range (s1, 1, 2147483399);
-
-  F77_FUNC (setall, SETALL) (s0, s1);
-  F77_FUNC (setcgn, SETCGN) (stored_distribution);
-}
+      case poisson_dist:
+        if (use_old_generators)
+          {
+            if (a < 0.0 || ! math::isfinite (a))
+              std::fill_n (v, len, numeric_limits<double>::NaN ());
+            else
+              {
+                // workaround bug in ignpoi, by calling with different Mu
+                double tmp;
+                F77_FUNC (dignpoi, DIGNPOI) (a + 1, tmp);
+                std::generate_n (v, len, [a](void) { double x; F77_FUNC (dignpoi, DIGNPOI) (a, x); return x; });
+              }
+          }
+        else
+          rand_poisson<double> (a, len, v);
+        break;
 
-void
-octave_rand::initialize_mersenne_twister (void)
-{
-  uint32NDArray s;
+      case gamma_dist:
+        if (use_old_generators)
+          {
+            if (a <= 0.0 || ! math::isfinite (a))
+              std::fill_n (v, len, numeric_limits<double>::NaN ());
+            else
+              std::generate_n (v, len, [a](void) { double x; F77_FUNC (dgengam, DGENGAM) (1.0, a, x); return x; });
+          }
+        else
+          rand_gamma<double> (a, len, v);
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("rand: invalid distribution ID = %d", current_distribution);
+        break;
+      }
 
-  oct_init_by_entropy ();
-  s = get_internal_state ();
-  rand_states[uniform_dist] = s;
+    save_state ();
+
+    return;
+  }
 
-  oct_init_by_entropy ();
-  s = get_internal_state ();
-  rand_states[normal_dist] = s;
+  void rand::fill (octave_idx_type len, float *v, float a)
+  {
+    if (len < 1)
+      return;
+
+    switch (current_distribution)
+      {
+      case uniform_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { float x; F77_FUNC (fgenunf, FGENUNF) (0.0f, 1.0f, x); return x; });
+        else
+          octave::rand_uniform<float> (len, v);
+        break;
 
-  oct_init_by_entropy ();
-  s = get_internal_state ();
-  rand_states[expon_dist] = s;
+      case normal_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { float x; F77_FUNC (fgennor, FGENNOR) (0.0f, 1.0f, x); return x; });
+        else
+          octave::rand_normal<float> (len, v);
+        break;
 
-  oct_init_by_entropy ();
-  s = get_internal_state ();
-  rand_states[poisson_dist] = s;
-
-  oct_init_by_entropy ();
-  s = get_internal_state ();
-  rand_states[gamma_dist] = s;
+      case expon_dist:
+        if (use_old_generators)
+          std::generate_n (v, len, [](void) { float x; F77_FUNC (fgenexp, FGENEXP) (1.0f, x); return x; });
+        else
+          octave::rand_exponential<float> (len, v);
+        break;
 
-  // All of the initializations above have messed with the internal state.
-  // Restore the state of the currently selected distribution.
-  set_internal_state (rand_states[current_distribution]);
-}
+      case poisson_dist:
+        if (use_old_generators)
+          {
+            if (a < 0.0f || ! math::isfinite (a))
+              std::fill_n (v, len, numeric_limits<float>::NaN ());
+            else
+              {
+                // workaround bug in ignpoi, by calling with different Mu
+                float tmp;
+                F77_FUNC (fignpoi, FIGNPOI) (a + 1, tmp);
+                std::generate_n (v, len, [a](void) { float x; F77_FUNC (fignpoi, FIGNPOI) (a, x); return x; });
+              }
+          }
+        else
+          octave::rand_poisson<float> (a, len, v);
+        break;
 
-uint32NDArray
-octave_rand::get_internal_state (void)
-{
-  uint32NDArray s (dim_vector (MT_N + 1, 1));
+      case gamma_dist:
+        if (use_old_generators)
+          {
+            if (a <= 0.0f || ! math::isfinite (a))
+              std::fill_n (v, len, numeric_limits<float>::NaN ());
+            else
+              std::generate_n (v, len, [a](void) { float x; F77_FUNC (fgengam, FGENGAM) (1.0f, a, x); return x; });
+          }
+        else
+          octave::rand_gamma<float> (a, len, v);
+        break;
 
-  oct_get_state (reinterpret_cast<uint32_t *> (s.fortran_vec ()));
+      default:
+        (*current_liboctave_error_handler)
+          ("rand: invalid distribution ID = %d", current_distribution);
+        break;
+      }
 
-  return s;
+    save_state ();
+
+    return;
+  }
 }
-
-void
-octave_rand::save_state (void)
-{
-  rand_states[current_distribution] = get_internal_state ();;
-}
-
-int
-octave_rand::get_dist_id (const std::string& d)
-{
-  int retval = unknown_dist;
-
-  if (d == "uniform" || d == "rand")
-    retval = uniform_dist;
-  else if (d == "normal" || d == "randn")
-    retval = normal_dist;
-  else if (d == "exponential" || d == "rande")
-    retval = expon_dist;
-  else if (d == "poisson" || d == "randp")
-    retval = poisson_dist;
-  else if (d == "gamma" || d == "randg")
-    retval = gamma_dist;
-  else
-    (*current_liboctave_error_handler)
-      ("rand: invalid distribution '%s'", d.c_str ());
-
-  return retval;
-}
-
-void
-octave_rand::set_internal_state (const uint32NDArray& s)
-{
-  octave_idx_type len = s.numel ();
-
-  const uint32_t *sdata = reinterpret_cast <const uint32_t *> (s.data ());
-
-  if (len == MT_N + 1 && sdata[MT_N] <= MT_N && sdata[MT_N] > 0)
-    oct_set_state (sdata);
-  else
-    oct_init_by_array (sdata, len);
-}
-
-void
-octave_rand::switch_to_generator (int dist)
-{
-  if (dist != current_distribution)
-    {
-      current_distribution = dist;
-
-      set_internal_state (rand_states[dist]);
-    }
-}
-
-void
-octave_rand::fill (octave_idx_type len, double *v, double a)
-{
-  if (len < 1)
-    return;
-
-  switch (current_distribution)
-    {
-    case uniform_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { double x; F77_FUNC (dgenunf, DGENUNF) (0.0, 1.0, x); return x; });
-      else
-        oct_fill_randu (len, v);
-      break;
-
-    case normal_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { double x; F77_FUNC (dgennor, DGENNOR) (0.0, 1.0, x); return x; });
-      else
-        oct_fill_randn (len, v);
-      break;
-
-    case expon_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { double x; F77_FUNC (dgenexp, DGENEXP) (1.0, x); return x; });
-      else
-        oct_fill_rande (len, v);
-      break;
-
-    case poisson_dist:
-      if (use_old_generators)
-        {
-          if (a < 0.0 || ! octave::math::isfinite (a))
-            std::fill_n (v, len, octave::numeric_limits<double>::NaN ());
-          else
-            {
-              // workaround bug in ignpoi, by calling with different Mu
-              double tmp;
-              F77_FUNC (dignpoi, DIGNPOI) (a + 1, tmp);
-              std::generate_n (v, len, [a](void) { double x; F77_FUNC (dignpoi, DIGNPOI) (a, x); return x; });
-            }
-        }
-      else
-        oct_fill_randp (a, len, v);
-      break;
-
-    case gamma_dist:
-      if (use_old_generators)
-        {
-          if (a <= 0.0 || ! octave::math::isfinite (a))
-            std::fill_n (v, len, octave::numeric_limits<double>::NaN ());
-          else
-            std::generate_n (v, len, [a](void) { double x; F77_FUNC (dgengam, DGENGAM) (1.0, a, x); return x; });
-        }
-      else
-        oct_fill_randg (a, len, v);
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("rand: invalid distribution ID = %d", current_distribution);
-      break;
-    }
-
-  save_state ();
-
-  return;
-}
-
-void
-octave_rand::fill (octave_idx_type len, float *v, float a)
-{
-  if (len < 1)
-    return;
-
-  switch (current_distribution)
-    {
-    case uniform_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { float x; F77_FUNC (fgenunf, FGENUNF) (0.0f, 1.0f, x); return x; });
-      else
-        oct_fill_float_randu (len, v);
-      break;
-
-    case normal_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { float x; F77_FUNC (fgennor, FGENNOR) (0.0f, 1.0f, x); return x; });
-      else
-        oct_fill_float_randn (len, v);
-      break;
-
-    case expon_dist:
-      if (use_old_generators)
-        std::generate_n (v, len, [](void) { float x; F77_FUNC (fgenexp, FGENEXP) (1.0f, x); return x; });
-      else
-        oct_fill_float_rande (len, v);
-      break;
-
-    case poisson_dist:
-      if (use_old_generators)
-        {
-          if (a < 0.0f || ! octave::math::isfinite (a))
-            std::fill_n (v, len, octave::numeric_limits<float>::NaN ());
-          else
-            {
-              // workaround bug in ignpoi, by calling with different Mu
-              float tmp;
-              F77_FUNC (fignpoi, FIGNPOI) (a + 1, tmp);
-              std::generate_n (v, len, [a](void) { float x; F77_FUNC (fignpoi, FIGNPOI) (a, x); return x; });
-            }
-        }
-      else
-        oct_fill_float_randp (a, len, v);
-      break;
-
-    case gamma_dist:
-      if (use_old_generators)
-        {
-          if (a <= 0.0f || ! octave::math::isfinite (a))
-            std::fill_n (v, len, octave::numeric_limits<float>::NaN ());
-          else
-            std::generate_n (v, len, [a](void) { float x; F77_FUNC (fgengam, FGENGAM) (1.0f, a, x); return x; });
-        }
-      else
-        oct_fill_float_randg (a, len, v);
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("rand: invalid distribution ID = %d", current_distribution);
-      break;
-    }
-
-  save_state ();
-
-  return;
-}
--- a/liboctave/numeric/oct-rand.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/oct-rand.h	Thu Dec 20 17:18:56 2018 -0500
@@ -36,247 +36,262 @@
 
 //class dim_vector;
 
-class
-OCTAVE_API
-octave_rand
+namespace octave
 {
-protected:
-
-  octave_rand (void);
-
-public:
-
-  ~octave_rand (void) = default;
-
-  static bool instance_ok (void);
-
-  // Return the current seed.
-  static double seed (void)
-  {
-    return instance_ok () ? instance->do_seed ()
-                          : octave::numeric_limits<double>::NaN ();
-  }
-
-  // Set the seed.
-  static void seed (double s)
-  {
-    if (instance_ok ())
-      instance->do_seed (s);
-  }
-
-  // Reset the seed.
-  static void reset (void)
-  {
-    if (instance_ok ())
-      instance->do_reset ();
-  }
-
-  // Return the current state.
-  static uint32NDArray state (const std::string& d = "")
-  {
-    return instance_ok () ? instance->do_state (d) : uint32NDArray ();
-  }
-
-  // Set the current state/
-  static void state (const uint32NDArray& s,
-                     const std::string& d = "")
-  {
-    if (instance_ok ())
-      instance->do_state (s, d);
-  }
-
-  // Reset the current state/
-  static void reset (const std::string& d)
-  {
-    if (instance_ok ())
-      instance->do_reset (d);
-  }
-
-  // Return the current distribution.
-  static std::string distribution (void)
+  class OCTAVE_API rand
   {
-    return instance_ok () ? instance->do_distribution () : "";
-  }
+  protected:
+
+    rand (void);
+
+  public:
+
+    ~rand (void) = default;
+
+    static bool instance_ok (void);
 
-  // Set the current distribution.  May be either "uniform" (the
-  // default), "normal", "exponential", "poisson", or "gamma".
-  static void distribution (const std::string& d)
-  {
-    if (instance_ok ())
-      instance->do_distribution (d);
-  }
+    // Return the current seed.
+    static double seed (void)
+    {
+      return instance_ok () ? instance->do_seed ()
+        : octave::numeric_limits<double>::NaN ();
+    }
+
+    // Set the seed.
+    static void seed (double s)
+    {
+      if (instance_ok ())
+        instance->do_seed (s);
+    }
 
-  static void uniform_distribution (void)
-  {
-    if (instance_ok ())
-      instance->do_uniform_distribution ();
-  }
+    // Reset the seed.
+    static void reset (void)
+    {
+      if (instance_ok ())
+        instance->do_reset ();
+    }
+
+    // Return the current state.
+    static uint32NDArray state (const std::string& d = "")
+    {
+      return instance_ok () ? instance->do_state (d) : uint32NDArray ();
+    }
 
-  static void normal_distribution (void)
-  {
-    if (instance_ok ())
-      instance->do_normal_distribution ();
-  }
+    // Set the current state/
+    static void state (const uint32NDArray& s,
+                       const std::string& d = "")
+    {
+      if (instance_ok ())
+        instance->do_state (s, d);
+    }
 
-  static void exponential_distribution (void)
-  {
-    if (instance_ok ())
-      instance->do_exponential_distribution ();
-  }
+    // Reset the current state/
+    static void reset (const std::string& d)
+    {
+      if (instance_ok ())
+        instance->do_reset (d);
+    }
+
+    // Return the current distribution.
+    static std::string distribution (void)
+    {
+      return instance_ok () ? instance->do_distribution () : "";
+    }
 
-  static void poisson_distribution (void)
-  {
-    if (instance_ok ())
-      instance->do_poisson_distribution ();
-  }
+    // Set the current distribution.  May be either "uniform" (the
+    // default), "normal", "exponential", "poisson", or "gamma".
+    static void distribution (const std::string& d)
+    {
+      if (instance_ok ())
+        instance->do_distribution (d);
+    }
+
+    static void uniform_distribution (void)
+    {
+      if (instance_ok ())
+        instance->do_uniform_distribution ();
+    }
 
-  static void gamma_distribution (void)
-  {
-    if (instance_ok ())
-      instance->do_gamma_distribution ();
-  }
+    static void normal_distribution (void)
+    {
+      if (instance_ok ())
+        instance->do_normal_distribution ();
+    }
+
+    static void exponential_distribution (void)
+    {
+      if (instance_ok ())
+        instance->do_exponential_distribution ();
+    }
+
+    static void poisson_distribution (void)
+    {
+      if (instance_ok ())
+        instance->do_poisson_distribution ();
+    }
 
-  // Return the next number from the sequence.
-  static double scalar (double a = 1.0)
-  {
-    return instance_ok () ? instance->do_scalar (a)
-                          : octave::numeric_limits<double>::NaN ();
-  }
+    static void gamma_distribution (void)
+    {
+      if (instance_ok ())
+        instance->do_gamma_distribution ();
+    }
+
+    // Return the next number from the sequence.
+    static double scalar (double a = 1.0)
+    {
+      return instance_ok () ? instance->do_scalar (a)
+        : octave::numeric_limits<double>::NaN ();
+    }
 
-  // Return the next number from the sequence.
-  static float float_scalar (float a = 1.0)
-  {
-    return instance_ok () ? instance->do_float_scalar (a)
-                          : octave::numeric_limits<float>::NaN ();
-  }
+    // Return the next number from the sequence.
+    static float float_scalar (float a = 1.0)
+    {
+      return instance_ok () ? instance->do_scalar (a)
+        : octave::numeric_limits<float>::NaN ();
+    }
 
-  // Return an array of numbers from the sequence.
-  static Array<double> vector (octave_idx_type n, double a = 1.0)
-  {
-    return instance_ok () ? instance->do_vector (n, a) : Array<double> ();
-  }
+    // Return an array of numbers from the sequence.
+    static Array<double> vector (octave_idx_type n, double a = 1.0)
+    {
+      return instance_ok () ? instance->do_vector (n, a) : Array<double> ();
+    }
+
+    // Return an array of numbers from the sequence.
+    static Array<float> float_vector (octave_idx_type n, float a = 1.0)
+    {
+      return instance_ok () ? instance->do_vector (n, a) : Array<float> ();
+    }
 
-  // Return an array of numbers from the sequence.
-  static Array<float> float_vector (octave_idx_type n, float a = 1.0)
-  {
-    return instance_ok () ? instance->do_float_vector (n, a) : Array<float> ();
-  }
+    // Return an N-dimensional array of numbers from the sequence,
+    // filled in column major order.
+    static NDArray nd_array (const dim_vector& dims, double a = 1.0)
+    {
+      return instance_ok () ? instance->do_nd_array (dims, a) : NDArray ();
+    }
 
-  // Return an N-dimensional array of numbers from the sequence,
-  // filled in column major order.
-  static NDArray nd_array (const dim_vector& dims, double a = 1.0)
-  {
-    return instance_ok () ? instance->do_nd_array (dims, a) : NDArray ();
-  }
+    // Return an N-dimensional array of numbers from the sequence,
+    // filled in column major order.
+    static FloatNDArray float_nd_array (const dim_vector& dims, float a = 1.0)
+    {
+      return instance_ok () ? instance->do_float_nd_array (dims, a)
+        : FloatNDArray ();
+    }
 
-  // Return an N-dimensional array of numbers from the sequence,
-  // filled in column major order.
-  static FloatNDArray float_nd_array (const dim_vector& dims, float a = 1.0)
-  {
-    return instance_ok () ? instance->do_float_nd_array (dims, a)
-                          : FloatNDArray ();
-  }
+  private:
+
+    static rand *instance;
+
+    static void cleanup_instance (void) { delete instance; instance = nullptr; }
 
-private:
-
-  static octave_rand *instance;
-
-  static void cleanup_instance (void) { delete instance; instance = nullptr; }
+    enum
+    {
+      unknown_dist,
+      uniform_dist,
+      normal_dist,
+      expon_dist,
+      poisson_dist,
+      gamma_dist
+    };
 
-  enum
-  {
-    unknown_dist,
-    uniform_dist,
-    normal_dist,
-    expon_dist,
-    poisson_dist,
-    gamma_dist
-  };
+    // Current distribution of random numbers.
+    int current_distribution;
 
-  // Current distribution of random numbers.
-  int current_distribution;
+    // If TRUE, use old RANLIB generators.  Otherwise, use Mersenne
+    // Twister generator.
+    bool use_old_generators;
+
+    // Saved MT states.
+    std::map<int, uint32NDArray> rand_states;
+
+    // Return the current seed.
+    double do_seed (void);
 
-  // If TRUE, use old RANLIB generators.  Otherwise, use Mersenne
-  // Twister generator.
-  bool use_old_generators;
+    // Set the seed.
+    void do_seed (double s);
 
-  // Saved MT states.
-  std::map<int, uint32NDArray> rand_states;
+    // Reset the seed.
+    void do_reset ();
+
+    // Return the current state.
+    uint32NDArray do_state (const std::string& d);
 
-  // Return the current seed.
-  double do_seed (void);
-
-  // Set the seed.
-  void do_seed (double s);
+    // Set the current state/
+    void do_state (const uint32NDArray& s, const std::string& d);
 
-  // Reset the seed.
-  void do_reset ();
+    // Reset the current state/
+    void do_reset (const std::string& d);
 
-  // Return the current state.
-  uint32NDArray do_state (const std::string& d);
+    // Return the current distribution.
+    std::string do_distribution (void);
 
-  // Set the current state/
-  void do_state (const uint32NDArray& s, const std::string& d);
+    // Set the current distribution.  May be either "uniform" (the
+    // default), "normal", "exponential", "poisson", or "gamma".
+    void do_distribution (const std::string& d);
 
-  // Reset the current state/
-  void do_reset (const std::string& d);
+    void do_uniform_distribution (void);
 
-  // Return the current distribution.
-  std::string do_distribution (void);
+    void do_normal_distribution (void);
+
+    void do_exponential_distribution (void);
 
-  // Set the current distribution.  May be either "uniform" (the
-  // default), "normal", "exponential", "poisson", or "gamma".
-  void do_distribution (const std::string& d);
+    void do_poisson_distribution (void);
 
-  void do_uniform_distribution (void);
+    void do_gamma_distribution (void);
 
-  void do_normal_distribution (void);
-
-  void do_exponential_distribution (void);
+    // The following templates only make sense for double and float
+    // types.
 
-  void do_poisson_distribution (void);
+    template <typename T> T uniform (void);
 
-  void do_gamma_distribution (void);
+    template <typename T> T normal (void);
+
+    template <typename T> T exponential (void);
 
-  // Return the next number from the sequence.
-  double do_scalar (double a = 1.);
+    template <typename T> T poisson (T a);
+
+    template <typename T> T gamma (T a);
 
-  // Return the next number from the sequence.
-  float do_float_scalar (float a = 1.);
+    // Return the next number from the sequence.
+    template <typename T> T do_scalar (T a = 1);
 
-  // Return an array of numbers from the sequence.
-  Array<double> do_vector (octave_idx_type n, double a = 1.);
+    // Return an array of numbers from the sequence.
+    template <typename T> Array<T> do_vector (octave_idx_type n, T a = 1);
 
-  // Return an array of numbers from the sequence.
-  Array<float> do_float_vector (octave_idx_type n, float 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.);
 
-  // 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.);
+    // 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.);
 
-  // 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.);
+    // Some helper functions.
+
+    void initialize_ranlib_generators (void);
 
-  // Some helper functions.
+    void initialize_mersenne_twister (void);
 
-  void initialize_ranlib_generators (void);
+    uint32NDArray get_internal_state (void);
 
-  void initialize_mersenne_twister (void);
+    void save_state (void);
 
-  uint32NDArray get_internal_state (void);
+    int get_dist_id (const std::string& d);
 
-  void save_state (void);
+    void set_internal_state (const uint32NDArray& s);
 
-  int get_dist_id (const std::string& d);
+    void switch_to_generator (int dist);
 
-  void set_internal_state (const uint32NDArray& s);
-
-  void switch_to_generator (int dist);
+    void fill (octave_idx_type len, double *v, double a);
 
-  void fill (octave_idx_type len, double *v, double a);
+    void fill (octave_idx_type len, float *v, float a);
+  };
+}
 
-  void fill (octave_idx_type len, float *v, float a);
-};
+#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand' instead")
+typedef octave::rand octave_rand;
 
 #endif
+
+#endif
--- a/liboctave/numeric/randgamma.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randgamma.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -87,110 +87,47 @@
 #include "randgamma.h"
 #include "randmtzig.h"
 
-#define INFINITE lo_ieee_isinf
-#define RUNI oct_randu()
-#define RNOR oct_randn()
-#define REXP oct_rande()
-
-void
-oct_fill_randg (double a, octave_idx_type n, double *r)
+namespace octave
 {
-  octave_idx_type i;
-  /* If a < 1, start by generating gamma (1+a) */
-  const double d = (a < 1. ? 1.+a : a) - 1./3.;
-  const double c = 1./std::sqrt (9.*d);
-
-  /* Handle invalid cases */
-  if (a <= 0 || INFINITE(a))
-    {
-      for (i=0; i < n; i++)
-        r[i] = octave::numeric_limits<double>::NaN ();
-      return;
-    }
+  template <typename T> void rand_gamma (T a, octave_idx_type n, T *r)
+  {
+    octave_idx_type i;
+    /* If a < 1, start by generating gamma (1+a) */
+    const T d = (a < 1. ? 1.+a : a) - 1./3.;
+    const T c = 1./std::sqrt (9.*d);
 
-  for (i=0; i < n; i++)
-    {
-      double x, xsq, v, u;
-    restart:
-      x = RNOR;
-      v = (1+c*x);
-      v *= v*v;
-      if (v <= 0)
-        goto restart; /* rare, so don't bother moving up */
-      u = RUNI;
-      xsq = x*x;
-      if (u >= 1.-0.0331*xsq*xsq && std::log (u) >= 0.5*xsq + d*(1-v+std::log (v)))
-        goto restart;
-      r[i] = d*v;
-    }
-  if (a < 1)
-    {
-      /* Use gamma(a) = gamma(1+a)*U^(1/a) */
-      /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */
-      for (i = 0; i < n; i++)
-        r[i] *= exp (-REXP/a);
-    }
-}
-
-double
-oct_randg (double a)
-{
-  double ret;
-  oct_fill_randg (a,1,&ret);
-  return ret;
-}
+    /* Handle invalid cases */
+    if (a <= 0 || lo_ieee_isinf (a))
+      {
+        for (i=0; i < n; i++)
+          r[i] = numeric_limits<T>::NaN ();
+        return;
+      }
 
-#undef RUNI
-#undef RNOR
-#undef REXP
-#define RUNI oct_float_randu()
-#define RNOR oct_float_randn()
-#define REXP oct_float_rande()
-
-void
-oct_fill_float_randg (float a, octave_idx_type n, float *r)
-{
-  octave_idx_type i;
-  /* If a < 1, start by generating gamma(1+a) */
-  const float d = (a < 1. ? 1.+a : a) - 1./3.;
-  const float c = 1./std::sqrt (9.*d);
-
-  /* Handle invalid cases */
-  if (a <= 0 || INFINITE(a))
-    {
-      for (i=0; i < n; i++)
-        r[i] = octave::numeric_limits<float>::NaN ();
-      return;
-    }
+    for (i=0; i < n; i++)
+      {
+        T x, xsq, v, u;
+      restart:
+        x = rand_normal<T> ();
+        v = (1+c*x);
+        v *= v*v;
+        if (v <= 0)
+          goto restart; /* rare, so don't bother moving up */
+        u = rand_uniform<T> ();
+        xsq = x*x;
+        if (u >= 1.-0.0331*xsq*xsq && std::log (u) >= 0.5*xsq + d*(1-v+std::log (v)))
+          goto restart;
+        r[i] = d*v;
+      }
+    if (a < 1)
+      {
+        /* Use gamma(a) = gamma(1+a)*U^(1/a) */
+        /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */
+        for (i = 0; i < n; i++)
+          r[i] *= exp (-rand_exponential<T> () / a);
+      }
+  }
 
-  for (i=0; i < n; i++)
-    {
-      float x, xsq, v, u;
-    frestart:
-      x = RNOR;
-      v = (1+c*x);
-      v *= v*v;
-      if (v <= 0)
-        goto frestart; /* rare, so don't bother moving up */
-      u = RUNI;
-      xsq = x*x;
-      if (u >= 1.-0.0331*xsq*xsq && std::log (u) >= 0.5*xsq + d*(1-v+std::log (v)))
-        goto frestart;
-      r[i] = d*v;
-    }
-  if (a < 1)
-    {
-      /* Use gamma(a) = gamma(1+a)*U^(1/a) */
-      /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */
-      for (i = 0; i < n; i++)
-        r[i] *= exp (-REXP/a);
-    }
+  template void rand_gamma (double, octave_idx_type, double *);
+  template void rand_gamma (float, octave_idx_type, float *);
 }
-
-float
-oct_float_randg (float a)
-{
-  float ret;
-  oct_fill_float_randg (a,1,&ret);
-  return ret;
-}
--- a/liboctave/numeric/randgamma.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randgamma.h	Thu Dec 20 17:18:56 2018 -0500
@@ -28,11 +28,48 @@
 
 #include "octave-config.h"
 
-extern OCTAVE_API double oct_randg (double a);
-extern OCTAVE_API void oct_fill_randg (double a, octave_idx_type n, double *p);
+namespace octave
+{
+  template <typename T>
+  void
+  rand_gamma (T a, octave_idx_type n, T *p);
+
+  template <typename T>
+  T
+  rand_gamma (T a)
+  {
+    T retval;
+    rand_gamma (a, 1, &retval);
+    return retval;
+  }
+}
 
-extern OCTAVE_API float oct_float_randg (float a);
-extern OCTAVE_API void oct_fill_float_randg (float a, octave_idx_type n,
-                                             float *p);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_gamma<double>' instead")
+inline double
+oct_randg (double a)
+{
+  return octave::rand_gamma (a);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_gamma<float>' instead")
+inline float
+oct_float_randg (float a)
+{
+  return octave::rand_gamma (a);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_gamma<double>' instead")
+inline void
+oct_fill_randg (double a, octave_idx_type n, double *p)
+{
+  octave::rand_gamma (a, n, p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_gamma<float>' instead")
+inline void
+oct_fill_float_randg (float a, octave_idx_type n, float *p)
+{
+  octave::rand_gamma (a, n, p);
+}
 
 #endif
--- a/liboctave/numeric/randmtzig.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randmtzig.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -112,16 +112,26 @@
 
    === Usage instructions ===
    Before using any of the generators, initialize the state with one of
-   oct_init_by_int, oct_init_by_array or oct_init_by_entropy.
+   the init_mersenne_twister functions.
 
    All generators share the same state vector.
 
    === Mersenne Twister ===
-   void oct_init_by_int (uint32_t s)           32-bit initial state
-   void oct_init_by_array (uint32_t k[],int m) m*32-bit initial state
-   void oct_init_by_entropy (void)             random initial state
-   void oct_get_state (uint32_t save[MT_N+1])  saves state in array
-   void oct_set_state (uint32_t save[MT_N+1])  restores state from array
+   random initial state:
+   void init_mersenne_twister (void)
+
+   // 32-bit initial state:
+   void init_mersenne_twister (uint32_t s)
+
+   // m*32-bit initial state:
+   void init_mersenne_twister (uint32_t k[],int m)
+
+   // saves state in array:
+   void get_mersenne_twister_state (uint32_t save[MT_N+1])
+
+   // restores state from array
+   void set_mersenne_twister_state (uint32_t save[MT_N+1])
+
    static uint32_t randmt (void)               returns 32-bit unsigned int
 
    === inline generators ===
@@ -131,22 +141,14 @@
    static float randu32 (void)      returns 32-bit uniform in (0,1)
    static double randu53 (void)     returns 53-bit uniform in (0,1)
 
-   double oct_randu (void)       returns M-bit uniform in (0,1)
-   double oct_randn (void)       returns M-bit standard normal
-   double oct_rande (void)       returns N-bit standard exponential
-
-   float oct_float_randu (void)       returns M-bit uniform in (0,1)
-   float oct_float_randn (void)       returns M-bit standard normal
-   float oct_float_rande (void)       returns N-bit standard exponential
+   double rand_uniform (void)       returns M-bit uniform in (0,1)
+   double rand_normal (void)        returns M-bit standard normal
+   double rand_exponential (void)   returns N-bit standard exponential
 
    === Array generators ===
-   void oct_fill_randu (octave_idx_type, double [])
-   void oct_fill_randn (octave_idx_type, double [])
-   void oct_fill_rande (octave_idx_type, double [])
-
-   void oct_fill_float_randu (octave_idx_type, float [])
-   void oct_fill_float_randn (octave_idx_type, float [])
-   void oct_fill_float_rande (octave_idx_type, float [])
+   void rand_uniform (octave_idx_type, double [])
+   void rand_normal (octave_idx_type, double [])
+   void rand_exponential (octave_idx_type, double [])
 */
 
 #if defined (HAVE_CONFIG_H)
@@ -170,7 +172,9 @@
 #  endif
 #endif
 
-/* ===== Mersenne Twister 32-bit generator ===== */
+namespace octave
+{
+  /* ===== Mersenne Twister 32-bit generator ===== */
 
 #define MT_M 397
 #define MATRIX_A 0x9908b0dfUL   /* constant vector a */
@@ -179,240 +183,231 @@
 #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
 #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
 
-static uint32_t *next;
-static uint32_t state[MT_N]; /* the array for the state vector  */
-static int left = 1;
-static int initf = 0;
-static int initt = 1;
-static int inittf = 1;
+  static uint32_t *next;
+  static uint32_t state[MT_N]; /* the array for the state vector  */
+  static int left = 1;
+  static int initf = 0;
+  static int initt = 1;
+  static int inittf = 1;
 
-/* initializes state[MT_N] with a seed */
-void
-oct_init_by_int (const uint32_t s)
-{
-  int j;
-  state[0] = s & 0xffffffffUL;
-  for (j = 1; j < MT_N; j++)
-    {
-      state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
-      /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
-      /* In the previous versions, MSBs of the seed affect   */
-      /* only MSBs of the array state[].                        */
-      /* 2002/01/09 modified by Makoto Matsumoto             */
-      state[j] &= 0xffffffffUL;  /* for >32 bit machines */
-    }
-  left = 1;
-  initf = 1;
-}
+  /* initializes state[MT_N] with a seed */
+  void init_mersenne_twister (const uint32_t s)
+  {
+    int j;
+    state[0] = s & 0xffffffffUL;
+    for (j = 1; j < MT_N; j++)
+      {
+        state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
+        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+        /* In the previous versions, MSBs of the seed affect   */
+        /* only MSBs of the array state[].                        */
+        /* 2002/01/09 modified by Makoto Matsumoto             */
+        state[j] &= 0xffffffffUL;  /* for >32 bit machines */
+      }
+    left = 1;
+    initf = 1;
+  }
 
-/* initialize by an array with array-length */
-/* init_key is the array for initializing keys */
-/* key_length is its length */
-void
-oct_init_by_array (const uint32_t *init_key, const int key_length)
-{
-  int i, j, k;
-  oct_init_by_int (19650218UL);
-  i = 1;
-  j = 0;
-  k = (MT_N > key_length ? MT_N : key_length);
-  for (; k; k--)
-    {
-      state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525UL))
-                 + init_key[j] + j; /* non linear */
-      state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
-      i++;
-      j++;
-      if (i >= MT_N)
-        {
-          state[0] = state[MT_N-1];
-          i = 1;
-        }
-      if (j >= key_length)
-        j = 0;
-    }
-  for (k = MT_N - 1; k; k--)
-    {
-      state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL))
-                 - i; /* non linear */
-      state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
-      i++;
-      if (i >= MT_N)
-        {
-          state[0] = state[MT_N-1];
-          i = 1;
-        }
-    }
+  /* initialize by an array with array-length */
+  /* init_key is the array for initializing keys */
+  /* key_length is its length */
+  void init_mersenne_twister (const uint32_t *init_key, const int key_length)
+  {
+    int i, j, k;
+    init_mersenne_twister (19650218UL);
+    i = 1;
+    j = 0;
+    k = (MT_N > key_length ? MT_N : key_length);
+    for (; k; k--)
+      {
+        state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525UL))
+          + init_key[j] + j; /* non linear */
+        state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++;
+        j++;
+        if (i >= MT_N)
+          {
+            state[0] = state[MT_N-1];
+            i = 1;
+          }
+        if (j >= key_length)
+          j = 0;
+      }
+    for (k = MT_N - 1; k; k--)
+      {
+        state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL))
+          - i; /* non linear */
+        state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++;
+        if (i >= MT_N)
+          {
+            state[0] = state[MT_N-1];
+            i = 1;
+          }
+      }
 
-  state[0] = 0x80000000UL; /* MSB is 1; assuring nonzero initial array */
-  left = 1;
-  initf = 1;
-}
+    state[0] = 0x80000000UL; /* MSB is 1; assuring nonzero initial array */
+    left = 1;
+    initf = 1;
+  }
 
-void
-oct_init_by_entropy (void)
-{
-  uint32_t entropy[MT_N];
-  int n = 0;
+  void init_mersenne_twister (void)
+  {
+    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);
-    }
+    /* 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 */
+    /* If there isn't enough entropy, gather some from various sources */
 
-  octave::sys::time now;
+    octave::sys::time now;
 
-  if (n < MT_N)
-    entropy[n++] = now.unix_time (); /* Current time in seconds */
+    if (n < MT_N)
+      entropy[n++] = now.unix_time (); /* Current time in seconds */
 
-  if (n < MT_N)
-    entropy[n++] = clock ();    /* CPU time used (usec) */
+    if (n < MT_N)
+      entropy[n++] = clock ();    /* CPU time used (usec) */
 
-  if (n < MT_N)
-    entropy[n++] = now.usec ();   /* Fractional part of current time */
+    if (n < MT_N)
+      entropy[n++] = now.usec ();   /* Fractional part of current time */
 
-  /* Send all the entropy into the initial state vector */
-  oct_init_by_array (entropy,n);
-}
+    /* Send all the entropy into the initial state vector */
+    init_mersenne_twister (entropy,n);
+  }
 
-void
-oct_set_state (const uint32_t *save)
-{
-  std::copy_n (save, MT_N, state);
-  left = save[MT_N];
-  next = state + (MT_N - left + 1);
-}
+  void set_mersenne_twister_state (const uint32_t *save)
+  {
+    std::copy_n (save, MT_N, state);
+    left = save[MT_N];
+    next = state + (MT_N - left + 1);
+  }
 
-void
-oct_get_state (uint32_t *save)
-{
-  std::copy_n (state, MT_N, save);
-  save[MT_N] = left;
-}
+  void get_mersenne_twister_state (uint32_t *save)
+  {
+    std::copy_n (state, MT_N, save);
+    save[MT_N] = left;
+  }
 
-static void
-next_state (void)
-{
-  uint32_t *p = state;
-  int j;
+  static void next_state (void)
+  {
+    uint32_t *p = state;
+    int j;
 
-  /* if init_by_int() has not been called, */
-  /* a default initial seed is used         */
-  /* if (initf==0) init_by_int(5489UL); */
-  /* Or better yet, a random seed! */
-  if (initf == 0)
-    oct_init_by_entropy ();
+    /* if init_by_int() has not been called, */
+    /* a default initial seed is used         */
+    /* if (initf==0) init_by_int(5489UL); */
+    /* Or better yet, a random seed! */
+    if (initf == 0)
+      init_mersenne_twister ();
 
-  left = MT_N;
-  next = state;
+    left = MT_N;
+    next = state;
 
-  for (j = MT_N - MT_M + 1; --j; p++)
-    *p = p[MT_M] ^ TWIST(p[0], p[1]);
+    for (j = MT_N - MT_M + 1; --j; p++)
+      *p = p[MT_M] ^ TWIST(p[0], p[1]);
 
-  for (j = MT_M; --j; p++)
-    *p = p[MT_M-MT_N] ^ TWIST(p[0], p[1]);
-
-  *p = p[MT_M-MT_N] ^ TWIST(p[0], state[0]);
-}
+    for (j = MT_M; --j; p++)
+      *p = p[MT_M-MT_N] ^ TWIST(p[0], p[1]);
 
-/* generates a random number on [0,0xffffffff]-interval */
-static uint32_t
-randmt (void)
-{
-  uint32_t y;
+    *p = p[MT_M-MT_N] ^ TWIST(p[0], state[0]);
+  }
+
+  /* generates a random number on [0,0xffffffff]-interval */
+  static uint32_t randmt (void)
+  {
+    uint32_t y;
 
-  if (--left == 0)
-    next_state ();
-  y = *next++;
+    if (--left == 0)
+      next_state ();
+    y = *next++;
 
-  /* Tempering */
-  y ^= (y >> 11);
-  y ^= (y << 7) & 0x9d2c5680UL;
-  y ^= (y << 15) & 0xefc60000UL;
-  return (y ^ (y >> 18));
-}
+    /* Tempering */
+    y ^= (y >> 11);
+    y ^= (y << 7) & 0x9d2c5680UL;
+    y ^= (y << 15) & 0xefc60000UL;
+    return (y ^ (y >> 18));
+  }
 
-/* ===== Uniform generators ===== */
+  /* ===== Uniform generators ===== */
 
-/* Select which 32 bit generator to use */
+  /* Select which 32 bit generator to use */
 #define randi32 randmt
 
-static uint64_t
-randi53 (void)
-{
-  const uint32_t lo = randi32 ();
-  const uint32_t hi = randi32 () & 0x1FFFFF;
+  static uint64_t randi53 (void)
+  {
+    const uint32_t lo = randi32 ();
+    const uint32_t hi = randi32 () & 0x1FFFFF;
 #if defined (HAVE_X86_32)
-  uint64_t u;
-  uint32_t *p = (uint32_t *)&u;
-  p[0] = lo;
-  p[1] = hi;
-  return u;
+    uint64_t u;
+    uint32_t *p = (uint32_t *)&u;
+    p[0] = lo;
+    p[1] = hi;
+    return u;
 #else
-  return ((static_cast<uint64_t> (hi) << 32) | lo);
+    return ((static_cast<uint64_t> (hi) << 32) | lo);
 #endif
-}
+  }
 
-static uint64_t
-randi54 (void)
-{
-  const uint32_t lo = randi32 ();
-  const uint32_t hi = randi32 () & 0x3FFFFF;
+  static uint64_t randi54 (void)
+  {
+    const uint32_t lo = randi32 ();
+    const uint32_t hi = randi32 () & 0x3FFFFF;
 #if defined (HAVE_X86_32)
-  uint64_t u;
-  uint32_t *p = static_cast<uint32_t *> (&u);
-  p[0] = lo;
-  p[1] = hi;
-  return u;
+    uint64_t u;
+    uint32_t *p = static_cast<uint32_t *> (&u);
+    p[0] = lo;
+    p[1] = hi;
+    return u;
 #else
-  return ((static_cast<uint64_t> (hi) << 32) | lo);
+    return ((static_cast<uint64_t> (hi) << 32) | lo);
 #endif
-}
+  }
 
-/* generates a random number on (0,1)-real-interval */
-static float
-randu32 (void)
-{
-  return (static_cast<float> (randi32 ()) + 0.5) * (1.0/4294967296.0);
-  /* divided by 2^32 */
-}
+  /* generates a random number on (0,1)-real-interval */
+  static float randu32 (void)
+  {
+    return (static_cast<float> (randi32 ()) + 0.5) * (1.0/4294967296.0);
+    /* divided by 2^32 */
+  }
+
+  /* generates a random number on (0,1) with 53-bit resolution */
+  static double randu53 (void)
+  {
+    const uint32_t a = randi32 () >> 5;
+    const uint32_t b = randi32 () >> 6;
+    return (a*67108864.0+b+0.4) * (1.0/9007199254740992.0);
+  }
 
-/* generates a random number on (0,1) with 53-bit resolution */
-static double
-randu53 (void)
-{
-  const uint32_t a = randi32 () >> 5;
-  const uint32_t b = randi32 () >> 6;
-  return (a*67108864.0+b+0.4) * (1.0/9007199254740992.0);
-}
+  /* Determine mantissa for uniform doubles */
+  template <>
+  double
+  rand_uniform<double> (void)
+  {
+    return randu53 ();
+  }
 
-/* Determine mantissa for uniform doubles */
-double
-oct_randu (void)
-{
-  return randu53 ();
-}
+  /* Determine mantissa for uniform floats */
+  template <>
+  float
+  rand_uniform<float> (void)
+  {
+    return randu32 ();
+  }
 
-/* Determine mantissa for uniform floats */
-float
-oct_float_randu (void)
-{
-  return randu32 ();
-}
-
-/* ===== Ziggurat normal and exponential generators ===== */
+  /* ===== Ziggurat normal and exponential generators ===== */
 
 #define ZIGGURAT_TABLE_SIZE 256
 
@@ -431,219 +426,232 @@
 #define NRANDI randi54() /* 53 bits for mantissa + 1 bit sign */
 #define RANDU randu53()
 
-static ZIGINT ki[ZIGGURAT_TABLE_SIZE];
-static double wi[ZIGGURAT_TABLE_SIZE], fi[ZIGGURAT_TABLE_SIZE];
-static ZIGINT ke[ZIGGURAT_TABLE_SIZE];
-static double we[ZIGGURAT_TABLE_SIZE], fe[ZIGGURAT_TABLE_SIZE];
+  static ZIGINT ki[ZIGGURAT_TABLE_SIZE];
+  static double wi[ZIGGURAT_TABLE_SIZE], fi[ZIGGURAT_TABLE_SIZE];
+  static ZIGINT ke[ZIGGURAT_TABLE_SIZE];
+  static double we[ZIGGURAT_TABLE_SIZE], fe[ZIGGURAT_TABLE_SIZE];
+
+  /*
+    This code is based on the paper Marsaglia and Tsang, "The ziggurat method
+    for generating random variables", Journ. Statistical Software. Code was
+    presented in this paper for a Ziggurat of 127 levels and using a 32 bit
+    integer random number generator. This version of the code, uses the
+    Mersenne Twister as the integer generator and uses 256 levels in the
+    Ziggurat. This has several advantages.
 
-/*
-This code is based on the paper Marsaglia and Tsang, "The ziggurat method
-for generating random variables", Journ. Statistical Software. Code was
-presented in this paper for a Ziggurat of 127 levels and using a 32 bit
-integer random number generator. This version of the code, uses the
-Mersenne Twister as the integer generator and uses 256 levels in the
-Ziggurat. This has several advantages.
+    1) As Marsaglia and Tsang themselves states, the more levels the few
+    times the expensive tail algorithm must be called
+    2) The cycle time of the generator is determined by the integer
+    generator, thus the use of a Mersenne Twister for the core random
+    generator makes this cycle extremely long.
+    3) The license on the original code was unclear, thus rewriting the code
+    from the article means we are free of copyright issues.
+    4) Compile flag for full 53-bit random mantissa.
 
-  1) As Marsaglia and Tsang themselves states, the more levels the few
-     times the expensive tail algorithm must be called
-  2) The cycle time of the generator is determined by the integer
-     generator, thus the use of a Mersenne Twister for the core random
-     generator makes this cycle extremely long.
-  3) The license on the original code was unclear, thus rewriting the code
-     from the article means we are free of copyright issues.
-  4) Compile flag for full 53-bit random mantissa.
+    It should be stated that the authors made my life easier, by the fact that
+    the algorithm developed in the text of the article is for a 256 level
+    ziggurat, even if the code itself isn't...
 
-It should be stated that the authors made my life easier, by the fact that
-the algorithm developed in the text of the article is for a 256 level
-ziggurat, even if the code itself isn't...
-
-One modification to the algorithm developed in the article, is that it is
-assumed that 0 <= x < Inf, and "unsigned long"s are used, thus resulting in
-terms like 2^32 in the code. As the normal distribution is defined between
--Inf < x < Inf, we effectively only have 31 bit integers plus a sign. Thus
-in Marsaglia and Tsang, terms like 2^32 become 2^31. We use NMANTISSA for
-this term.  The exponential distribution is one sided so we use the
-full 32 bits.  We use EMANTISSA for this term.
+    One modification to the algorithm developed in the article, is that it is
+    assumed that 0 <= x < Inf, and "unsigned long"s are used, thus resulting in
+    terms like 2^32 in the code. As the normal distribution is defined between
+    -Inf < x < Inf, we effectively only have 31 bit integers plus a sign. Thus
+    in Marsaglia and Tsang, terms like 2^32 become 2^31. We use NMANTISSA for
+    this term.  The exponential distribution is one sided so we use the
+    full 32 bits.  We use EMANTISSA for this term.
 
-It appears that I'm slightly slower than the code in the article, this
-is partially due to a better generator of random integers than they
-use. But might also be that the case of rapid return was optimized by
-inlining the relevant code with a #define. As the basic Mersenne
-Twister is only 25% faster than this code I suspect that the main
-reason is just the use of the Mersenne Twister and not the inlining,
-so I'm not going to try and optimize further.
-*/
+    It appears that I'm slightly slower than the code in the article, this
+    is partially due to a better generator of random integers than they
+    use. But might also be that the case of rapid return was optimized by
+    inlining the relevant code with a #define. As the basic Mersenne
+    Twister is only 25% faster than this code I suspect that the main
+    reason is just the use of the Mersenne Twister and not the inlining,
+    so I'm not going to try and optimize further.
+  */
 
-static void
-create_ziggurat_tables (void)
-{
-  int i;
-  double x, x1;
+  void create_ziggurat_tables (void)
+  {
+    int i;
+    double x, x1;
+
+    /* Ziggurat tables for the normal distribution */
+    x1 = ZIGGURAT_NOR_R;
+    wi[255] = x1 / NMANTISSA;
+    fi[255] = exp (-0.5 * x1 * x1);
 
-  /* Ziggurat tables for the normal distribution */
-  x1 = ZIGGURAT_NOR_R;
-  wi[255] = x1 / NMANTISSA;
-  fi[255] = exp (-0.5 * x1 * x1);
-
-  /* Index zero is special for tail strip, where Marsaglia and Tsang
-   * defines this as
-   * k_0 = 2^31 * r * f(r) / v, w_0 = 0.5^31 * v / f(r), f_0 = 1,
-   * where v is the area of each strip of the ziggurat.
-   */
-  ki[0] = static_cast<ZIGINT> (x1 * fi[255] / NOR_SECTION_AREA * NMANTISSA);
-  wi[0] = NOR_SECTION_AREA / fi[255] / NMANTISSA;
-  fi[0] = 1.;
+    /* Index zero is special for tail strip, where Marsaglia and Tsang
+     * defines this as
+     * k_0 = 2^31 * r * f(r) / v, w_0 = 0.5^31 * v / f(r), f_0 = 1,
+     * where v is the area of each strip of the ziggurat.
+     */
+    ki[0] = static_cast<ZIGINT> (x1 * fi[255] / NOR_SECTION_AREA * NMANTISSA);
+    wi[0] = NOR_SECTION_AREA / fi[255] / NMANTISSA;
+    fi[0] = 1.;
 
-  for (i = 254; i > 0; i--)
-    {
-      /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
-       * need inverse operator of y = exp(-0.5*x*x) -> x = sqrt(-2*ln(y))
-       */
-      x = std::sqrt (-2. * std::log (NOR_SECTION_AREA / x1 + fi[i+1]));
-      ki[i+1] = static_cast<ZIGINT> (x / x1 * NMANTISSA);
-      wi[i] = x / NMANTISSA;
-      fi[i] = exp (-0.5 * x * x);
-      x1 = x;
-    }
+    for (i = 254; i > 0; i--)
+      {
+        /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
+         * need inverse operator of y = exp(-0.5*x*x) -> x = sqrt(-2*ln(y))
+         */
+        x = std::sqrt (-2. * std::log (NOR_SECTION_AREA / x1 + fi[i+1]));
+        ki[i+1] = static_cast<ZIGINT> (x / x1 * NMANTISSA);
+        wi[i] = x / NMANTISSA;
+        fi[i] = exp (-0.5 * x * x);
+        x1 = x;
+      }
 
-  ki[1] = 0;
+    ki[1] = 0;
 
-  /* Zigurrat tables for the exponential distribution */
-  x1 = ZIGGURAT_EXP_R;
-  we[255] = x1 / EMANTISSA;
-  fe[255] = exp (-x1);
+    /* Zigurrat tables for the exponential distribution */
+    x1 = ZIGGURAT_EXP_R;
+    we[255] = x1 / EMANTISSA;
+    fe[255] = exp (-x1);
 
-  /* Index zero is special for tail strip, where Marsaglia and Tsang
-   * defines this as
-   * k_0 = 2^32 * r * f(r) / v, w_0 = 0.5^32 * v / f(r), f_0 = 1,
-   * where v is the area of each strip of the ziggurat.
-   */
-  ke[0] = static_cast<ZIGINT> (x1 * fe[255] / EXP_SECTION_AREA * EMANTISSA);
-  we[0] = EXP_SECTION_AREA / fe[255] / EMANTISSA;
-  fe[0] = 1.;
+    /* Index zero is special for tail strip, where Marsaglia and Tsang
+     * defines this as
+     * k_0 = 2^32 * r * f(r) / v, w_0 = 0.5^32 * v / f(r), f_0 = 1,
+     * where v is the area of each strip of the ziggurat.
+     */
+    ke[0] = static_cast<ZIGINT> (x1 * fe[255] / EXP_SECTION_AREA * EMANTISSA);
+    we[0] = EXP_SECTION_AREA / fe[255] / EMANTISSA;
+    fe[0] = 1.;
 
-  for (i = 254; i > 0; i--)
-    {
-      /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
-       * need inverse operator of y = exp(-x) -> x = -ln(y)
-       */
-      x = - std::log (EXP_SECTION_AREA / x1 + fe[i+1]);
-      ke[i+1] = static_cast<ZIGINT> (x / x1 * EMANTISSA);
-      we[i] = x / EMANTISSA;
-      fe[i] = exp (-x);
-      x1 = x;
-    }
-  ke[1] = 0;
+    for (i = 254; i > 0; i--)
+      {
+        /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
+         * need inverse operator of y = exp(-x) -> x = -ln(y)
+         */
+        x = - std::log (EXP_SECTION_AREA / x1 + fe[i+1]);
+        ke[i+1] = static_cast<ZIGINT> (x / x1 * EMANTISSA);
+        we[i] = x / EMANTISSA;
+        fe[i] = exp (-x);
+        x1 = x;
+      }
+    ke[1] = 0;
 
-  initt = 0;
-}
+    initt = 0;
+  }
 
-/*
- * Here is the guts of the algorithm. As Marsaglia and Tsang state the
- * algorithm in their paper
- *
- * 1) Calculate a random signed integer j and let i be the index
- *     provided by the rightmost 8-bits of j
- * 2) Set x = j * w_i. If j < k_i return x
- * 3) If i = 0, then return x from the tail
- * 4) If [f(x_{i-1}) - f(x_i)] * U < f(x) - f(x_i), return x
- * 5) goto step 1
- *
- * Where f is the functional form of the distribution, which for a normal
- * distribution is exp(-0.5*x*x)
- */
+  /*
+   * Here is the guts of the algorithm. As Marsaglia and Tsang state the
+   * algorithm in their paper
+   *
+   * 1) Calculate a random signed integer j and let i be the index
+   *     provided by the rightmost 8-bits of j
+   * 2) Set x = j * w_i. If j < k_i return x
+   * 3) If i = 0, then return x from the tail
+   * 4) If [f(x_{i-1}) - f(x_i)] * U < f(x) - f(x_i), return x
+   * 5) goto step 1
+   *
+   * Where f is the functional form of the distribution, which for a normal
+   * distribution is exp(-0.5*x*x)
+   */
 
-double
-oct_randn (void)
-{
-  if (initt)
-    create_ziggurat_tables ();
+
+  template <> double rand_normal<double> (void)
+  {
+    if (initt)
+      create_ziggurat_tables ();
 
-  while (1)
-    {
-      /* The following code is specialized for 32-bit mantissa.
-       * Compared to the arbitrary mantissa code, there is a performance
-       * gain for 32-bits:  PPC: 2%, MIPS: 8%, x86: 40%
-       * There is a bigger performance gain compared to using a full
-       * 53-bit mantissa:  PPC: 60%, MIPS: 65%, x86: 240%
-       * Of course, different compilers and operating systems may
-       * have something to do with this.
-       */
+    while (1)
+      {
+        /* The following code is specialized for 32-bit mantissa.
+         * Compared to the arbitrary mantissa code, there is a performance
+         * gain for 32-bits:  PPC: 2%, MIPS: 8%, x86: 40%
+         * There is a bigger performance gain compared to using a full
+         * 53-bit mantissa:  PPC: 60%, MIPS: 65%, x86: 240%
+         * Of course, different compilers and operating systems may
+         * have something to do with this.
+         */
 # if defined (HAVE_X86_32)
-      /* 53-bit mantissa, 1-bit sign, x86 32-bit architecture */
-      double x;
-      int si,idx;
-      uint32_t lo, hi;
-      int64_t rabs;
-      uint32_t *p = (uint32_t *)&rabs;
-      lo = randi32 ();
-      idx = lo & 0xFF;
-      hi = randi32 ();
-      si = hi & UMASK;
-      p[0] = lo;
-      p[1] = hi & 0x1FFFFF;
-      x = ( si ? -rabs : rabs ) * wi[idx];
+        /* 53-bit mantissa, 1-bit sign, x86 32-bit architecture */
+        double x;
+        int si,idx;
+        uint32_t lo, hi;
+        int64_t rabs;
+        uint32_t *p = (uint32_t *)&rabs;
+        lo = randi32 ();
+        idx = lo & 0xFF;
+        hi = randi32 ();
+        si = hi & UMASK;
+        p[0] = lo;
+        p[1] = hi & 0x1FFFFF;
+        x = ( si ? -rabs : rabs ) * wi[idx];
 # else
-      /* arbitrary mantissa (selected by NRANDI, with 1 bit for sign) */
-      const uint64_t r = NRANDI;
-      const int64_t rabs = r >> 1;
-      const int idx = static_cast<int> (rabs & 0xFF);
-      const double x = ( (r & 1) ? -rabs : rabs) * wi[idx];
+        /* arbitrary mantissa (selected by NRANDI, with 1 bit for sign) */
+        const uint64_t r = NRANDI;
+        const int64_t rabs = r >> 1;
+        const int idx = static_cast<int> (rabs & 0xFF);
+        const double x = ( (r & 1) ? -rabs : rabs) * wi[idx];
 # endif
-      if (rabs < static_cast<int64_t> (ki[idx]))
-        return x;        /* 99.3% of the time we return here 1st try */
-      else if (idx == 0)
-        {
-          /* As stated in Marsaglia and Tsang
-           *
-           * For the normal tail, the method of Marsaglia[5] provides:
-           * generate x = -ln(U_1)/r, y = -ln(U_2), until y+y > x*x,
-           * then return r+x. Except that r+x is always in the positive
-           * tail!!!! Any thing random might be used to determine the
-           * sign, but as we already have r we might as well use it
-           *
-           * [PAK] but not the bottom 8 bits, since they are all 0 here!
-           */
-          double xx, yy;
-          do
-            {
-              xx = - ZIGGURAT_NOR_INV_R * std::log (RANDU);
-              yy = - std::log (RANDU);
-            }
-          while ( yy+yy <= xx*xx);
-          return ((rabs & 0x100) ? -ZIGGURAT_NOR_R-xx : ZIGGURAT_NOR_R+xx);
-        }
-      else if ((fi[idx-1] - fi[idx]) * RANDU + fi[idx] < exp (-0.5*x*x))
-        return x;
-    }
-}
+        if (rabs < static_cast<int64_t> (ki[idx]))
+          return x;        /* 99.3% of the time we return here 1st try */
+        else if (idx == 0)
+          {
+            /* As stated in Marsaglia and Tsang
+             *
+             * For the normal tail, the method of Marsaglia[5] provides:
+             * generate x = -ln(U_1)/r, y = -ln(U_2), until y+y > x*x,
+             * then return r+x. Except that r+x is always in the positive
+             * tail!!!! Any thing random might be used to determine the
+             * sign, but as we already have r we might as well use it
+             *
+             * [PAK] but not the bottom 8 bits, since they are all 0 here!
+             */
+            double xx, yy;
+            do
+              {
+                xx = - ZIGGURAT_NOR_INV_R * std::log (RANDU);
+                yy = - std::log (RANDU);
+              }
+            while ( yy+yy <= xx*xx);
+            return ((rabs & 0x100) ? -ZIGGURAT_NOR_R-xx : ZIGGURAT_NOR_R+xx);
+          }
+        else if ((fi[idx-1] - fi[idx]) * RANDU + fi[idx] < exp (-0.5*x*x))
+          return x;
+      }
+  }
+
+  template <> double rand_exponential<double> (void)
+  {
+    if (initt)
+      create_ziggurat_tables ();
 
-double
-oct_rande (void)
-{
-  if (initt)
-    create_ziggurat_tables ();
+    while (1)
+      {
+        ZIGINT ri = ERANDI;
+        const int idx = static_cast<int> (ri & 0xFF);
+        const double x = ri * we[idx];
+        if (ri < ke[idx])
+          return x;               /* 98.9% of the time we return here 1st try */
+        else if (idx == 0)
+          {
+            /* As stated in Marsaglia and Tsang
+             *
+             * For the exponential tail, the method of Marsaglia[5] provides:
+             * x = r - ln(U);
+             */
+            return ZIGGURAT_EXP_R - std::log (RANDU);
+          }
+        else if ((fe[idx-1] - fe[idx]) * RANDU + fe[idx] < exp (-x))
+          return x;
+      }
+  }
 
-  while (1)
-    {
-      ZIGINT ri = ERANDI;
-      const int idx = static_cast<int> (ri & 0xFF);
-      const double x = ri * we[idx];
-      if (ri < ke[idx])
-        return x;               /* 98.9% of the time we return here 1st try */
-      else if (idx == 0)
-        {
-          /* As stated in Marsaglia and Tsang
-           *
-           * For the exponential tail, the method of Marsaglia[5] provides:
-           * x = r - ln(U);
-           */
-          return ZIGGURAT_EXP_R - std::log (RANDU);
-        }
-      else if ((fe[idx-1] - fe[idx]) * RANDU + fe[idx] < exp (-x))
-        return x;
-    }
-}
+  template <> 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)
+  {
+    std::generate_n (p, n, [](void) { return rand_normal<double> (); });
+  }
+
+  template <> void rand_exponential (octave_idx_type n, double *p)
+  {
+    std::generate_n (p, n, [](void) { return rand_exponential<double> (); });
+  }
 
 #undef ZIGINT
 #undef EMANTISSA
@@ -659,191 +667,168 @@
 #define NRANDI randi32() /* 31 bits for mantissa + 1 bit sign */
 #define RANDU randu32()
 
-static ZIGINT fki[ZIGGURAT_TABLE_SIZE];
-static float fwi[ZIGGURAT_TABLE_SIZE], ffi[ZIGGURAT_TABLE_SIZE];
-static ZIGINT fke[ZIGGURAT_TABLE_SIZE];
-static float fwe[ZIGGURAT_TABLE_SIZE], ffe[ZIGGURAT_TABLE_SIZE];
+  static ZIGINT fki[ZIGGURAT_TABLE_SIZE];
+  static float fwi[ZIGGURAT_TABLE_SIZE], ffi[ZIGGURAT_TABLE_SIZE];
+  static ZIGINT fke[ZIGGURAT_TABLE_SIZE];
+  static float fwe[ZIGGURAT_TABLE_SIZE], ffe[ZIGGURAT_TABLE_SIZE];
+
+  static void create_ziggurat_float_tables (void)
+  {
+    int i;
+    float x, x1;
 
-static void
-create_ziggurat_float_tables (void)
-{
-  int i;
-  float x, x1;
+    /* Ziggurat tables for the normal distribution */
+    x1 = ZIGGURAT_NOR_R;
+    fwi[255] = x1 / NMANTISSA;
+    ffi[255] = exp (-0.5 * x1 * x1);
+
+    /* Index zero is special for tail strip, where Marsaglia and Tsang
+     * defines this as
+     * k_0 = 2^31 * r * f(r) / v, w_0 = 0.5^31 * v / f(r), f_0 = 1,
+     * where v is the area of each strip of the ziggurat.
+     */
+    fki[0] = static_cast<ZIGINT> (x1 * ffi[255] / NOR_SECTION_AREA * NMANTISSA);
+    fwi[0] = NOR_SECTION_AREA / ffi[255] / NMANTISSA;
+    ffi[0] = 1.;
 
-  /* Ziggurat tables for the normal distribution */
-  x1 = ZIGGURAT_NOR_R;
-  fwi[255] = x1 / NMANTISSA;
-  ffi[255] = exp (-0.5 * x1 * x1);
+    for (i = 254; i > 0; i--)
+      {
+        /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
+         * need inverse operator of y = exp(-0.5*x*x) -> x = sqrt(-2*ln(y))
+         */
+        x = std::sqrt (-2. * std::log (NOR_SECTION_AREA / x1 + ffi[i+1]));
+        fki[i+1] = static_cast<ZIGINT> (x / x1 * NMANTISSA);
+        fwi[i] = x / NMANTISSA;
+        ffi[i] = exp (-0.5 * x * x);
+        x1 = x;
+      }
+
+    fki[1] = 0;
+
+    /* Zigurrat tables for the exponential distribution */
+    x1 = ZIGGURAT_EXP_R;
+    fwe[255] = x1 / EMANTISSA;
+    ffe[255] = exp (-x1);
 
-  /* Index zero is special for tail strip, where Marsaglia and Tsang
-   * defines this as
-   * k_0 = 2^31 * r * f(r) / v, w_0 = 0.5^31 * v / f(r), f_0 = 1,
-   * where v is the area of each strip of the ziggurat.
-   */
-  fki[0] = static_cast<ZIGINT> (x1 * ffi[255] / NOR_SECTION_AREA * NMANTISSA);
-  fwi[0] = NOR_SECTION_AREA / ffi[255] / NMANTISSA;
-  ffi[0] = 1.;
+    /* Index zero is special for tail strip, where Marsaglia and Tsang
+     * defines this as
+     * k_0 = 2^32 * r * f(r) / v, w_0 = 0.5^32 * v / f(r), f_0 = 1,
+     * where v is the area of each strip of the ziggurat.
+     */
+    fke[0] = static_cast<ZIGINT> (x1 * ffe[255] / EXP_SECTION_AREA * EMANTISSA);
+    fwe[0] = EXP_SECTION_AREA / ffe[255] / EMANTISSA;
+    ffe[0] = 1.;
+
+    for (i = 254; i > 0; i--)
+      {
+        /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
+         * need inverse operator of y = exp(-x) -> x = -ln(y)
+         */
+        x = - std::log (EXP_SECTION_AREA / x1 + ffe[i+1]);
+        fke[i+1] = static_cast<ZIGINT> (x / x1 * EMANTISSA);
+        fwe[i] = x / EMANTISSA;
+        ffe[i] = exp (-x);
+        x1 = x;
+      }
+    fke[1] = 0;
+
+    inittf = 0;
+  }
 
-  for (i = 254; i > 0; i--)
-    {
-      /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
-       * need inverse operator of y = exp(-0.5*x*x) -> x = sqrt(-2*ln(y))
-       */
-      x = std::sqrt (-2. * std::log (NOR_SECTION_AREA / x1 + ffi[i+1]));
-      fki[i+1] = static_cast<ZIGINT> (x / x1 * NMANTISSA);
-      fwi[i] = x / NMANTISSA;
-      ffi[i] = exp (-0.5 * x * x);
-      x1 = x;
-    }
+  /*
+   * Here is the guts of the algorithm. As Marsaglia and Tsang state the
+   * algorithm in their paper
+   *
+   * 1) Calculate a random signed integer j and let i be the index
+   *     provided by the rightmost 8-bits of j
+   * 2) Set x = j * w_i. If j < k_i return x
+   * 3) If i = 0, then return x from the tail
+   * 4) If [f(x_{i-1}) - f(x_i)] * U < f(x) - f(x_i), return x
+   * 5) goto step 1
+   *
+   * Where f is the functional form of the distribution, which for a normal
+   * distribution is exp(-0.5*x*x)
+   */
 
-  fki[1] = 0;
-
-  /* Zigurrat tables for the exponential distribution */
-  x1 = ZIGGURAT_EXP_R;
-  fwe[255] = x1 / EMANTISSA;
-  ffe[255] = exp (-x1);
+  template <> float rand_normal<float> (void)
+  {
+    if (inittf)
+      create_ziggurat_float_tables ();
 
-  /* Index zero is special for tail strip, where Marsaglia and Tsang
-   * defines this as
-   * k_0 = 2^32 * r * f(r) / v, w_0 = 0.5^32 * v / f(r), f_0 = 1,
-   * where v is the area of each strip of the ziggurat.
-   */
-  fke[0] = static_cast<ZIGINT> (x1 * ffe[255] / EXP_SECTION_AREA * EMANTISSA);
-  fwe[0] = EXP_SECTION_AREA / ffe[255] / EMANTISSA;
-  ffe[0] = 1.;
+    while (1)
+      {
+        /* 32-bit mantissa */
+        const uint32_t r = randi32 ();
+        const uint32_t rabs = r & LMASK;
+        const int idx = static_cast<int> (r & 0xFF);
+        const float x = static_cast<int32_t> (r) * fwi[idx];
+        if (rabs < fki[idx])
+          return x;        /* 99.3% of the time we return here 1st try */
+        else if (idx == 0)
+          {
+            /* As stated in Marsaglia and Tsang
+             *
+             * For the normal tail, the method of Marsaglia[5] provides:
+             * generate x = -ln(U_1)/r, y = -ln(U_2), until y+y > x*x,
+             * then return r+x. Except that r+x is always in the positive
+             * tail!!!! Any thing random might be used to determine the
+             * sign, but as we already have r we might as well use it
+             *
+             * [PAK] but not the bottom 8 bits, since they are all 0 here!
+             */
+            float xx, yy;
+            do
+              {
+                xx = - ZIGGURAT_NOR_INV_R * std::log (RANDU);
+                yy = - std::log (RANDU);
+              }
+            while ( yy+yy <= xx*xx);
+            return ((rabs & 0x100) ? -ZIGGURAT_NOR_R-xx : ZIGGURAT_NOR_R+xx);
+          }
+        else if ((ffi[idx-1] - ffi[idx]) * RANDU + ffi[idx] < exp (-0.5*x*x))
+          return x;
+      }
+  }
 
-  for (i = 254; i > 0; i--)
-    {
-      /* New x is given by x = f^{-1}(v/x_{i+1} + f(x_{i+1})), thus
-       * need inverse operator of y = exp(-x) -> x = -ln(y)
-       */
-      x = - std::log (EXP_SECTION_AREA / x1 + ffe[i+1]);
-      fke[i+1] = static_cast<ZIGINT> (x / x1 * EMANTISSA);
-      fwe[i] = x / EMANTISSA;
-      ffe[i] = exp (-x);
-      x1 = x;
-    }
-  fke[1] = 0;
+  template <> float rand_exponential<float> (void)
+  {
+    if (inittf)
+      create_ziggurat_float_tables ();
 
-  inittf = 0;
+    while (1)
+      {
+        ZIGINT ri = ERANDI;
+        const int idx = static_cast<int> (ri & 0xFF);
+        const float x = ri * fwe[idx];
+        if (ri < fke[idx])
+          return x;               /* 98.9% of the time we return here 1st try */
+        else if (idx == 0)
+          {
+            /* As stated in Marsaglia and Tsang
+             *
+             * For the exponential tail, the method of Marsaglia[5] provides:
+             * x = r - ln(U);
+             */
+            return ZIGGURAT_EXP_R - std::log (RANDU);
+          }
+        else if ((ffe[idx-1] - ffe[idx]) * RANDU + ffe[idx] < exp (-x))
+          return x;
+      }
+  }
+
+  template <> 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)
+  {
+    std::generate_n (p, n, [](void) { return rand_normal<float> (); });
+  }
+
+  template <> void rand_exponential (octave_idx_type n, float *p)
+  {
+    std::generate_n (p, n, [](void) { return rand_exponential<float> (); });
+  }
 }
 
-/*
- * Here is the guts of the algorithm. As Marsaglia and Tsang state the
- * algorithm in their paper
- *
- * 1) Calculate a random signed integer j and let i be the index
- *     provided by the rightmost 8-bits of j
- * 2) Set x = j * w_i. If j < k_i return x
- * 3) If i = 0, then return x from the tail
- * 4) If [f(x_{i-1}) - f(x_i)] * U < f(x) - f(x_i), return x
- * 5) goto step 1
- *
- * Where f is the functional form of the distribution, which for a normal
- * distribution is exp(-0.5*x*x)
- */
-
-float
-oct_float_randn (void)
-{
-  if (inittf)
-    create_ziggurat_float_tables ();
-
-  while (1)
-    {
-      /* 32-bit mantissa */
-      const uint32_t r = randi32 ();
-      const uint32_t rabs = r & LMASK;
-      const int idx = static_cast<int> (r & 0xFF);
-      const float x = static_cast<int32_t> (r) * fwi[idx];
-      if (rabs < fki[idx])
-        return x;        /* 99.3% of the time we return here 1st try */
-      else if (idx == 0)
-        {
-          /* As stated in Marsaglia and Tsang
-           *
-           * For the normal tail, the method of Marsaglia[5] provides:
-           * generate x = -ln(U_1)/r, y = -ln(U_2), until y+y > x*x,
-           * then return r+x. Except that r+x is always in the positive
-           * tail!!!! Any thing random might be used to determine the
-           * sign, but as we already have r we might as well use it
-           *
-           * [PAK] but not the bottom 8 bits, since they are all 0 here!
-           */
-          float xx, yy;
-          do
-            {
-              xx = - ZIGGURAT_NOR_INV_R * std::log (RANDU);
-              yy = - std::log (RANDU);
-            }
-          while ( yy+yy <= xx*xx);
-          return ((rabs & 0x100) ? -ZIGGURAT_NOR_R-xx : ZIGGURAT_NOR_R+xx);
-        }
-      else if ((ffi[idx-1] - ffi[idx]) * RANDU + ffi[idx] < exp (-0.5*x*x))
-        return x;
-    }
-}
-
-float
-oct_float_rande (void)
-{
-  if (inittf)
-    create_ziggurat_float_tables ();
-
-  while (1)
-    {
-      ZIGINT ri = ERANDI;
-      const int idx = static_cast<int> (ri & 0xFF);
-      const float x = ri * fwe[idx];
-      if (ri < fke[idx])
-        return x;               /* 98.9% of the time we return here 1st try */
-      else if (idx == 0)
-        {
-          /* As stated in Marsaglia and Tsang
-           *
-           * For the exponential tail, the method of Marsaglia[5] provides:
-           * x = r - ln(U);
-           */
-          return ZIGGURAT_EXP_R - std::log (RANDU);
-        }
-      else if ((ffe[idx-1] - ffe[idx]) * RANDU + ffe[idx] < exp (-x))
-        return x;
-    }
-}
-
-/* Array generators */
-void
-oct_fill_randu (octave_idx_type n, double *p)
-{
-  std::generate_n (p, n, oct_randu);
-}
-
-void
-oct_fill_randn (octave_idx_type n, double *p)
-{
-  std::generate_n (p, n, oct_randn);
-}
-
-void
-oct_fill_rande (octave_idx_type n, double *p)
-{
-  std::generate_n (p, n, oct_rande);
-}
-
-void
-oct_fill_float_randu (octave_idx_type n, float *p)
-{
-  std::generate_n (p, n, oct_float_randu);
-}
-
-void
-oct_fill_float_randn (octave_idx_type n, float *p)
-{
-  std::generate_n (p, n, oct_float_randn);
-}
-
-void
-oct_fill_float_rande (octave_idx_type n, float *p)
-{
-  std::generate_n (p, n, oct_float_rande);
-}
--- a/liboctave/numeric/randmtzig.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randmtzig.h	Thu Dec 20 17:18:56 2018 -0500
@@ -68,30 +68,170 @@
 
 #define MT_N 624
 
-// Mersenne Twister.
-extern OCTAVE_API void oct_init_by_int (const uint32_t s);
-extern OCTAVE_API void oct_init_by_array (const uint32_t *init_key,
-                                          const int key_length);
-extern OCTAVE_API void oct_init_by_entropy (void);
-extern OCTAVE_API void oct_set_state (const uint32_t *save);
-extern OCTAVE_API void oct_get_state (uint32_t *save);
+namespace octave
+{
+  // 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 void set_mersenne_twister_state (const uint32_t *save);
+  extern 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> 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 <> double rand_uniform<double> (void);
+  template <> double rand_normal<double> (void);
+  template <> double rand_exponential<double> (void);
+
+  template <> float rand_uniform<float> (void);
+  template <> float rand_normal<float> (void);
+  template <> float rand_exponential<float> (void);
+
+  template <> void
+  rand_uniform<double> (octave_idx_type n, double *p);
+
+  template <> void
+  rand_normal<double> (octave_idx_type n, double *p);
+
+  template <> void
+  rand_exponential<double> (octave_idx_type n, double *p);
+
+  template <> void
+  rand_uniform<float> (octave_idx_type n, float *p);
 
-// Array generators.
-extern OCTAVE_API double oct_randu (void);
-extern OCTAVE_API double oct_randn (void);
-extern OCTAVE_API double oct_rande (void);
+  template <> void
+  rand_normal<float> (octave_idx_type n, float *p);
+
+  template <> void
+  rand_exponential<float> (octave_idx_type n, float *p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::init_mersenne_twister' instead")
+inline void
+oct_init_by_entropy (void)
+{
+  octave::init_mersenne_twister ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::init_mersenne_twister' instead")
+inline void
+oct_init_by_int (const uint32_t seed)
+{
+  octave::init_mersenne_twister (seed);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::init_mersenne_twister' instead")
+inline void
+oct_init_by_array (const uint32_t *init_key, const int key_length)
+{
+  octave::init_mersenne_twister (init_key, key_length);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::set_mersenne_twister_state' instead")
+inline void
+oct_set_state (const uint32_t *save)
+{
+  octave::set_mersenne_twister_state (save);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::get_mersenne_twister_state' instead")
+inline void
+oct_get_state (uint32_t *save)
+{
+  octave::get_mersenne_twister_state (save);
+}
 
-extern OCTAVE_API float oct_float_randu (void);
-extern OCTAVE_API float oct_float_randn (void);
-extern OCTAVE_API float oct_float_rande (void);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_uniform<double>' instead")
+inline double
+oct_randu (void)
+{
+  return octave::rand_uniform<double> ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_normal<double>' instead")
+inline double
+oct_randn (void)
+{
+  return octave::rand_normal<double> ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_exponential<double>' instead")
+inline double
+oct_rande (void)
+{
+  return octave::rand_exponential<double> ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_uniform' instead")
+inline void
+oct_fill_randu (octave_idx_type n, double *p)
+{
+  octave::rand_uniform (n, p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_normal' instead")
+inline void
+oct_fill_randn (octave_idx_type n, double *p)
+{
+  octave::rand_normal (n, p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_exponential' instead")
+inline void
+oct_fill_rande (octave_idx_type n, double *p)
+{
+  octave::rand_exponential (n, p);
+}
 
-// Array generators.
-extern OCTAVE_API void oct_fill_randu (octave_idx_type n, double *p);
-extern OCTAVE_API void oct_fill_randn (octave_idx_type n, double *p);
-extern OCTAVE_API void oct_fill_rande (octave_idx_type n, double *p);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_uniform<float>' instead")
+inline float
+oct_float_randu (void)
+{
+  return octave::rand_uniform<float> ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_normal<float>' instead")
+inline float
+oct_float_randn (void)
+{
+  return octave::rand_normal<float> ();
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_exponential<float>' instead")
+inline float
+oct_float_rande (void)
+{
+  return octave::rand_exponential<float> ();
+}
 
-extern OCTAVE_API void oct_fill_float_randu (octave_idx_type n, float *p);
-extern OCTAVE_API void oct_fill_float_randn (octave_idx_type n, float *p);
-extern OCTAVE_API void oct_fill_float_rande (octave_idx_type n, float *p);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_uniform' instead")
+inline void
+oct_fill_float_randu (octave_idx_type n, float *p)
+{
+  octave::rand_uniform (n, p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_normal' instead")
+inline void
+oct_fill_float_randn (octave_idx_type n, float *p)
+{
+  octave::rand_normal (n, p);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_exponential' instead")
+inline void
+oct_fill_float_rande (octave_idx_type n, float *p)
+{
+  octave::rand_exponential (n, p);
+}
 
 #endif
--- a/liboctave/numeric/randpoisson.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randpoisson.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -23,14 +23,6 @@
 /* Original version written by Paul Kienzle distributed as free
    software in the in the public domain.  */
 
-/* Needs the following defines:
- * NAN: value to return for Not-A-Number
- * RUNI: uniform generator on (0,1)
- * RNOR: normal generator
- * LGAMMA: log gamma function
- * INFINITE: function to test whether a value is infinite
- */
-
 #if defined (HAVE_CONFIG_H)
 #  include "config.h"
 #endif
@@ -44,246 +36,234 @@
 #include "randmtzig.h"
 #include "randpoisson.h"
 
-#undef INFINITE
-#define INFINITE lo_ieee_isinf
-#define RUNI oct_randu()
-#define RNOR oct_randn()
-#define LGAMMA xlgamma
-
-static double
-xlgamma (double x)
+namespace octave
 {
-  return std::lgamma (x);
-}
-
-/* ---- pprsc.c from Stadloeber's winrand --- */
+  static double xlgamma (double x)
+  {
+    return std::lgamma (x);
+  }
 
-/* flogfak(k) = ln(k!) */
-static double
-flogfak (double k)
-{
+  /* ---- pprsc.c from Stadloeber's winrand --- */
+
+  /* flogfak(k) = ln(k!) */
+  static double flogfak (double k)
+  {
 #define C0  9.18938533204672742e-01
 #define C1  8.33333333333333333e-02
 #define C3 -2.77777777777777778e-03
 #define C5  7.93650793650793651e-04
 #define C7 -5.95238095238095238e-04
 
-  static double logfak[30L] =
-  {
-    0.00000000000000000,   0.00000000000000000,   0.69314718055994531,
-    1.79175946922805500,   3.17805383034794562,   4.78749174278204599,
-    6.57925121201010100,   8.52516136106541430,  10.60460290274525023,
-    12.80182748008146961,  15.10441257307551530,  17.50230784587388584,
-    19.98721449566188615,  22.55216385312342289,  25.19122118273868150,
-    27.89927138384089157,  30.67186010608067280,  33.50507345013688888,
-    36.39544520803305358,  39.33988418719949404,  42.33561646075348503,
-    45.38013889847690803,  48.47118135183522388,  51.60667556776437357,
-    54.78472939811231919,  58.00360522298051994,  61.26170176100200198,
-    64.55753862700633106,  67.88974313718153498,  71.25703896716800901
-  };
+    static double logfak[30L] =
+      {
+        0.00000000000000000,   0.00000000000000000,   0.69314718055994531,
+        1.79175946922805500,   3.17805383034794562,   4.78749174278204599,
+        6.57925121201010100,   8.52516136106541430,  10.60460290274525023,
+        12.80182748008146961,  15.10441257307551530,  17.50230784587388584,
+        19.98721449566188615,  22.55216385312342289,  25.19122118273868150,
+        27.89927138384089157,  30.67186010608067280,  33.50507345013688888,
+        36.39544520803305358,  39.33988418719949404,  42.33561646075348503,
+        45.38013889847690803,  48.47118135183522388,  51.60667556776437357,
+        54.78472939811231919,  58.00360522298051994,  61.26170176100200198,
+        64.55753862700633106,  67.88974313718153498,  71.25703896716800901
+      };
 
-  double r, rr;
+    double r, rr;
 
-  if (k >= 30.0)
-    {
-      r  = 1.0 / k;
-      rr = r * r;
-      return ((k + 0.5)*std::log (k) - k + C0
-              + r*(C1 + rr*(C3 + rr*(C5 + rr*C7))));
-    }
-  else
-    return (logfak[static_cast<int> (k)]);
-}
+    if (k >= 30.0)
+      {
+        r  = 1.0 / k;
+        rr = r * r;
+        return ((k + 0.5)*std::log (k) - k + C0
+                + r*(C1 + rr*(C3 + rr*(C5 + rr*C7))));
+      }
+    else
+      return (logfak[static_cast<int> (k)]);
+  }
 
-/******************************************************************
- *                                                                *
- * Poisson Distribution - Patchwork Rejection/Inversion           *
- *                                                                *
- ******************************************************************
- *                                                                *
- * For parameter my < 10, Tabulated Inversion is applied.         *
- * For my >= 10, Patchwork Rejection is employed:                 *
- * The area below the histogram function f(x) is rearranged in    *
- * its body by certain point reflections. Within a large center   *
- * interval variates are sampled efficiently by rejection from    *
- * uniform hats. Rectangular immediate acceptance regions speed   *
- * up the generation. The remaining tails are covered by          *
- * exponential functions.                                         *
- *                                                                *
- ******************************************************************
- *                                                                *
- * FUNCTION :   - pprsc samples a random number from the Poisson  *
- *                distribution with parameter my > 0.             *
- * REFERENCE :  - H. Zechner (1994): Efficient sampling from      *
- *                continuous and discrete unimodal distributions, *
- *                Doctoral Dissertation, 156 pp., Technical       *
- *                University Graz, Austria.                       *
- * SUBPROGRAM : - drand(seed) ... (0,1)-Uniform generator with    *
- *                unsigned long integer *seed.                    *
- *                                                                *
- * Implemented by H. Zechner, January 1994                        *
- * Revised by F. Niederl, July 1994                               *
- *                                                                *
- ******************************************************************/
+  /******************************************************************
+   *                                                                *
+   * Poisson Distribution - Patchwork Rejection/Inversion           *
+   *                                                                *
+   ******************************************************************
+   *                                                                *
+   * For parameter my < 10, Tabulated Inversion is applied.         *
+   * For my >= 10, Patchwork Rejection is employed:                 *
+   * The area below the histogram function f(x) is rearranged in    *
+   * its body by certain point reflections. Within a large center   *
+   * interval variates are sampled efficiently by rejection from    *
+   * uniform hats. Rectangular immediate acceptance regions speed   *
+   * up the generation. The remaining tails are covered by          *
+   * exponential functions.                                         *
+   *                                                                *
+   ******************************************************************
+   *                                                                *
+   * FUNCTION :   - pprsc samples a random number from the Poisson  *
+   *                distribution with parameter my > 0.             *
+   * REFERENCE :  - H. Zechner (1994): Efficient sampling from      *
+   *                continuous and discrete unimodal distributions, *
+   *                Doctoral Dissertation, 156 pp., Technical       *
+   *                University Graz, Austria.                       *
+   * SUBPROGRAM : - drand(seed) ... (0,1)-Uniform generator with    *
+   *                unsigned long integer *seed.                    *
+   *                                                                *
+   * Implemented by H. Zechner, January 1994                        *
+   * Revised by F. Niederl, July 1994                               *
+   *                                                                *
+   ******************************************************************/
 
-static double
-f (double k, double l_nu, double c_pm)
-{
-  return exp (k * l_nu - flogfak (k) - c_pm);
-}
+  static double f (double k, double l_nu, double c_pm)
+  {
+    return exp (k * l_nu - flogfak (k) - c_pm);
+  }
 
-static double
-pprsc (double my)
-{
-  static double my_last = -1.0;
-  static double m,  k2, k4, k1, k5;
-  static double dl, dr, r1, r2, r4, r5, ll, lr, l_my, c_pm,
-                f1, f2, f4, f5, p1, p2, p3, p4, p5, p6;
-  double        Dk, X, Y;
-  double        Ds, U, V, W;
+  static double pprsc (double my)
+  {
+    static double my_last = -1.0;
+    static double m,  k2, k4, k1, k5;
+    static double dl, dr, r1, r2, r4, r5, ll, lr, l_my, c_pm,
+      f1, f2, f4, f5, p1, p2, p3, p4, p5, p6;
+    double        Dk, X, Y;
+    double        Ds, U, V, W;
 
-  if (my != my_last)
-    {                               /* set-up           */
-      my_last = my;
-      /* approximate deviation of reflection points k2, k4 from my - 1/2 */
-      Ds = std::sqrt (my + 0.25);
+    if (my != my_last)
+      {                               /* set-up           */
+        my_last = my;
+        /* approximate deviation of reflection points k2, k4 from my - 1/2 */
+        Ds = std::sqrt (my + 0.25);
 
-      /* mode m, reflection points k2 and k4, and points k1 and k5,      */
-      /* which delimit the centre region of h(x)                         */
-      m  = std::floor (my);
-      k2 = ceil (my - 0.5 - Ds);
-      k4 = std::floor (my - 0.5 + Ds);
-      k1 = k2 + k2 - m + 1L;
-      k5 = k4 + k4 - m;
+        /* mode m, reflection points k2 and k4, and points k1 and k5,      */
+        /* which delimit the centre region of h(x)                         */
+        m  = std::floor (my);
+        k2 = ceil (my - 0.5 - Ds);
+        k4 = std::floor (my - 0.5 + Ds);
+        k1 = k2 + k2 - m + 1L;
+        k5 = k4 + k4 - m;
 
-      /* range width of the critical left and right centre region        */
-      dl = (k2 - k1);
-      dr = (k5 - k4);
+        /* range width of the critical left and right centre region        */
+        dl = (k2 - k1);
+        dr = (k5 - k4);
 
-      /* recurrence constants r(k)=p(k)/p(k-1) at k = k1, k2, k4+1, k5+1 */
-      r1 = my / k1;
-      r2 = my / k2;
-      r4 = my / (k4 + 1.0);
-      r5 = my / (k5 + 1.0);
+        /* recurrence constants r(k)=p(k)/p(k-1) at k = k1, k2, k4+1, k5+1 */
+        r1 = my / k1;
+        r2 = my / k2;
+        r4 = my / (k4 + 1.0);
+        r5 = my / (k5 + 1.0);
 
-      /* reciprocal values of the scale parameters of exp. tail envelope */
-      ll =  std::log (r1);                        /* expon. tail left */
-      lr = -std::log (r5);                        /* expon. tail right*/
+        /* reciprocal values of the scale parameters of exp. tail envelope */
+        ll =  std::log (r1);                        /* expon. tail left */
+        lr = -std::log (r5);                        /* expon. tail right*/
 
-      /* Poisson constants, necessary for computing function values f(k) */
-      l_my = std::log (my);
-      c_pm = m * l_my - flogfak (m);
+        /* Poisson constants, necessary for computing function values f(k) */
+        l_my = std::log (my);
+        c_pm = m * l_my - flogfak (m);
 
-      /* function values f(k) = p(k)/p(m) at k = k2, k4, k1, k5          */
-      f2 = f (k2, l_my, c_pm);
-      f4 = f (k4, l_my, c_pm);
-      f1 = f (k1, l_my, c_pm);
-      f5 = f (k5, l_my, c_pm);
+        /* function values f(k) = p(k)/p(m) at k = k2, k4, k1, k5          */
+        f2 = f (k2, l_my, c_pm);
+        f4 = f (k4, l_my, c_pm);
+        f1 = f (k1, l_my, c_pm);
+        f5 = f (k5, l_my, c_pm);
 
-      /* area of the two centre and the two exponential tail regions     */
-      /* area of the two immediate acceptance regions between k2, k4     */
-      p1 = f2 * (dl + 1.0);                            /* immed. left    */
-      p2 = f2 * dl         + p1;                       /* centre left    */
-      p3 = f4 * (dr + 1.0) + p2;                       /* immed. right   */
-      p4 = f4 * dr         + p3;                       /* centre right   */
-      p5 = f1 / ll         + p4;                       /* exp. tail left */
-      p6 = f5 / lr         + p5;                       /* exp. tail right*/
-    }
+        /* area of the two centre and the two exponential tail regions     */
+        /* area of the two immediate acceptance regions between k2, k4     */
+        p1 = f2 * (dl + 1.0);                            /* immed. left    */
+        p2 = f2 * dl         + p1;                       /* centre left    */
+        p3 = f4 * (dr + 1.0) + p2;                       /* immed. right   */
+        p4 = f4 * dr         + p3;                       /* centre right   */
+        p5 = f1 / ll         + p4;                       /* exp. tail left */
+        p6 = f5 / lr         + p5;                       /* exp. tail right*/
+      }
 
-  for (;;)
-    {
-      /* generate uniform number U -- U(0, p6)                           */
-      /* case distinction corresponding to U                             */
-      if ((U = RUNI * p6) < p2)
-        {                                            /* centre left      */
+    for (;;)
+      {
+        /* generate uniform number U -- U(0, p6)                           */
+        /* case distinction corresponding to U                             */
+        if ((U = octave::rand_uniform<double> () * p6) < p2)
+          {                                            /* centre left      */
 
-          /* immediate acceptance region
-             R2 = [k2, m) *[0, f2),  X = k2, ... m -1 */
-          if ((V = U - p1) < 0.0)  return (k2 + std::floor (U/f2));
-          /* immediate acceptance region
-             R1 = [k1, k2)*[0, f1),  X = k1, ... k2-1 */
-          if ((W = V / dl) < f1 )  return (k1 + std::floor (V/f1));
+            /* immediate acceptance region
+               R2 = [k2, m) *[0, f2),  X = k2, ... m -1 */
+            if ((V = U - p1) < 0.0)  return (k2 + std::floor (U/f2));
+            /* immediate acceptance region
+               R1 = [k1, k2)*[0, f1),  X = k1, ... k2-1 */
+            if ((W = V / dl) < f1 )  return (k1 + std::floor (V/f1));
 
-          /* computation of candidate X < k2, and its counterpart Y > k2 */
-          /* either squeeze-acceptance of X or acceptance-rejection of Y */
-          Dk = std::floor (dl * RUNI) + 1.0;
-          if (W <= f2 - Dk * (f2 - f2/r2))
-            {                                        /* quick accept of  */
-              return (k2 - Dk);                      /* X = k2 - Dk      */
-            }
-          if ((V = f2 + f2 - W) < 1.0)
-            {                                        /* quick reject of Y*/
-              Y = k2 + Dk;
-              if (V <= f2 + Dk * (1.0 - f2)/(dl + 1.0))
-                {                                    /* quick accept of  */
-                  return (Y);                        /* Y = k2 + Dk      */
-                }
-              if (V <= f (Y, l_my, c_pm))  return (Y); /* final accept of Y*/
-            }
-          X = k2 - Dk;
-        }
-      else if (U < p4)
-        {                                            /* centre right     */
-          /*  immediate acceptance region
-              R3 = [m, k4+1)*[0, f4), X = m, ... k4    */
-          if ((V = U - p3) < 0.0)  return (k4 - std::floor ((U - p2)/f4));
-          /* immediate acceptance region
-             R4 = [k4+1, k5+1)*[0, f5)                */
-          if ((W = V / dr) < f5 )  return (k5 - std::floor (V/f5));
+            /* computation of candidate X < k2, and its counterpart Y > k2 */
+            /* either squeeze-acceptance of X or acceptance-rejection of Y */
+            Dk = std::floor (dl * octave::rand_uniform<double> ()) + 1.0;
+            if (W <= f2 - Dk * (f2 - f2/r2))
+              {                                        /* quick accept of  */
+                return (k2 - Dk);                      /* X = k2 - Dk      */
+              }
+            if ((V = f2 + f2 - W) < 1.0)
+              {                                        /* quick reject of Y*/
+                Y = k2 + Dk;
+                if (V <= f2 + Dk * (1.0 - f2)/(dl + 1.0))
+                  {                                    /* quick accept of  */
+                    return (Y);                        /* Y = k2 + Dk      */
+                  }
+                if (V <= f (Y, l_my, c_pm))  return (Y); /* final accept of Y*/
+              }
+            X = k2 - Dk;
+          }
+        else if (U < p4)
+          {                                            /* centre right     */
+            /*  immediate acceptance region
+                R3 = [m, k4+1)*[0, f4), X = m, ... k4    */
+            if ((V = U - p3) < 0.0)  return (k4 - std::floor ((U - p2)/f4));
+            /* immediate acceptance region
+               R4 = [k4+1, k5+1)*[0, f5)                */
+            if ((W = V / dr) < f5 )  return (k5 - std::floor (V/f5));
 
-          /* computation of candidate X > k4, and its counterpart Y < k4 */
-          /* either squeeze-acceptance of X or acceptance-rejection of Y */
-          Dk = std::floor (dr * RUNI) + 1.0;
-          if (W <= f4 - Dk * (f4 - f4*r4))
-            {                                        /* quick accept of  */
-              return (k4 + Dk);                      /* X = k4 + Dk      */
-            }
-          if ((V = f4 + f4 - W) < 1.0)
-            {                                        /* quick reject of Y*/
-              Y = k4 - Dk;
-              if (V <= f4 + Dk * (1.0 - f4)/ dr)
-                {                                    /* quick accept of  */
-                  return (Y);                        /* Y = k4 - Dk      */
-                }
-              if (V <= f (Y, l_my, c_pm))  return (Y); /* final accept of Y*/
-            }
-          X = k4 + Dk;
-        }
-      else
-        {
-          W = RUNI;
-          if (U < p5)
-            {                                        /* expon. tail left */
-              Dk = std::floor (1.0 - std::log (W)/ll);
-              if ((X = k1 - Dk) < 0L)  continue;     /* 0 <= X <= k1 - 1 */
-              W *= (U - p4) * ll;                    /* W -- U(0, h(x))  */
-              if (W <= f1 - Dk * (f1 - f1/r1))
-                return (X);                          /* quick accept of X*/
-            }
-          else
-            {                                        /* expon. tail right*/
-              Dk = std::floor (1.0 - std::log (W)/lr);
-              X  = k5 + Dk;                          /* X >= k5 + 1      */
-              W *= (U - p5) * lr;                    /* W -- U(0, h(x))  */
-              if (W <= f5 - Dk * (f5 - f5*r5))
-                return (X);                          /* quick accept of X*/
-            }
-        }
+            /* computation of candidate X > k4, and its counterpart Y < k4 */
+            /* either squeeze-acceptance of X or acceptance-rejection of Y */
+            Dk = std::floor (dr * octave::rand_uniform<double> ()) + 1.0;
+            if (W <= f4 - Dk * (f4 - f4*r4))
+              {                                        /* quick accept of  */
+                return (k4 + Dk);                      /* X = k4 + Dk      */
+              }
+            if ((V = f4 + f4 - W) < 1.0)
+              {                                        /* quick reject of Y*/
+                Y = k4 - Dk;
+                if (V <= f4 + Dk * (1.0 - f4)/ dr)
+                  {                                    /* quick accept of  */
+                    return (Y);                        /* Y = k4 - Dk      */
+                  }
+                if (V <= f (Y, l_my, c_pm))  return (Y); /* final accept of Y*/
+              }
+            X = k4 + Dk;
+          }
+        else
+          {
+            W = octave::rand_uniform<double> ();
+            if (U < p5)
+              {                                        /* expon. tail left */
+                Dk = std::floor (1.0 - std::log (W)/ll);
+                if ((X = k1 - Dk) < 0L)  continue;     /* 0 <= X <= k1 - 1 */
+                W *= (U - p4) * ll;                    /* W -- U(0, h(x))  */
+                if (W <= f1 - Dk * (f1 - f1/r1))
+                  return (X);                          /* quick accept of X*/
+              }
+            else
+              {                                        /* expon. tail right*/
+                Dk = std::floor (1.0 - std::log (W)/lr);
+                X  = k5 + Dk;                          /* X >= k5 + 1      */
+                W *= (U - p5) * lr;                    /* W -- U(0, h(x))  */
+                if (W <= f5 - Dk * (f5 - f5*r5))
+                  return (X);                          /* quick accept of X*/
+              }
+          }
 
-      /* acceptance-rejection test of candidate X from the original area */
-      /* test, whether  W <= f(k),    with  W = U*h(x)  and  U -- U(0, 1)*/
-      /* log f(X) = (X - m)*log(my) - log X! + log m!                    */
-      if (std::log (W) <= X * l_my - flogfak (X) - c_pm)  return (X);
-    }
-}
-/* ---- pprsc.c end ------ */
+        /* acceptance-rejection test of candidate X from the original area */
+        /* test, whether  W <= f(k),    with  W = U*h(x)  and  U -- U(0, 1)*/
+        /* log f(X) = (X - m)*log(my) - log X! + log m!                    */
+        if (std::log (W) <= X * l_my - flogfak (X) - c_pm)  return (X);
+      }
+  }
+  /* ---- pprsc.c end ------ */
 
-/* The remainder of the file is by Paul Kienzle */
+  /* The remainder of the file is by Paul Kienzle */
 
-/* Given uniform u, find x such that CDF(L,x)==u.  Return x. */
-static void
-poisson_cdf_lookup (double lambda, double *p, size_t n)
-{
   /* Table size is predicated on the maximum value of lambda
    * we want to store in the table, and the maximum value of
    * returned by the uniform random number generator on [0,1).
@@ -294,312 +274,184 @@
    * size of 46 instead.  For long doubles, the table size
    * will need to be longer still.  */
 #define TABLESIZE 46
-  double t[TABLESIZE];
 
-  /* Precompute the table for the u up to and including 0.458.
-   * We will almost certainly need it. */
-  int intlambda = static_cast<int> (std::floor (lambda));
-  double P;
-  int tableidx;
-  size_t i = n;
+  /* Given uniform u, find x such that CDF(L,x)==u.  Return x. */
 
-  t[0] = P = exp (-lambda);
-  for (tableidx = 1; tableidx <= intlambda; tableidx++)
-    {
-      P = P*lambda/static_cast<double> (tableidx);
-      t[tableidx] = t[tableidx-1] + P;
-    }
+  template <typename T>
+  static void
+  poisson_cdf_lookup (double lambda, T *p, size_t n)
+  {
+    double t[TABLESIZE];
 
-  while (i-- > 0)
-    {
-      double u = RUNI;
-
-      /* If u > 0.458 we know we can jump to floor(lambda) before
-       * comparing (this observation is based on Stadlober's winrand
-       * code). For lambda >= 1, this will be a win.  Lambda < 1
-       * is already fast, so adding an extra comparison is not a
-       * problem. */
-      int k = (u > 0.458 ? intlambda : 0);
+    /* Precompute the table for the u up to and including 0.458.
+     * We will almost certainly need it. */
+    int intlambda = static_cast<int> (std::floor (lambda));
+    double P;
+    int tableidx;
+    size_t i = n;
 
-      /* We aren't using a for loop here because when we find the
-       * right k we want to jump to the next iteration of the
-       * outer loop, and the continue statement will only work for
-       * the inner loop. */
-    nextk:
-      if (u <= t[k])
-        {
-          p[i] = static_cast<double> (k);
-          continue;
-        }
-      if (++k < tableidx)
-        goto nextk;
+    t[0] = P = exp (-lambda);
+    for (tableidx = 1; tableidx <= intlambda; tableidx++)
+      {
+        P = P*lambda/static_cast<double> (tableidx);
+        t[tableidx] = t[tableidx-1] + P;
+      }
 
-      /* We only need high values of the table very rarely so we
-       * don't automatically compute the entire table. */
-      while (tableidx < TABLESIZE)
-        {
-          P = P*lambda/static_cast<double> (tableidx);
-          t[tableidx] = t[tableidx-1] + P;
-          /* Make sure we converge to 1.0 just in case u is uniform
-           * on [0,1] rather than [0,1). */
-          if (t[tableidx] == t[tableidx-1]) t[tableidx] = 1.0;
-          tableidx++;
-          if (u <= t[tableidx-1]) break;
-        }
+    while (i-- > 0)
+      {
+        double u = octave::rand_uniform<double> ();
 
-      /* We are assuming that the table size is big enough here.
-       * This should be true even if RUNI is returning values in
-       * the range [0,1] rather than [0,1). */
-      p[i] = static_cast<double> (tableidx-1);
-    }
-}
-
-static void
-poisson_cdf_lookup_float (double lambda, float *p, size_t n)
-{
-  double t[TABLESIZE];
+        /* If u > 0.458 we know we can jump to floor(lambda) before
+         * comparing (this observation is based on Stadlober's winrand
+         * code). For lambda >= 1, this will be a win.  Lambda < 1
+         * is already fast, so adding an extra comparison is not a
+         * problem. */
+        int k = (u > 0.458 ? intlambda : 0);
 
-  /* Precompute the table for the u up to and including 0.458.
-   * We will almost certainly need it. */
-  int intlambda = static_cast<int> (std::floor (lambda));
-  double P;
-  int tableidx;
-  size_t i = n;
-
-  t[0] = P = exp (-lambda);
-  for (tableidx = 1; tableidx <= intlambda; tableidx++)
-    {
-      P = P*lambda/static_cast<double> (tableidx);
-      t[tableidx] = t[tableidx-1] + P;
-    }
-
-  while (i-- > 0)
-    {
-      double u = RUNI;
-      int k = (u > 0.458 ? intlambda : 0);
-    nextk:
-      if (u <= t[k])
-        {
-          p[i] = static_cast<float> (k);
-          continue;
-        }
-      if (++k < tableidx)
-        goto nextk;
-
-      while (tableidx < TABLESIZE)
-        {
-          P = P*lambda/static_cast<double> (tableidx);
-          t[tableidx] = t[tableidx-1] + P;
-          if (t[tableidx] == t[tableidx-1]) t[tableidx] = 1.0;
-          tableidx++;
-          if (u <= t[tableidx-1]) break;
-        }
+        /* We aren't using a for loop here because when we find the
+         * right k we want to jump to the next iteration of the
+         * outer loop, and the continue statement will only work for
+         * the inner loop. */
+      nextk:
+        if (u <= t[k])
+          {
+            p[i] = static_cast<T> (k);
+            continue;
+          }
+        if (++k < tableidx)
+          goto nextk;
 
-      p[i] = static_cast<float> (tableidx-1);
-    }
-}
-
-/* From Press, et al., Numerical Recipes */
-static void
-poisson_rejection (double lambda, double *p, size_t n)
-{
-  double sq = std::sqrt (2.0*lambda);
-  double alxm = std::log (lambda);
-  double g = lambda*alxm - LGAMMA(lambda+1.0);
-  size_t i;
+        /* We only need high values of the table very rarely so we
+         * don't automatically compute the entire table. */
+        while (tableidx < TABLESIZE)
+          {
+            P = P*lambda/static_cast<double> (tableidx);
+            t[tableidx] = t[tableidx-1] + P;
+            /* Make sure we converge to 1.0 just in case u is uniform
+             * on [0,1] rather than [0,1). */
+            if (t[tableidx] == t[tableidx-1]) t[tableidx] = 1.0;
+            tableidx++;
+            if (u <= t[tableidx-1]) break;
+          }
 
-  for (i = 0; i < n; i++)
-    {
-      double y, em, t;
-      do
-        {
-          do
-            {
-              y = tan (M_PI*RUNI);
-              em = sq * y + lambda;
-            } while (em < 0.0);
-          em = std::floor (em);
-          t = 0.9*(1.0+y*y)*exp (em*alxm-flogfak (em)-g);
-        } while (RUNI > t);
-      p[i] = em;
-    }
-}
+        /* We are assuming that the table size is big enough here.
+         * This should be true even if rand_uniform is returning values in
+         * the range [0,1] rather than [0,1). */
+        p[i] = static_cast<T> (tableidx-1);
+      }
+  }
 
-/* From Press, et al., Numerical Recipes */
-static void
-poisson_rejection_float (double lambda, float *p, size_t n)
-{
-  double sq = std::sqrt (2.0*lambda);
-  double alxm = std::log (lambda);
-  double g = lambda*alxm - LGAMMA(lambda+1.0);
-  size_t i;
+  /* From Press, et al., Numerical Recipes */
+  template <typename T>
+  static void
+  poisson_rejection (double lambda, T *p, size_t n)
+  {
+    double sq = std::sqrt (2.0*lambda);
+    double alxm = std::log (lambda);
+    double g = lambda*alxm - xlgamma (lambda+1.0);
+    size_t i;
 
-  for (i = 0; i < n; i++)
-    {
-      double y, em, t;
-      do
-        {
-          do
-            {
-              y = tan (M_PI*RUNI);
-              em = sq * y + lambda;
-            } while (em < 0.0);
-          em = std::floor (em);
-          t = 0.9*(1.0+y*y)*exp (em*alxm-flogfak (em)-g);
-        } while (RUNI > t);
-      p[i] = em;
-    }
-}
-
-/* The cutoff of L <= 1e8 in the following two functions before using
- * the normal approximation is based on:
- *   > L=1e8; x=floor(linspace(0,2*L,1000));
- *   > max(abs(normal_pdf(x,L,L)-poisson_pdf(x,L)))
- *   ans = 1.1376e-28
- * For L=1e7, the max is around 1e-9, which is within the step size of RUNI.
- * For L>1e10 the pprsc function breaks down, as I saw from the histogram
- * of a large sample, so 1e8 is both small enough and large enough. */
+    for (i = 0; i < n; i++)
+      {
+        double y, em, t;
+        do
+          {
+            do
+              {
+                y = tan (M_PI*octave::rand_uniform<double> ());
+                em = sq * y + lambda;
+              } while (em < 0.0);
+            em = std::floor (em);
+            t = 0.9*(1.0+y*y)*exp (em*alxm-flogfak (em)-g);
+          } while (octave::rand_uniform<double> () > t);
+        p[i] = em;
+      }
+  }
 
-/* Generate a set of poisson numbers with the same distribution */
-void
-oct_fill_randp (double L, octave_idx_type n, double *p)
-{
-  octave_idx_type i;
-  if (L < 0.0 || INFINITE(L))
-    {
-      for (i=0; i<n; i++)
-        p[i] = octave::numeric_limits<double>::NaN ();
-    }
-  else if (L <= 10.0)
-    {
-      poisson_cdf_lookup (L, p, n);
-    }
-  else if (L <= 1e8)
-    {
-      for (i=0; i<n; i++)
-        p[i] = pprsc (L);
-    }
-  else
-    {
-      /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
-      const double sqrtL = std::sqrt (L);
-      for (i = 0; i < n; i++)
-        {
-          p[i] = std::floor (RNOR*sqrtL + L + 0.5);
-          if (p[i] < 0.0)
-            p[i] = 0.0; /* will probably never happen */
-        }
-    }
-}
+  /* The cutoff of L <= 1e8 in the following two functions before using
+   * the normal approximation is based on:
+   *   > L=1e8; x=floor(linspace(0,2*L,1000));
+   *   > max(abs(normal_pdf(x,L,L)-poisson_pdf(x,L)))
+   *   ans = 1.1376e-28
+   * For L=1e7, the max is around 1e-9, which is within the step size of
+   * rand_uniform.  For L>1e10 the pprsc function breaks down, as I saw
+   * from the histogram of a large sample, so 1e8 is both small enough
+   * and large enough. */
 
-/* Generate one poisson variate */
-double
-oct_randp (double L)
-{
-  double ret;
-  if (L < 0.0) ret = octave::numeric_limits<double>::NaN ();
-  else if (L <= 12.0)
-    {
-      /* From Press, et al. Numerical recipes */
-      double g = exp (-L);
-      int em = -1;
-      double t = 1.0;
-      do
-        {
-          ++em;
-          t *= RUNI;
-        } while (t > g);
-      ret = em;
-    }
-  else if (L <= 1e8)
-    {
-      /* numerical recipes */
-      poisson_rejection (L, &ret, 1);
-    }
-  else if (INFINITE(L))
-    {
-      /* FIXME: R uses NaN, but the normal approximation suggests that
-       * limit should be Inf.  Which is correct? */
-      ret = octave::numeric_limits<double>::NaN ();
-    }
-  else
-    {
-      /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
-      ret = std::floor (RNOR*std::sqrt (L) + L + 0.5);
-      if (ret < 0.0) ret = 0.0; /* will probably never happen */
-    }
-  return ret;
-}
+  /* Generate a set of poisson numbers with the same distribution */
+  template <typename T> void rand_poisson (T L_arg, octave_idx_type n, T *p)
+  {
+    double L = L_arg;
+    octave_idx_type i;
+    if (L < 0.0 || lo_ieee_isinf (L))
+      {
+        for (i=0; i<n; i++)
+          p[i] = numeric_limits<T>::NaN ();
+      }
+    else if (L <= 10.0)
+      {
+        poisson_cdf_lookup<T> (L, p, n);
+      }
+    else if (L <= 1e8)
+      {
+        for (i=0; i<n; i++)
+          p[i] = pprsc (L);
+      }
+    else
+      {
+        /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
+        const double sqrtL = std::sqrt (L);
+        for (i = 0; i < n; i++)
+          {
+            p[i] = std::floor (rand_normal<T> () * sqrtL + L + 0.5);
+            if (p[i] < 0.0)
+              p[i] = 0.0; /* will probably never happen */
+          }
+      }
+  }
+
+  template void rand_poisson<double> (double, octave_idx_type, double *);
+  template void rand_poisson<float> (float, octave_idx_type, float *);
 
-/* Generate a set of poisson numbers with the same distribution */
-void
-oct_fill_float_randp (float FL, octave_idx_type n, float *p)
-{
-  double L = FL;
-  octave_idx_type i;
-  if (L < 0.0 || INFINITE(L))
-    {
-      for (i=0; i<n; i++)
-        p[i] = octave::numeric_limits<double>::NaN ();
-    }
-  else if (L <= 10.0)
-    {
-      poisson_cdf_lookup_float (L, p, n);
-    }
-  else if (L <= 1e8)
-    {
-      for (i=0; i<n; i++)
-        p[i] = pprsc (L);
-    }
-  else
-    {
-      /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
-      const double sqrtL = std::sqrt (L);
-      for (i = 0; i < n; i++)
-        {
-          p[i] = std::floor (RNOR*sqrtL + L + 0.5);
-          if (p[i] < 0.0)
-            p[i] = 0.0; /* will probably never happen */
-        }
-    }
-}
+  /* Generate one poisson variate */
+  template <typename T> T rand_poisson (T L_arg)
+  {
+    double L = L_arg;
+    T ret;
+    if (L < 0.0) ret = numeric_limits<T>::NaN ();
+    else if (L <= 12.0)
+      {
+        /* From Press, et al. Numerical recipes */
+        double g = exp (-L);
+        int em = -1;
+        double t = 1.0;
+        do
+          {
+            ++em;
+            t *= rand_uniform<T> ();
+          } while (t > g);
+        ret = em;
+      }
+    else if (L <= 1e8)
+      {
+        /* numerical recipes */
+        poisson_rejection<T> (L, &ret, 1);
+      }
+    else if (lo_ieee_isinf (L))
+      {
+        /* FIXME: R uses NaN, but the normal approximation suggests that
+         * limit should be Inf.  Which is correct? */
+        ret = numeric_limits<T>::NaN ();
+      }
+    else
+      {
+        /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
+        ret = std::floor (rand_normal<T> () * std::sqrt (L) + L + 0.5);
+        if (ret < 0.0) ret = 0.0; /* will probably never happen */
+      }
+    return ret;
+  }
 
-/* Generate one poisson variate */
-float
-oct_float_randp (float FL)
-{
-  double L = FL;
-  float ret;
-  if (L < 0.0) ret = octave::numeric_limits<float>::NaN ();
-  else if (L <= 12.0)
-    {
-      /* From Press, et al. Numerical recipes */
-      double g = exp (-L);
-      int em = -1;
-      double t = 1.0;
-      do
-        {
-          ++em;
-          t *= RUNI;
-        } while (t > g);
-      ret = em;
-    }
-  else if (L <= 1e8)
-    {
-      /* numerical recipes */
-      poisson_rejection_float (L, &ret, 1);
-    }
-  else if (INFINITE(L))
-    {
-      /* FIXME: R uses NaN, but the normal approximation suggests that
-       * limit should be Inf. Which is correct? */
-      ret = octave::numeric_limits<float>::NaN ();
-    }
-  else
-    {
-      /* normal approximation: from Phys. Rev. D (1994) v50 p1284 */
-      ret = std::floor (RNOR*std::sqrt (L) + L + 0.5);
-      if (ret < 0.0) ret = 0.0; /* will probably never happen */
-    }
-  return ret;
+  template double rand_poisson<double> (double);
+  template float rand_poisson<float> (float);
 }
--- a/liboctave/numeric/randpoisson.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/randpoisson.h	Thu Dec 20 17:18:56 2018 -0500
@@ -28,16 +28,39 @@
 
 #include "octave-config.h"
 
-extern OCTAVE_API double
-oct_randp (double L);
+namespace octave
+{
+  template <typename T> void rand_poisson (T L, octave_idx_type n, T *p);
+
+  template <typename T> T rand_poisson (T L);
+}
 
-extern OCTAVE_API void
-oct_fill_randp (double L, octave_idx_type n, double *p);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_poisson<double>' instead")
+inline double
+oct_randp (double L)
+{
+  return octave::rand_poisson (L);
+}
 
-extern OCTAVE_API float
-oct_float_randp (float L);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_poisson<double>' instead")
+inline void
+oct_fill_randp (double L, octave_idx_type n, double *p)
+{
+  octave::rand_poisson (L, n, p);
+}
 
-extern OCTAVE_API void
-oct_fill_float_randp (float L, octave_idx_type n, float *p);
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_poisson<float>' instead")
+inline float
+oct_float_randp (float L)
+{
+  return octave::rand_poisson (L);
+}
+
+OCTAVE_DEPRECATED (4.4, "use 'octave::rand_poisson<float>' instead")
+inline void
+oct_fill_float_randp (float L, octave_idx_type n, float *p)
+{
+  octave::rand_poisson (L, n, p);
+}
 
 #endif
--- a/liboctave/numeric/sparse-chol.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/sparse-chol.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -102,7 +102,7 @@
       octave_idx_type P (void) const
       {
 #if defined (HAVE_CHOLMOD)
-        return (minor_p == static_cast<octave_idx_type>(Lsparse->ncol) ?
+        return (minor_p == static_cast<octave_idx_type> (Lsparse->ncol) ?
                 0 : minor_p + 1);
 #else
         return 0;
@@ -374,7 +374,7 @@
       for (octave_idx_type i = 0; i < n; i++)
         {
           p.xcidx (i) = i;
-          p.xridx (i) = static_cast<octave_idx_type>(perms (i));
+          p.xridx (i) = static_cast<octave_idx_type> (perms (i));
           p.xdata (i) = 1;
         }
 
--- a/liboctave/numeric/sparse-chol.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/sparse-chol.h	Thu Dec 20 17:18:56 2018 -0500
@@ -27,6 +27,8 @@
 
 #include "octave-config.h"
 
+#include "CSparse.h"
+
 class RowVector;
 class SparseMatrix;
 class SparseComplexMatrix;
--- a/liboctave/numeric/sparse-qr.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/numeric/sparse-qr.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,8 @@
 
 #include "octave-config.h"
 
+#include "oct-cmplx.h"
+
 class Matrix;
 class ComplexMatrix;
 class SparseComplexMatrix;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/octave.in.pc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,9 @@
+Name: @PACKAGE_NAME@
+Description: C++ interface to GNU Octave underlying library.
+URL: https://www.octave.org
+Version: @PACKAGE_VERSION@
+Requires:
+Requires.private:
+Libs: -L@octlibdir@ @LIBOCTAVE@
+Libs.private: @LIBOCTAVE_LINK_DEPS@
+Cflags: -I@octincludedir@/..
--- a/liboctave/operators/Sparse-op-defs.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/Sparse-op-defs.h	Thu Dec 20 17:18:56 2018 -0500
@@ -77,7 +77,7 @@
   SPARSE_SMS_BIN_OP_2 (R2, operator *, *, M, S) \
   SPARSE_SMS_BIN_OP_2 (R2, operator /, /, M, S)
 
-#define SPARSE_SMS_CMP_OP(F, OP, M, MZ, MC, S, SZ, SC)                  \
+#define SPARSE_SMS_CMP_OP(F, OP, M, S)                                  \
   SparseBoolMatrix                                                      \
   F (const M& m, const S& s)                                            \
   {                                                                     \
@@ -85,12 +85,14 @@
     octave_idx_type nc = m.cols ();                                     \
     SparseBoolMatrix r;                                                 \
                                                                         \
-    if (MC (MZ) OP SC (s))                                              \
+    M::element_type m_zero = M::element_type ();                        \
+                                                                        \
+    if (m_zero OP s)                                                    \
       {                                                                 \
         r = SparseBoolMatrix (nr, nc, true);                            \
         for (octave_idx_type j = 0; j < nc; j++)                        \
           for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)   \
-            if (! (MC (m.data (i)) OP SC (s)))                          \
+            if (! (m.data (i) OP s))                                    \
               r.data (m.ridx (i) + j * nr) = false;                     \
         r.maybe_compress (true);                                        \
       }                                                                 \
@@ -102,7 +104,7 @@
         for (octave_idx_type j = 0; j < nc; j++)                        \
           {                                                             \
             for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-              if (MC (m.data (i)) OP SC (s))                            \
+              if (m.data (i) OP s)                                      \
                 {                                                       \
                   r.ridx (nel) = m.ridx (i);                            \
                   r.data (nel++) = true;                                \
@@ -114,37 +116,33 @@
     return r;                                                           \
   }
 
-#define SPARSE_SMS_CMP_OPS(M, MZ, CM, S, SZ, CS)                \
-  SPARSE_SMS_CMP_OP (mx_el_lt, <,  M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_le, <=, M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_ge, >=, M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_gt, >,  M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ,   , S, SZ,   )
+#define SPARSE_SMS_CMP_OPS(M, S)                \
+  SPARSE_SMS_CMP_OP (mx_el_lt, <,  M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_le, <=, M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_ge, >=, M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_gt, >,  M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, S)
 
-#define SPARSE_SMS_EQNE_OPS(M, MZ, CM, S, SZ, CS)               \
-  SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ,   , S, SZ,   )        \
-  SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ,   , S, SZ,   )
+#define SPARSE_SMS_EQNE_OPS(M, S)               \
+  SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, S)        \
+  SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, S)
 
-#define SPARSE_SMS_BOOL_OP(F, OP, M, S, LHS_ZERO, RHS_ZERO)             \
+#define SPARSE_SMS_BOOL_OR_OP(M, S)                                     \
   SparseBoolMatrix                                                      \
-  F (const M& m, const S& s)                                            \
+  mx_el_or (const M& m, const S& s)                                     \
   {                                                                     \
     octave_idx_type nr = m.rows ();                                     \
     octave_idx_type nc = m.cols ();                                     \
     SparseBoolMatrix r;                                                 \
                                                                         \
+    M::element_type lhs_zero = M::element_type ();                      \
+    S rhs_zero = S ();                                                  \
+                                                                        \
     if (nr > 0 && nc > 0)                                               \
       {                                                                 \
-        if (LHS_ZERO OP (s != RHS_ZERO))                                \
-          {                                                             \
-            r = SparseBoolMatrix (nr, nc, true);                        \
-            for (octave_idx_type j = 0; j < nc; j++)                    \
-              for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-                if (! ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO)))    \
-                  r.data (m.ridx (i) + j * nr) = false;                 \
-            r.maybe_compress (true);                                    \
-          }                                                             \
+        if (s != rhs_zero)                                              \
+          r = SparseBoolMatrix (nr, nc, true);                          \
         else                                                            \
           {                                                             \
             r = SparseBoolMatrix (nr, nc, m.nnz ());                    \
@@ -153,7 +151,7 @@
             for (octave_idx_type j = 0; j < nc; j++)                    \
               {                                                         \
                 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-                  if ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO))      \
+                  if (m.data (i) != lhs_zero)                           \
                     {                                                   \
                       r.ridx (nel) = m.ridx (i);                        \
                       r.data (nel++) = true;                            \
@@ -166,12 +164,45 @@
     return r;                                                           \
   }
 
-#define SPARSE_SMS_BOOL_OPS2(M, S, LHS_ZERO, RHS_ZERO)          \
-  SPARSE_SMS_BOOL_OP (mx_el_and, &&, M, S, LHS_ZERO, RHS_ZERO)  \
-  SPARSE_SMS_BOOL_OP (mx_el_or,  ||, M, S, LHS_ZERO, RHS_ZERO)
+#define SPARSE_SMS_BOOL_AND_OP(M, S)                                    \
+  SparseBoolMatrix                                                      \
+  mx_el_and (const M& m, const S& s)                                    \
+  {                                                                     \
+    octave_idx_type nr = m.rows ();                                     \
+    octave_idx_type nc = m.cols ();                                     \
+    SparseBoolMatrix r;                                                 \
+                                                                        \
+    M::element_type lhs_zero = M::element_type ();                      \
+    S rhs_zero = S ();                                                  \
+                                                                        \
+    if (nr > 0 && nc > 0)                                               \
+      {                                                                 \
+        if (s != rhs_zero)                                              \
+          {                                                             \
+            r = SparseBoolMatrix (nr, nc, m.nnz ());                    \
+            r.cidx (0) = static_cast<octave_idx_type> (0);              \
+            octave_idx_type nel = 0;                                    \
+            for (octave_idx_type j = 0; j < nc; j++)                    \
+              {                                                         \
+                for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
+                  if (m.data (i) != lhs_zero)                           \
+                    {                                                   \
+                      r.ridx (nel) = m.ridx (i);                        \
+                      r.data (nel++) = true;                            \
+                    }                                                   \
+                r.cidx (j + 1) = nel;                                   \
+              }                                                         \
+            r.maybe_compress (false);                                   \
+          }                                                             \
+        else                                                            \
+          r = SparseBoolMatrix (nr, nc);                                \
+      }                                                                 \
+    return r;                                                           \
+  }
 
-#define SPARSE_SMS_BOOL_OPS(M, S, ZERO)         \
-  SPARSE_SMS_BOOL_OPS2(M, S, ZERO, ZERO)
+#define SPARSE_SMS_BOOL_OPS(M, S)               \
+  SPARSE_SMS_BOOL_AND_OP (M, S)                 \
+  SPARSE_SMS_BOOL_OR_OP (M, S)
 
 // scalar by sparse matrix operations.
 
@@ -219,7 +250,7 @@
   SPARSE_SSM_BIN_OP_2 (R2, operator *, *, S, M) \
   SPARSE_SSM_BIN_OP_2 (R2, operator /, /, S, M)
 
-#define SPARSE_SSM_CMP_OP(F, OP, S, SZ, SC, M, MZ, MC)                  \
+#define SPARSE_SSM_CMP_OP(F, OP, S, M)                                  \
   SparseBoolMatrix                                                      \
   F (const S& s, const M& m)                                            \
   {                                                                     \
@@ -227,12 +258,14 @@
     octave_idx_type nc = m.cols ();                                     \
     SparseBoolMatrix r;                                                 \
                                                                         \
-    if (SC (s) OP SC (MZ))                                              \
+    M::element_type m_zero = M::element_type ();                        \
+                                                                        \
+    if (s OP m_zero)                                                    \
       {                                                                 \
         r = SparseBoolMatrix (nr, nc, true);                            \
         for (octave_idx_type j = 0; j < nc; j++)                        \
           for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)   \
-            if (! (SC (s) OP MC (m.data (i))))                          \
+            if (! (s OP m.data (i)))                                    \
               r.data (m.ridx (i) + j * nr) = false;                     \
         r.maybe_compress (true);                                        \
       }                                                                 \
@@ -244,7 +277,7 @@
         for (octave_idx_type j = 0; j < nc; j++)                        \
           {                                                             \
             for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-              if (SC (s) OP MC (m.data (i)))                            \
+              if (s OP m.data (i))                                      \
                 {                                                       \
                   r.ridx (nel) = m.ridx (i);                            \
                   r.data (nel++) = true;                                \
@@ -256,37 +289,33 @@
     return r;                                                           \
   }
 
-#define SPARSE_SSM_CMP_OPS(S, SZ, SC, M, MZ, MC)                \
-  SPARSE_SSM_CMP_OP (mx_el_lt, <,  S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_le, <=, S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_ge, >=, S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_gt, >,  S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ,   , M, MZ,   )
+#define SPARSE_SSM_CMP_OPS(S, M)                \
+  SPARSE_SSM_CMP_OP (mx_el_lt, <,  S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_le, <=, S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_ge, >=, S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_gt, >,  S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, M)
 
-#define SPARSE_SSM_EQNE_OPS(S, SZ, SC, M, MZ, MC)               \
-  SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ,   , M, MZ,   )        \
-  SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ,   , M, MZ,   )
+#define SPARSE_SSM_EQNE_OPS(S, M)               \
+  SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, M)        \
+  SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, M)
 
-#define SPARSE_SSM_BOOL_OP(F, OP, S, M, LHS_ZERO, RHS_ZERO)             \
+#define SPARSE_SSM_BOOL_OR_OP(S, M)                                     \
   SparseBoolMatrix                                                      \
-  F (const S& s, const M& m)                                            \
+  mx_el_or (const S& s, const M& m)                                     \
   {                                                                     \
     octave_idx_type nr = m.rows ();                                     \
     octave_idx_type nc = m.cols ();                                     \
     SparseBoolMatrix r;                                                 \
                                                                         \
+    S lhs_zero = S ();                                                  \
+    M::element_type rhs_zero = M::element_type ();                      \
+                                                                        \
     if (nr > 0 && nc > 0)                                               \
       {                                                                 \
-        if ((s != LHS_ZERO) OP RHS_ZERO)                                \
-          {                                                             \
-            r = SparseBoolMatrix (nr, nc, true);                        \
-            for (octave_idx_type j = 0; j < nc; j++)                    \
-              for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-                if (! ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO)))    \
-                  r.data (m.ridx (i) + j * nr) = false;                 \
-            r.maybe_compress (true);                                    \
-          }                                                             \
+        if (s != lhs_zero)                                              \
+          r = SparseBoolMatrix (nr, nc, true);                          \
         else                                                            \
           {                                                             \
             r = SparseBoolMatrix (nr, nc, m.nnz ());                    \
@@ -295,7 +324,7 @@
             for (octave_idx_type j = 0; j < nc; j++)                    \
               {                                                         \
                 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
-                  if ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO))      \
+                  if (m.data (i) != rhs_zero)                           \
                     {                                                   \
                       r.ridx (nel) = m.ridx (i);                        \
                       r.data (nel++) = true;                            \
@@ -308,12 +337,45 @@
     return r;                                                           \
   }
 
-#define SPARSE_SSM_BOOL_OPS2(S, M, LHS_ZERO, RHS_ZERO)          \
-  SPARSE_SSM_BOOL_OP (mx_el_and, &&, S, M, LHS_ZERO, RHS_ZERO)  \
-  SPARSE_SSM_BOOL_OP (mx_el_or,  ||, S, M, LHS_ZERO, RHS_ZERO)
+#define SPARSE_SSM_BOOL_AND_OP(S, M)                                    \
+  SparseBoolMatrix                                                      \
+  mx_el_and (const S& s, const M& m)                                    \
+  {                                                                     \
+    octave_idx_type nr = m.rows ();                                     \
+    octave_idx_type nc = m.cols ();                                     \
+    SparseBoolMatrix r;                                                 \
+                                                                        \
+    S lhs_zero = S ();                                                  \
+    M::element_type rhs_zero = M::element_type ();                      \
+                                                                        \
+    if (nr > 0 && nc > 0)                                               \
+      {                                                                 \
+        if (s != lhs_zero)                                              \
+          {                                                             \
+            r = SparseBoolMatrix (nr, nc, m.nnz ());                    \
+            r.cidx (0) = static_cast<octave_idx_type> (0);              \
+            octave_idx_type nel = 0;                                    \
+            for (octave_idx_type j = 0; j < nc; j++)                    \
+              {                                                         \
+                for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
+                  if (m.data (i) != rhs_zero)                           \
+                    {                                                   \
+                      r.ridx (nel) = m.ridx (i);                        \
+                      r.data (nel++) = true;                            \
+                    }                                                   \
+                r.cidx (j + 1) = nel;                                   \
+              }                                                         \
+            r.maybe_compress (false);                                   \
+          }                                                             \
+        else                                                            \
+          r = SparseBoolMatrix (nr, nc);                                \
+      }                                                                 \
+    return r;                                                           \
+  }
 
-#define SPARSE_SSM_BOOL_OPS(S, M, ZERO)         \
-  SPARSE_SSM_BOOL_OPS2(S, M, ZERO, ZERO)
+#define SPARSE_SSM_BOOL_OPS(S, M)               \
+  SPARSE_SSM_BOOL_AND_OP (S, M)                 \
+  SPARSE_SSM_BOOL_OR_OP (S, M)
 
 // sparse matrix by sparse matrix operations.
 
@@ -660,7 +722,7 @@
 // FIXME: this macro duplicates the bodies of the template functions
 // defined in the SPARSE_SSM_CMP_OP and SPARSE_SMS_CMP_OP macros.
 
-#define SPARSE_SMSM_CMP_OP(F, OP, M1, Z1, C1, M2, Z2, C2)               \
+#define SPARSE_SMSM_CMP_OP(F, OP, M1, M2)                               \
   SparseBoolMatrix                                                      \
   F (const M1& m1, const M2& m2)                                        \
   {                                                                     \
@@ -672,14 +734,17 @@
     octave_idx_type m2_nr = m2.rows ();                                 \
     octave_idx_type m2_nc = m2.cols ();                                 \
                                                                         \
+    M1::element_type Z1 = M1::element_type ();                          \
+    M2::element_type Z2 = M2::element_type ();                          \
+                                                                        \
     if (m1_nr == 1 && m1_nc == 1)                                       \
       {                                                                 \
-        if (C1 (m1.elem (0,0)) OP C2 (Z2))                              \
+        if (m1.elem (0,0) OP Z2)                                        \
           {                                                             \
             r = SparseBoolMatrix (m2_nr, m2_nc, true);                  \
             for (octave_idx_type j = 0; j < m2_nc; j++)                 \
               for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
-                if (! (C1 (m1.elem (0,0)) OP C2 (m2.data (i))))         \
+                if (! (m1.elem (0,0) OP m2.data (i)))                   \
                   r.data (m2.ridx (i) + j * m2_nr) = false;             \
             r.maybe_compress (true);                                    \
           }                                                             \
@@ -691,7 +756,7 @@
             for (octave_idx_type j = 0; j < m2_nc; j++)                 \
               {                                                         \
                 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
-                  if (C1 (m1.elem (0,0)) OP C2 (m2.data (i)))           \
+                  if (m1.elem (0,0) OP m2.data (i))                     \
                     {                                                   \
                       r.ridx (nel) = m2.ridx (i);                       \
                       r.data (nel++) = true;                            \
@@ -703,12 +768,12 @@
       }                                                                 \
     else if (m2_nr == 1 && m2_nc == 1)                                  \
       {                                                                 \
-        if (C1 (Z1) OP C2 (m2.elem (0,0)))                              \
+        if (Z1 OP m2.elem (0,0))                                        \
           {                                                             \
             r = SparseBoolMatrix (m1_nr, m1_nc, true);                  \
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
-                if (! (C1 (m1.data (i)) OP C2 (m2.elem (0,0))))         \
+                if (! (m1.data (i) OP m2.elem (0,0)))                   \
                   r.data (m1.ridx (i) + j * m1_nr) = false;             \
             r.maybe_compress (true);                                    \
           }                                                             \
@@ -720,7 +785,7 @@
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               {                                                         \
                 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
-                  if (C1 (m1.data (i)) OP C2 (m2.elem (0,0)))           \
+                  if (m1.data (i) OP m2.elem (0,0))                     \
                     {                                                   \
                       r.ridx (nel) = m1.ridx (i);                       \
                       r.data (nel++) = true;                            \
@@ -734,7 +799,7 @@
       {                                                                 \
         if (m1_nr != 0 || m1_nc != 0)                                   \
           {                                                             \
-            if (C1 (Z1) OP C2 (Z2))                                     \
+            if (Z1 OP Z2)                                               \
               {                                                         \
                 r = SparseBoolMatrix (m1_nr, m1_nc, true);              \
                 for (octave_idx_type j = 0; j < m1_nc; j++)             \
@@ -747,19 +812,19 @@
                       {                                                 \
                         if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
                           {                                             \
-                            if (! (C1 (Z1) OP C2 (m2.data (i2))))       \
+                            if (! (Z1 OP m2.data (i2)))                 \
                               r.data (m2.ridx (i2) + j * m1_nr) = false; \
                             i2++;                                       \
                           }                                             \
                         else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \
                           {                                             \
-                            if (! (C1 (m1.data (i1)) OP C2 (Z2)))       \
+                            if (! (m1.data (i1) OP Z2))                 \
                               r.data (m1.ridx (i1) + j * m1_nr) = false; \
                             i1++;                                       \
                           }                                             \
                         else                                            \
                           {                                             \
-                            if (! (C1 (m1.data (i1)) OP C2 (m2.data (i2)))) \
+                            if (! (m1.data (i1) OP m2.data (i2)))       \
                               r.data (m1.ridx (i1) + j * m1_nr) = false; \
                             i1++;                                       \
                             i2++;                                       \
@@ -783,7 +848,7 @@
                       {                                                 \
                         if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
                           {                                             \
-                            if (C1 (Z1) OP C2 (m2.data (i2)))           \
+                            if (Z1 OP m2.data (i2))                     \
                               {                                         \
                                 r.ridx (nel) = m2.ridx (i2);            \
                                 r.data (nel++) = true;                  \
@@ -792,7 +857,7 @@
                           }                                             \
                         else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \
                           {                                             \
-                            if (C1 (m1.data (i1)) OP C2 (Z2))           \
+                            if (m1.data (i1) OP Z2)                     \
                               {                                         \
                                 r.ridx (nel) = m1.ridx (i1);            \
                                 r.data (nel++) = true;                  \
@@ -801,7 +866,7 @@
                           }                                             \
                         else                                            \
                           {                                             \
-                            if (C1 (m1.data (i1)) OP C2 (m2.data (i2))) \
+                            if (m1.data (i1) OP m2.data (i2))           \
                               {                                         \
                                 r.ridx (nel) = m1.ridx (i1);            \
                                 r.data (nel++) = true;                  \
@@ -824,24 +889,23 @@
     return r;                                                           \
   }
 
-#define SPARSE_SMSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2)             \
-  SPARSE_SMSM_CMP_OP (mx_el_lt, <,  M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_le, <=, M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_ge, >=, M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_gt, >,  M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1,   , M2, Z2,   )
+#define SPARSE_SMSM_CMP_OPS(M1, M2)             \
+  SPARSE_SMSM_CMP_OP (mx_el_lt, <,  M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_le, <=, M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_ge, >=, M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_gt, >,  M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-#define SPARSE_SMSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2)            \
-  SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1,   , M2, Z2,   )     \
-  SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1,   , M2, Z2,   )
+#define SPARSE_SMSM_EQNE_OPS(M1, M2)            \
+  SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, M2)     \
+  SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-// FIXME: this macro duplicates the bodies of the template functions
-// defined in the SPARSE_SSM_BOOL_OP and SPARSE_SMS_BOOL_OP macros.
-
-#define SPARSE_SMSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO)          \
+#define SPARSE_SMSM_BOOL_AND_OP(M1, M2)                                 \
+  extern SparseBoolMatrix mx_el_and (const M1&, const M2::element_type&); \
+  extern SparseBoolMatrix mx_el_and (const M1::element_type&, const M2&); \
   SparseBoolMatrix                                                      \
-  F (const M1& m1, const M2& m2)                                        \
+  mx_el_and (const M1& m1, const M2& m2)                                \
   {                                                                     \
     SparseBoolMatrix r;                                                 \
                                                                         \
@@ -851,70 +915,77 @@
     octave_idx_type m2_nr = m2.rows ();                                 \
     octave_idx_type m2_nc = m2.cols ();                                 \
                                                                         \
+    M1::element_type lhs_zero = M1::element_type ();                    \
+    M2::element_type rhs_zero = M2::element_type ();                    \
+                                                                        \
     if (m1_nr == 1 && m1_nc == 1)                                       \
+      return mx_el_and (m1.elem (0,0), m2);                             \
+    else if (m2_nr == 1 && m2_nc == 1)                                  \
+      return mx_el_and (m1, m2.elem (0,0));                             \
+    else if (m1_nr == m2_nr && m1_nc == m2_nc)                          \
       {                                                                 \
-        if (m2_nr > 0 && m2_nc > 0)                                     \
+        if (m1_nr != 0 || m1_nc != 0)                                   \
           {                                                             \
-            if ((m1.elem (0,0) != LHS_ZERO) OP RHS_ZERO)                \
-              {                                                         \
-                r = SparseBoolMatrix (m2_nr, m2_nc, true);              \
-                for (octave_idx_type j = 0; j < m2_nc; j++)             \
-                  for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
-                    if (! ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO))) \
-                      r.data (m2.ridx (i) + j * m2_nr) = false;         \
-                r.maybe_compress (true);                                \
-              }                                                         \
-            else                                                        \
+            r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz () + m2.nnz ()); \
+            r.cidx (0) = static_cast<octave_idx_type> (0);              \
+            octave_idx_type nel = 0;                                    \
+            for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               {                                                         \
-                r = SparseBoolMatrix (m2_nr, m2_nc, m2.nnz ());         \
-                r.cidx (0) = static_cast<octave_idx_type> (0);          \
-                octave_idx_type nel = 0;                                \
-                for (octave_idx_type j = 0; j < m2_nc; j++)             \
+                octave_idx_type i1 = m1.cidx (j);                       \
+                octave_idx_type e1 = m1.cidx (j+1);                     \
+                octave_idx_type i2 = m2.cidx (j);                       \
+                octave_idx_type e2 = m2.cidx (j+1);                     \
+                while (i1 < e1 || i2 < e2)                              \
                   {                                                     \
-                    for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
-                      if ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO)) \
-                        {                                               \
-                          r.ridx (nel) = m2.ridx (i);                   \
-                          r.data (nel++) = true;                        \
-                        }                                               \
-                    r.cidx (j + 1) = nel;                               \
+                    if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
+                      i2++;                                             \
+                    else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2))   \
+                      i1++;                                             \
+                    else                                                \
+                      {                                                 \
+                        if (m1.data (i1) != lhs_zero && m2.data (i2) != rhs_zero) \
+                          {                                             \
+                            r.ridx (nel) = m1.ridx (i1);                \
+                            r.data (nel++) = true;                      \
+                          }                                             \
+                        i1++;                                           \
+                        i2++;                                           \
+                      }                                                 \
                   }                                                     \
-                r.maybe_compress (false);                               \
+                r.cidx (j + 1) = nel;                                   \
               }                                                         \
+            r.maybe_compress (false);                                   \
           }                                                             \
       }                                                                 \
-    else if (m2_nr == 1 && m2_nc == 1)                                  \
+    else                                                                \
       {                                                                 \
-        if (m1_nr > 0 && m1_nc > 0)                                     \
-          {                                                             \
-            if (LHS_ZERO OP (m2.elem (0,0) != RHS_ZERO))                \
-              {                                                         \
-                r = SparseBoolMatrix (m1_nr, m1_nc, true);              \
-                for (octave_idx_type j = 0; j < m1_nc; j++)             \
-                  for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
-                    if (! ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO))) \
-                      r.data (m1.ridx (i) + j * m1_nr) = false;         \
-                r.maybe_compress (true);                                \
-              }                                                         \
-            else                                                        \
-              {                                                         \
-                r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz ());         \
-                r.cidx (0) = static_cast<octave_idx_type> (0);          \
-                octave_idx_type nel = 0;                                \
-                for (octave_idx_type j = 0; j < m1_nc; j++)             \
-                  {                                                     \
-                    for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
-                      if ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO)) \
-                        {                                               \
-                          r.ridx (nel) = m1.ridx (i);                   \
-                          r.data (nel++) = true;                        \
-                        }                                               \
-                    r.cidx (j + 1) = nel;                               \
-                  }                                                     \
-                r.maybe_compress (false);                               \
-              }                                                         \
-          }                                                             \
+        if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0))   \
+          octave::err_nonconformant ("mx_el_and_", m1_nr, m1_nc, m2_nr, m2_nc); \
       }                                                                 \
+    return r;                                                           \
+  }
+
+#define SPARSE_SMSM_BOOL_OR_OP(M1, M2)                                  \
+  extern SparseBoolMatrix mx_el_or (const M1&, const M2::element_type&); \
+  extern SparseBoolMatrix mx_el_or (const M1::element_type&, const M2&); \
+  SparseBoolMatrix                                                      \
+  mx_el_or (const M1& m1, const M2& m2)                                 \
+  {                                                                     \
+    SparseBoolMatrix r;                                                 \
+                                                                        \
+    octave_idx_type m1_nr = m1.rows ();                                 \
+    octave_idx_type m1_nc = m1.cols ();                                 \
+                                                                        \
+    octave_idx_type m2_nr = m2.rows ();                                 \
+    octave_idx_type m2_nc = m2.cols ();                                 \
+                                                                        \
+    M1::element_type lhs_zero = M1::element_type ();                    \
+    M2::element_type rhs_zero = M2::element_type ();                    \
+                                                                        \
+    if (m1_nr == 1 && m1_nc == 1)                                       \
+      return mx_el_or (m1.elem (0,0), m2);                              \
+    else if (m2_nr == 1 && m2_nc == 1)                                  \
+      return mx_el_or (m1, m2.elem (0,0));                              \
     else if (m1_nr == m2_nr && m1_nc == m2_nc)                          \
       {                                                                 \
         if (m1_nr != 0 || m1_nc != 0)                                   \
@@ -932,7 +1003,7 @@
                   {                                                     \
                     if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
                       {                                                 \
-                        if (LHS_ZERO OP m2.data (i2) != RHS_ZERO)       \
+                        if (m2.data (i2) != rhs_zero)                   \
                           {                                             \
                             r.ridx (nel) = m2.ridx (i2);                \
                             r.data (nel++) = true;                      \
@@ -941,7 +1012,7 @@
                       }                                                 \
                     else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2))   \
                       {                                                 \
-                        if (m1.data (i1) != LHS_ZERO OP RHS_ZERO)       \
+                        if (m1.data (i1) != lhs_zero)                   \
                           {                                             \
                             r.ridx (nel) = m1.ridx (i1);                \
                             r.data (nel++) = true;                      \
@@ -950,7 +1021,7 @@
                       }                                                 \
                     else                                                \
                       {                                                 \
-                        if (m1.data (i1) != LHS_ZERO OP m2.data (i2) != RHS_ZERO) \
+                        if (m1.data (i1) != lhs_zero || m2.data (i2) != rhs_zero) \
                           {                                             \
                             r.ridx (nel) = m1.ridx (i1);                \
                             r.data (nel++) = true;                      \
@@ -967,17 +1038,14 @@
     else                                                                \
       {                                                                 \
         if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0))   \
-          octave::err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc);           \
+          octave::err_nonconformant ("mx_el_or", m1_nr, m1_nc, m2_nr, m2_nc); \
       }                                                                 \
     return r;                                                           \
   }
 
-#define SPARSE_SMSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO)               \
-  SPARSE_SMSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO)       \
-  SPARSE_SMSM_BOOL_OP (mx_el_or,  ||, M1, M2, LHS_ZERO, RHS_ZERO)
-
-#define SPARSE_SMSM_BOOL_OPS(M1, M2, ZERO)      \
-  SPARSE_SMSM_BOOL_OPS2(M1, M2, ZERO, ZERO)
+#define SPARSE_SMSM_BOOL_OPS(M1, M2)            \
+  SPARSE_SMSM_BOOL_AND_OP (M1, M2)              \
+  SPARSE_SMSM_BOOL_OR_OP (M1, M2)
 
 // matrix by sparse matrix operations.
 
@@ -1053,14 +1121,13 @@
     return r;                                                           \
   }
 
-// FIXME: Pass a specific ZERO value
 #define SPARSE_MSM_BIN_OPS(R1, R2, M1, M2)              \
   SPARSE_MSM_BIN_OP_1 (R1, operator +,  +, M1, M2)      \
   SPARSE_MSM_BIN_OP_1 (R1, operator -,  -, M1, M2)      \
   SPARSE_MSM_BIN_OP_2 (R2, product,     *, M1, M2)      \
   SPARSE_MSM_BIN_OP_1 (R2, quotient,    /, M1, M2)
 
-#define SPARSE_MSM_CMP_OP(F, OP, M1, C1, M2, C2)                        \
+#define SPARSE_MSM_CMP_OP(F, OP, M1, M2)                                \
   SparseBoolMatrix                                                      \
   F (const M1& m1, const M2& m2)                                        \
   {                                                                     \
@@ -1082,7 +1149,7 @@
             octave_idx_type nel = 0;                                    \
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               for (octave_idx_type i = 0; i < m1_nr; i++)               \
-                if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)))         \
+                if (m1.elem (i, j) OP m2.elem (i, j))                   \
                   nel++;                                                \
                                                                         \
             r = SparseBoolMatrix (m1_nr, m1_nc, nel);                   \
@@ -1093,7 +1160,7 @@
               {                                                         \
                 for (octave_idx_type i = 0; i < m1_nr; i++)             \
                   {                                                     \
-                    bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \
+                    bool el = m1.elem (i, j) OP m2.elem (i, j);         \
                     if (el)                                             \
                       {                                                 \
                         r.data (ii) = el;                               \
@@ -1112,19 +1179,19 @@
     return r;                                                           \
   }
 
-#define SPARSE_MSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2)      \
-  SPARSE_MSM_CMP_OP (mx_el_lt, <,  M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_le, <=, M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_ge, >=, M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_gt, >,  M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1,   , M2,   )
+#define SPARSE_MSM_CMP_OPS(M1, M2)              \
+  SPARSE_MSM_CMP_OP (mx_el_lt, <,  M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_le, <=, M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_ge, >=, M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_gt, >,  M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-#define SPARSE_MSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2)     \
-  SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1,   , M2,   )      \
-  SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1,   , M2,   )
+#define SPARSE_MSM_EQNE_OPS(M1, M2)             \
+  SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, M2)      \
+  SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-#define SPARSE_MSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO)           \
+#define SPARSE_MSM_BOOL_OP(F, OP, M1, M2)                               \
   SparseBoolMatrix                                                      \
   F (const M1& m1, const M2& m2)                                        \
   {                                                                     \
@@ -1136,6 +1203,9 @@
     octave_idx_type m2_nr = m2.rows ();                                 \
     octave_idx_type m2_nc = m2.cols ();                                 \
                                                                         \
+    M1::element_type lhs_zero = M1::element_type ();                    \
+    M2::element_type rhs_zero = M2::element_type ();                    \
+                                                                        \
     if (m2_nr == 1 && m2_nc == 1)                                       \
       r = SparseBoolMatrix (F (m1, m2.elem (0,0)));                     \
     else if (m1_nr == m2_nr && m1_nc == m2_nc)                          \
@@ -1146,8 +1216,8 @@
             octave_idx_type nel = 0;                                    \
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               for (octave_idx_type i = 0; i < m1_nr; i++)               \
-                if ((m1.elem (i, j) != LHS_ZERO)                        \
-                    OP (m2.elem (i, j) != RHS_ZERO))                    \
+                if ((m1.elem (i, j) != lhs_zero)                        \
+                    OP (m2.elem (i, j) != rhs_zero))                    \
                   nel++;                                                \
                                                                         \
             r = SparseBoolMatrix (m1_nr, m1_nc, nel);                   \
@@ -1158,8 +1228,8 @@
               {                                                         \
                 for (octave_idx_type i = 0; i < m1_nr; i++)             \
                   {                                                     \
-                    bool el = (m1.elem (i, j) != LHS_ZERO)              \
-                      OP (m2.elem (i, j) != RHS_ZERO);                  \
+                    bool el = (m1.elem (i, j) != lhs_zero)              \
+                      OP (m2.elem (i, j) != rhs_zero);                  \
                     if (el)                                             \
                       {                                                 \
                         r.data (ii) = el;                               \
@@ -1178,12 +1248,9 @@
     return r;                                                           \
   }
 
-#define SPARSE_MSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO)                \
-  SPARSE_MSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO)        \
-  SPARSE_MSM_BOOL_OP (mx_el_or,  ||, M1, M2, LHS_ZERO, RHS_ZERO)
-
-#define SPARSE_MSM_BOOL_OPS(M1, M2, ZERO)       \
-  SPARSE_MSM_BOOL_OPS2(M1, M2, ZERO, ZERO)
+#define SPARSE_MSM_BOOL_OPS(M1, M2)             \
+  SPARSE_MSM_BOOL_OP (mx_el_and, &&, M1, M2)    \
+  SPARSE_MSM_BOOL_OP (mx_el_or,  ||, M1, M2)
 
 // sparse matrix by matrix operations.
 
@@ -1273,7 +1340,7 @@
   SPARSE_SMM_BIN_OP_2 (R2, product,     *, M1, M2)      \
   SPARSE_SMM_BIN_OP_2 (R2, quotient,    /, M1, M2)
 
-#define SPARSE_SMM_CMP_OP(F, OP, M1, C1, M2, C2)                        \
+#define SPARSE_SMM_CMP_OP(F, OP, M1, M2)                                \
   SparseBoolMatrix                                                      \
   F (const M1& m1, const M2& m2)                                        \
   {                                                                     \
@@ -1295,7 +1362,7 @@
             octave_idx_type nel = 0;                                    \
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               for (octave_idx_type i = 0; i < m1_nr; i++)               \
-                if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)))         \
+                if (m1.elem (i, j) OP m2.elem (i, j))                   \
                   nel++;                                                \
                                                                         \
             r = SparseBoolMatrix (m1_nr, m1_nc, nel);                   \
@@ -1306,7 +1373,7 @@
               {                                                         \
                 for (octave_idx_type i = 0; i < m1_nr; i++)             \
                   {                                                     \
-                    bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \
+                    bool el = m1.elem (i, j) OP m2.elem (i, j);         \
                     if (el)                                             \
                       {                                                 \
                         r.data (ii) = el;                               \
@@ -1325,19 +1392,19 @@
     return r;                                                           \
   }
 
-#define SPARSE_SMM_CMP_OPS(M1, Z1, C1, M2, Z2, C2)      \
-  SPARSE_SMM_CMP_OP (mx_el_lt, <,  M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_le, <=, M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_ge, >=, M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_gt, >,  M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1,   , M2,   )
+#define SPARSE_SMM_CMP_OPS(M1, M2)              \
+  SPARSE_SMM_CMP_OP (mx_el_lt, <,  M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_le, <=, M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_ge, >=, M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_gt, >,  M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-#define SPARSE_SMM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2)     \
-  SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1,   , M2,   )      \
-  SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1,   , M2,   )
+#define SPARSE_SMM_EQNE_OPS(M1, M2)             \
+  SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, M2)      \
+  SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, M2)
 
-#define SPARSE_SMM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO)           \
+#define SPARSE_SMM_BOOL_OP(F, OP, M1, M2)                               \
   SparseBoolMatrix                                                      \
   F (const M1& m1, const M2& m2)                                        \
   {                                                                     \
@@ -1349,6 +1416,9 @@
     octave_idx_type m2_nr = m2.rows ();                                 \
     octave_idx_type m2_nc = m2.cols ();                                 \
                                                                         \
+    M1::element_type lhs_zero = M1::element_type ();                    \
+    M2::element_type rhs_zero = M2::element_type ();                    \
+                                                                        \
     if (m1_nr == 1 && m1_nc == 1)                                       \
       r = SparseBoolMatrix (F (m1.elem (0,0), m2));                     \
     else if (m1_nr == m2_nr && m1_nc == m2_nc)                          \
@@ -1359,8 +1429,8 @@
             octave_idx_type nel = 0;                                    \
             for (octave_idx_type j = 0; j < m1_nc; j++)                 \
               for (octave_idx_type i = 0; i < m1_nr; i++)               \
-                if ((m1.elem (i, j) != LHS_ZERO)                        \
-                    OP (m2.elem (i, j) != RHS_ZERO))                    \
+                if ((m1.elem (i, j) != lhs_zero)                        \
+                    OP (m2.elem (i, j) != rhs_zero))                    \
                   nel++;                                                \
                                                                         \
             r = SparseBoolMatrix (m1_nr, m1_nc, nel);                   \
@@ -1371,8 +1441,8 @@
               {                                                         \
                 for (octave_idx_type i = 0; i < m1_nr; i++)             \
                   {                                                     \
-                    bool el = (m1.elem (i, j) != LHS_ZERO)              \
-                      OP (m2.elem (i, j) != RHS_ZERO);                  \
+                    bool el = (m1.elem (i, j) != lhs_zero)              \
+                      OP (m2.elem (i, j) != rhs_zero);                  \
                     if (el)                                             \
                       {                                                 \
                         r.data (ii) = el;                               \
@@ -1391,12 +1461,9 @@
     return r;                                                           \
   }
 
-#define SPARSE_SMM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO)                \
-  SPARSE_SMM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO)        \
-  SPARSE_SMM_BOOL_OP (mx_el_or,  ||, M1, M2, LHS_ZERO, RHS_ZERO)
-
-#define SPARSE_SMM_BOOL_OPS(M1, M2, ZERO)       \
-  SPARSE_SMM_BOOL_OPS2(M1, M2, ZERO, ZERO)
+#define SPARSE_SMM_BOOL_OPS(M1, M2)             \
+  SPARSE_SMM_BOOL_OP (mx_el_and, &&, M1, M2)    \
+  SPARSE_SMM_BOOL_OP (mx_el_or,  ||, M1, M2)
 
 // Avoid some code duplication.  Maybe we should use templates.
 
@@ -1858,7 +1925,7 @@
         }                                                               \
     }
 
-#define SPARSE_FULL_MUL(RET_TYPE, EL_TYPE, ZERO)                        \
+#define SPARSE_FULL_MUL(RET_TYPE, EL_TYPE)                              \
   octave_idx_type nr = m.rows ();                                       \
   octave_idx_type nc = m.cols ();                                       \
                                                                         \
@@ -1874,7 +1941,9 @@
     octave::err_nonconformant ("operator *", nr, nc, a_nr, a_nc);               \
   else                                                                  \
     {                                                                   \
-      RET_TYPE retval (nr, a_nc, ZERO);                                 \
+      RET_TYPE::element_type zero = RET_TYPE::element_type ();          \
+                                                                        \
+      RET_TYPE retval (nr, a_nc, zero);                                 \
                                                                         \
       for (octave_idx_type i = 0; i < a_nc ; i++)                       \
         {                                                               \
@@ -1890,7 +1959,7 @@
       return retval;                                                    \
     }
 
-#define SPARSE_FULL_TRANS_MUL(RET_TYPE, EL_TYPE, ZERO, CONJ_OP)         \
+#define SPARSE_FULL_TRANS_MUL(RET_TYPE, EL_TYPE, CONJ_OP)               \
   octave_idx_type nr = m.rows ();                                       \
   octave_idx_type nc = m.cols ();                                       \
                                                                         \
@@ -1914,7 +1983,7 @@
             {                                                           \
               octave_quit ();                                           \
                                                                         \
-              EL_TYPE acc = ZERO;                                       \
+              EL_TYPE acc = EL_TYPE ();                                 \
               for (octave_idx_type k = m.cidx (j) ; k < m.cidx (j+1); k++) \
                 acc += a.elem (m.ridx (k),i) * CONJ_OP (m.data (k));    \
               retval.xelem (j,i) = acc;                                 \
@@ -1923,7 +1992,7 @@
       return retval;                                                    \
     }
 
-#define FULL_SPARSE_MUL(RET_TYPE, EL_TYPE, ZERO)                        \
+#define FULL_SPARSE_MUL(RET_TYPE, EL_TYPE)                              \
   octave_idx_type nr = m.rows ();                                       \
   octave_idx_type nc = m.cols ();                                       \
                                                                         \
@@ -1939,7 +2008,9 @@
     octave::err_nonconformant ("operator *", nr, nc, a_nr, a_nc);               \
   else                                                                  \
     {                                                                   \
-      RET_TYPE retval (nr, a_nc, ZERO);                                 \
+      RET_TYPE::element_type zero = RET_TYPE::element_type ();          \
+                                                                        \
+      RET_TYPE retval (nr, a_nc, zero);                                 \
                                                                         \
       for (octave_idx_type i = 0; i < a_nc ; i++)                       \
         {                                                               \
@@ -1956,7 +2027,7 @@
       return retval;                                                    \
     }
 
-#define FULL_SPARSE_MUL_TRANS(RET_TYPE, EL_TYPE, ZERO, CONJ_OP)         \
+#define FULL_SPARSE_MUL_TRANS(RET_TYPE, EL_TYPE, CONJ_OP)               \
   octave_idx_type nr = m.rows ();                                       \
   octave_idx_type nc = m.cols ();                                       \
                                                                         \
@@ -1972,7 +2043,9 @@
     octave::err_nonconformant ("operator *", nr, nc, a_nc, a_nr);               \
   else                                                                  \
     {                                                                   \
-      RET_TYPE retval (nr, a_nr, ZERO);                                 \
+      RET_TYPE::element_type zero = RET_TYPE::element_type ();          \
+                                                                        \
+      RET_TYPE retval (nr, a_nr, zero);                                 \
                                                                         \
       for (octave_idx_type i = 0; i < a_nc ; i++)                       \
         {                                                               \
--- a/liboctave/operators/mk-ops.awk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/mk-ops.awk	Thu Dec 20 17:18:56 2018 -0500
@@ -89,12 +89,11 @@
     {
       ntypes++;
 
-      if (NF == 6 || NF == 7)
+      if (NF == 5 || NF == 6)
         {
-          if (NF == 7)
-            core_type[ntypes] = $7;
+          if (NF == 6)
+            core_type[ntypes] = $6;
 
-          scalar_zero_val[ntypes] = $6;
           fwd_decl_ok[ntypes] = $5 == "YES";
           header[ntypes] = $4 == "NONE" ? "" : $4;
           class[ntypes] = $3;
@@ -123,18 +122,6 @@
           eqne_ops = index (op_type, "E") != 0;
           bool_ops = index (op_type, "L") != 0;
 
-          if (cmp_ops)
-            {
-              lhs_conv = $(++n);
-              rhs_conv = $(++n);
-            }
-
-          if (lhs_conv == "NONE")
-            lhs_conv = "";
-
-          if (rhs_conv == "NONE")
-            rhs_conv = "";
-
           k = 0
           while (NF > n)
             bool_headers[k++] = $(++n);
@@ -180,12 +167,6 @@
           lhs_core_type = core_type[lhs_num];
           rhs_core_type = core_type[rhs_num];
 
-          result_scalar_zero_val_1 = scalar_zero_val[result_num_1];
-          if (sparse)
-            result_scalar_zero_val_2 = scalar_zero_val[result_num_2];
-          lhs_scalar_zero_val = scalar_zero_val[lhs_num];
-          rhs_scalar_zero_val = scalar_zero_val[rhs_num];
-
           result_header_1 = header[result_num_1];
           if (sparse)
             result_header_2 = header[result_num_2];
@@ -335,47 +316,23 @@
 
                   printf ("#include \"Sparse-op-defs.h\"\n");
                 }
-              else
-                printf ("#include \"mx-op-decl.h\"\n");
 
               if (bin_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_BIN_OP_DECLS (%s, %s, %s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, result_type_1, result_type_2,
-                            lhs_type, rhs_type);
-                  else
-                    printf ("%s%s_BIN_OP_DECLS (%s, %s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, result_type_1, lhs_type,
-                            rhs_type);
-                }
+                emit_bin_op_decls(sparse, lhs_class, rhs_class,
+                                  result_type_1, result_type_2,
+                                  lhs_type, rhs_type);
 
               if (cmp_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_CMP_OP_DECLS (%s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                  else
-                    printf ("%s%s_CMP_OP_DECLS (%s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                }
+                emit_cmp_op_decls(sparse, lhs_class, rhs_class,
+                                  lhs_type, rhs_type);
 
               if (eqne_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_EQNE_OP_DECLS (%s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                }
+                emit_eqne_op_decls(sparse, lhs_class, rhs_class,
+                                   lhs_type, rhs_type);
 
               if (bool_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_BOOL_OP_DECLS (%s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                  else
-                    printf ("%s%s_BOOL_OP_DECLS (%s, %s, OCTAVE_API)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                }
+                emit_bool_op_decls(sparse, lhs_class, rhs_class,
+                                   lhs_type, rhs_type);
 
               print "#endif";
 
@@ -411,61 +368,23 @@
               if (lhs_header && ! (lhs_header == result_header_1 || lhs_header == result_header_2))
                 printf ("#include \"%s\"\n", lhs_header);
 
-              if (rhs_header && ! (rhs_header == lhs_header || rhs_header == result_header_1 || rhs_heaer == result_header_2))
+              if (rhs_header && ! (rhs_header == lhs_header || rhs_header == result_header_1 || rhs_header == result_header_2))
                 printf ("#include \"%s\"\n", rhs_header);
 
               if (bin_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_BIN_OPS (%s, %s, %s, %s)\n",
-                            lhs_class, rhs_class, result_type_1,
-                            result_type_2, lhs_type, rhs_type);
-                  else
-                    {
-                      if ((lhs_class == "DM" && rhs_class == "M") || (lhs_class == "M" && rhs_class == "DM"))
-                        printf ("%s%s_BIN_OPS (%s, %s, %s, %s)\n",
-                                lhs_class, rhs_class, result_type_1,
-                                lhs_type, rhs_type, result_scalar_zero_val_1);
-                      else
-                        printf ("%s%s_BIN_OPS (%s, %s, %s)\n",
-                                lhs_class, rhs_class, result_type_1,
-                                lhs_type, rhs_type);
-                    }
-                }
+                emit_bin_ops(sparse, lhs_class, rhs_class,
+                             result_type_1, result_type_2, lhs_type, rhs_type);
 
               if (cmp_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_CMP_OPS (%s, %s, %s, %s, %s, %s)\n",
-                            lhs_class, rhs_class, lhs_type,
-                            lhs_scalar_zero_val, lhs_conv, rhs_type,
-                            rhs_scalar_zero_val, rhs_conv);
-                  else
-                    printf ("%s%s_CMP_OPS (%s, %s)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type);
-                }
+                emit_cmp_ops(sparse, lhs_class, rhs_class, lhs_type, rhs_type);
 
               if (eqne_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_EQNE_OPS (%s, %s, %s, %s, %s, %s)\n",
-                            lhs_class, rhs_class, lhs_type,
-                            lhs_scalar_zero_val, lhs_conv, rhs_type,
-                            rhs_scalar_zero_val, rhs_conv);
-
-                  ## No separate eqne ops for full-matrix or vector.
-                }
+                emit_eqne_ops(sparse, lhs_class, rhs_class,
+                              lhs_type, rhs_type);
 
               if (bool_ops)
-                {
-                  if (sparse)
-                    printf ("SPARSE_%s%s_BOOL_OPS2 (%s, %s, %s, %s)\n",
-                            lhs_class, rhs_class, lhs_type, rhs_type,
-                            lhs_scalar_zero_val, rhs_scalar_zero_val);
-                  else
-                    printf ("%s%s_BOOL_OPS (%s, %s)\n", lhs_class, rhs_class,
-                            lhs_type, rhs_type);
-                }
+                emit_bool_ops(sparse, lhs_class, rhs_class,
+                              lhs_type, rhs_type);
 
               exit (0);
             }
@@ -478,3 +397,272 @@
   if (make_inclusive_header)
     print "#endif";
 }
+
+function emit_bin_op_decl (result_type, operator, lhs_type, rhs_type)
+{
+  if (operator != "")
+    printf ("  extern OCTAVE_API %s %s (const %s&, const %s&);\n",
+            result_type, operator, lhs_type, rhs_type);
+}
+
+function emit_bin_op_decls_1 (result_type, lhs_type, rhs_type,
+                              add_op, sub_op, mul_op, div_op)
+{
+  emit_bin_op_decl(result_type, add_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, sub_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, mul_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, div_op, lhs_type, rhs_type);
+}
+
+function emit_sparse_bin_op_decls (result_type_1, result_type_2,
+                                   lhs_type, rhs_type,
+                                   add_op, sub_op, mul_op, div_op)
+{
+  emit_bin_op_decl(result_type_1, add_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type_1, sub_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type_2, mul_op, lhs_type, rhs_type);
+  emit_bin_op_decl(result_type_2, div_op, lhs_type, rhs_type);
+}
+
+function emit_bin_op_decls (sparse, lhs_class, rhs_class,
+                            result_type_1, result_type_2,
+                            lhs_type, rhs_type)
+{
+  if (sparse)
+    {
+      if ((lhs_class == "SM" && rhs_class == "S") \
+          || (lhs_class == "S" && rhs_class == "SM"))
+        emit_sparse_bin_op_decls(result_type_1, result_type_2,
+                                 lhs_type, rhs_type,
+                                 "operator +", "operator -",
+                                 "operator *", "operator /");
+
+      else if ((lhs_class == "M" && rhs_class == "SM")    \
+               || (lhs_class == "SM" && rhs_class == "M") \
+               || (lhs_class == "SM" && rhs_class == "SM"))
+        emit_sparse_bin_op_decls(result_type_1, result_type_2,
+                                 lhs_type, rhs_type,
+                                 "operator +", "operator -",
+                                 "product", "quotient");
+    }
+  else
+    {
+      if ((lhs_class == "M" && rhs_class == "S") \
+          || (lhs_class == "ND" && rhs_class == "S") \
+          || (lhs_class == "S" \
+              && (rhs_class == "M" || rhs_class == "ND" || rhs_class == "V")) \
+          || (lhs_class == "V" && rhs_class == "S"))
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "operator +", "operator -",
+                            "operator *", "operator /");
+
+      else if ((lhs_class == "M" && rhs_class == "M")      \
+               || (lhs_class == "ND" && rhs_class == "ND") \
+               || (lhs_class == "V" && rhs_class == "V"))
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "operator +", "operator -",
+                            "product", "quotient");
+
+      else if ((lhs_class == "DM" && rhs_class == "M")  \
+          || (lhs_class == "M" && rhs_class == "DM"))
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "operator +", "operator -", "operator *", "");
+
+      else if (lhs_class == "DM" && rhs_class == "DM")
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "operator +", "operator -", "product", "");
+
+      else if (lhs_class == "DM" && rhs_class == "S")
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "", "", "operator *", "operator /");
+
+      else if ((lhs_class == "M" && rhs_class == "PM") \
+               || (lhs_class == "PM" && rhs_class == "M") \
+               || (lhs_class == "S" && rhs_class == "DM"))
+        emit_bin_op_decls_1(result_type_1, lhs_type, rhs_type,
+                            "", "", "operator *", "");
+    }
+}
+
+function emit_cmp_op_decls_1(result_type, lhs_type, rhs_type)
+{
+  emit_bin_op_decl(result_type, "mx_el_lt", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_le", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_ge", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_gt", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_eq", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_ne", lhs_type, rhs_type);
+}
+
+function emit_cmp_op_decls (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    {
+      if ((lhs_class == "M" && rhs_class == "SM") \
+          || (lhs_class == "SM" && (rhs_class == "M" || rhs_class == "S" || rhs_class == "SM")) \
+          || (lhs_class == "S" && rhs_class == "SM"))
+        emit_cmp_op_decls_1("SparseBoolMatrix", lhs_type, rhs_type);
+    }
+  else
+    {
+      if ((lhs_class == "M" && rhs_class == "M") \
+          || (lhs_class == "M" && rhs_class == "S") \
+          || (lhs_class == "S" && rhs_class == "M"))
+        emit_cmp_op_decls_1("boolMatrix", lhs_type, rhs_type);
+      else if ((lhs_class == "ND" && rhs_class == "ND") \
+               || (lhs_class == "ND" && rhs_class == "S") \
+               || (lhs_class == "S" && rhs_class == "ND"))
+        emit_cmp_op_decls_1("boolNDArray", lhs_type, rhs_type);
+    }
+}
+
+function emit_eqne_op_decls_1(result_type, lhs_type, rhs_type)
+{
+  emit_bin_op_decl(result_type, "mx_el_eq", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_ne", lhs_type, rhs_type);
+}
+
+function emit_eqne_op_decls (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    {
+      if ((lhs_class == "M" && rhs_class == "SM") \
+          || (lhs_class == "SM" && rhs_class == "M"))
+        emit_eqne_op_decls_1("SparseBoolMatrix", lhs_type, rhs_type);
+    }
+
+  ## No separate eqne ops for full-matrix or vector.
+}
+
+function emit_bool_op_decls_1 (result_type, lhs_type, rhs_type)
+{
+  emit_bin_op_decl(result_type, "mx_el_and", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_or", lhs_type, rhs_type);
+}
+
+function emit_bool_op_decls_2 (result_type, lhs_type, rhs_type)
+{
+  emit_bin_op_decl(result_type, "mx_el_not_and", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_not_or", lhs_type, rhs_type);
+}
+
+function emit_bool_op_decls_3 (result_type, lhs_type, rhs_type)
+{
+  emit_bin_op_decl(result_type, "mx_el_and_not", lhs_type, rhs_type);
+  emit_bin_op_decl(result_type, "mx_el_or_not", lhs_type, rhs_type);
+}
+
+function emit_bool_op_decls (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    {
+      if ((lhs_class == "M" && rhs_class == "SM") \
+          || (lhs_class == "SM" && (rhs_class == "M" || rhs_class == "S" || rhs_class == "SM")) \
+          || (lhs_class == "S" && rhs_class == "SM"))
+        emit_bool_op_decls_1("SparseBoolMatrix", lhs_type, rhs_type);
+    }
+  else
+    {
+      if ((lhs_class == "M" && rhs_class == "M") \
+          || (lhs_class == "M" && rhs_class == "S") \
+          || (lhs_class == "S" && rhs_class == "M"))
+        emit_bool_op_decls_1("boolMatrix", lhs_type, rhs_type);
+      else if (lhs_class == "ND" && rhs_class == "S")
+        {
+          emit_bool_op_decls_1("boolNDArray", lhs_type, rhs_type);
+          emit_bool_op_decls_2("boolNDArray", lhs_type, rhs_type);
+        }
+      else if (lhs_class == "S" && rhs_class == "ND")
+        {
+          emit_bool_op_decls_1("boolNDArray", lhs_type, rhs_type);
+          emit_bool_op_decls_3("boolNDArray", lhs_type, rhs_type);
+        }
+      else if (lhs_class == "ND" && rhs_class == "ND")
+        {
+          emit_bool_op_decls_1("boolNDArray", lhs_type, rhs_type);
+          emit_bool_op_decls_2("boolNDArray", lhs_type, rhs_type);
+          emit_bool_op_decls_3("boolNDArray", lhs_type, rhs_type);
+        }
+    }
+}
+
+function emit_sparse_bin_ops (lhs_class, rhs_class, result_type_1,
+                              result_type_2, lhs_type, rhs_type)
+{
+  printf ("SPARSE_%s%s_BIN_OPS (%s, %s, %s, %s)\n",
+          lhs_class, rhs_class, result_type_1,
+          result_type_2, lhs_type, rhs_type);
+}
+
+function emit_dm_bin_ops (lhs_class, rhs_class, result_type_1,
+                          lhs_type, rhs_type)
+{
+  printf ("%s%s_BIN_OPS (%s, %s, %s)\n",
+          lhs_class, rhs_class, result_type_1, lhs_type, rhs_type);
+}
+
+function emit_mm_bin_op (result_t, op, lhs_t, rhs_t, fcn)
+{
+  printf ("\n" \
+          "%s\n" \
+          "%s (const %s& m1, const %s& m2)\n" \
+          "{\n" \
+          "  return do_mm_binary_op<%s::element_type, %s::element_type, %s::element_type> (m1, m2, %s, %s, %s, \"%s\");\n" \
+          "}\n",
+          result_t, op, lhs_t, rhs_t, result_t, lhs_t, rhs_t,
+          fcn, fcn, fcn, op);
+}
+
+function emit_mm_bin_ops (result_t, lhs_t, rhs_t)
+{
+  emit_mm_bin_op(result_t, "operator +", lhs_t, rhs_t, "mx_inline_add");
+  emit_mm_bin_op(result_t, "operator -", lhs_t, rhs_t, "mx_inline_sub");
+  emit_mm_bin_op(result_t, "product", lhs_t, rhs_t, "mx_inline_mul");
+  emit_mm_bin_op(result_t, "quotient", lhs_t, rhs_t, "mx_inline_div");
+}
+
+function emit_bin_ops (sparse, lhs_class, rhs_class,
+                       result_type_1, result_type_2, lhs_type, rhs_type)
+{
+  if (sparse)
+    emit_sparse_bin_ops(lhs_class, rhs_class, result_type_1,
+                        result_type_2, lhs_type, rhs_type);
+ else if ((lhs_class == "DM" && rhs_class == "M") \
+          || (lhs_class == "M" && rhs_class == "DM"))
+    emit_dm_bin_ops(lhs_class, rhs_class, result_type_1,
+                    lhs_type, rhs_type);
+  else if (lhs_class == "M" && rhs_class == "M")
+    emit_mm_bin_ops(result_type_1, lhs_type, rhs_type);
+  else
+    printf ("%s%s_BIN_OPS (%s, %s, %s)\n",
+            lhs_class, rhs_class, result_type_1, lhs_type, rhs_type);
+}
+
+function emit_cmp_ops (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    printf ("SPARSE_%s%s_CMP_OPS (%s, %s)\n",
+            lhs_class, rhs_class, lhs_type, rhs_type);
+  else
+    printf ("%s%s_CMP_OPS (%s, %s)\n",
+            lhs_class, rhs_class, lhs_type, rhs_type);
+}
+
+function emit_eqne_ops (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    printf ("SPARSE_%s%s_EQNE_OPS (%s, %s)\n",
+            lhs_class, rhs_class, lhs_type, rhs_type);
+
+  ## No separate eqne ops for full-matrix or vector.
+}
+
+function emit_bool_ops (sparse, lhs_class, rhs_class, lhs_type, rhs_type)
+{
+  if (sparse)
+    printf ("SPARSE_%s%s_BOOL_OPS (%s, %s)\n",
+            lhs_class, rhs_class, lhs_type, rhs_type);
+  else
+    printf ("%s%s_BOOL_OPS (%s, %s)\n",
+            lhs_class, rhs_class, lhs_type, rhs_type);
+}
--- a/liboctave/operators/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -6,6 +6,18 @@
 include %reldir%/mx-op-src.mk
 include %reldir%/smx-op-src.mk
 
+OP_MK_FILES := \
+  $(srcdir)/%reldir%/vx-op-inc.mk \
+  $(srcdir)/%reldir%/mx-op-inc.mk \
+  $(srcdir)/%reldir%/smx-op-inc.mk \
+  $(srcdir)/%reldir%/vx-op-src.mk \
+  $(srcdir)/%reldir%/mx-op-src.mk \
+  $(srcdir)/%reldir%/smx-op-src.mk
+
+$(OP_MK_FILES) : %.mk : $(srcdir)/%reldir%/config-ops.sh $(srcdir)/%reldir%/mk-ops.awk
+	$(AM_V_GEN)$(SHELL) $(srcdir)/%reldir%/config-ops.sh $(top_srcdir) `echo $(*F) | $(SED) 's/-op-.*//'` `echo $(*F) | $(SED) 's/.*-op-//'`
+
+
 BUILT_LIBOCTAVE_OPERATORS_SOURCES = \
   $(MX_OP_SRC) \
   $(VX_OP_SRC) \
@@ -82,10 +94,6 @@
 
 %canon_reldir%_liboperators_la_CPPFLAGS = $(liboctave_liboctave_la_CPPFLAGS)
 
-%canon_reldir%_liboperators_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_liboperators_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/liboperators.la
 
 liboctave_EXTRA_DIST += \
--- a/liboctave/operators/mx-op-defs.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/mx-op-defs.h	Thu Dec 20 17:18:56 2018 -0500
@@ -421,12 +421,14 @@
     return r;                                                   \
   }
 
-#define MDM_MULTIPLY_OP(R, M, DM, R_ZERO)                               \
+#define MDM_MULTIPLY_OP(R, M, DM)                                       \
   R                                                                     \
   operator * (const M& m, const DM& dm)                                 \
   {                                                                     \
     R r;                                                                \
                                                                         \
+    R::element_type r_zero = R::element_type ();                        \
+                                                                        \
     octave_idx_type m_nr = m.rows ();                                   \
     octave_idx_type m_nc = m.cols ();                                   \
                                                                         \
@@ -447,15 +449,15 @@
         mx_inline_mul (m_nr, rd, md, dd[i]);                            \
         rd += m_nr; md += m_nr;                                         \
       }                                                                 \
-    mx_inline_fill (m_nr * (dm_nc - len), rd, R_ZERO);                  \
+    mx_inline_fill (m_nr * (dm_nc - len), rd, r_zero);                  \
                                                                         \
     return r;                                                           \
   }
 
-#define MDM_BIN_OPS(R, M, DM, R_ZERO)           \
+#define MDM_BIN_OPS(R, M, DM)                   \
   MDM_BIN_OP (R, operator +, M, DM, +=)         \
   MDM_BIN_OP (R, operator -, M, DM, -=)         \
-  MDM_MULTIPLY_OP (R, M, DM, R_ZERO)
+  MDM_MULTIPLY_OP (R, M, DM)
 
 // diagonal matrix by matrix operations.
 
@@ -491,12 +493,14 @@
     return r;                                                   \
   }
 
-#define DMM_MULTIPLY_OP(R, DM, M, R_ZERO)                               \
+#define DMM_MULTIPLY_OP(R, DM, M)                                       \
   R                                                                     \
   operator * (const DM& dm, const M& m)                                 \
   {                                                                     \
     R r;                                                                \
                                                                         \
+    R::element_type r_zero = R::element_type ();                        \
+                                                                        \
     octave_idx_type dm_nr = dm.rows ();                                 \
     octave_idx_type dm_nc = dm.cols ();                                 \
                                                                         \
@@ -516,17 +520,17 @@
       {                                                                 \
         mx_inline_mul (len, rd, md, dd);                                \
         rd += len; md += m_nr;                                          \
-        mx_inline_fill (dm_nr - len, rd, R_ZERO);                       \
+        mx_inline_fill (dm_nr - len, rd, r_zero);                       \
         rd += dm_nr - len;                                              \
       }                                                                 \
                                                                         \
     return r;                                                           \
   }
 
-#define DMM_BIN_OPS(R, DM, M, R_ZERO)           \
+#define DMM_BIN_OPS(R, DM, M)                   \
   DMM_BIN_OP (R, operator +, DM, M, +=, )       \
   DMM_BIN_OP (R, operator -, DM, M, +=, -)      \
-  DMM_MULTIPLY_OP (R, DM, M, R_ZERO)
+  DMM_MULTIPLY_OP (R, DM, M)
 
 // diagonal matrix by diagonal matrix operations.
 
--- a/liboctave/operators/mx-ops	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/mx-ops	Thu Dec 20 17:18:56 2018 -0500
@@ -21,7 +21,7 @@
 
 # types
 #
-# key typename object-type header fwd-decl-ok scalar-zero core-type
+# key typename object-type header fwd-decl-ok core-type
 #
 # object-type is one of
 #
@@ -37,47 +37,47 @@
 # core-type is only used for the octave_int types, and is the template
 # parameter: octave_int8 is octave_int<int8_t>
 #
-x NONE NONE NONE NO 0
-b bool S NONE NO false
-bm boolMatrix ND boolMatrix.h YES false
-bnda boolNDArray ND boolNDArray.h YES false
-cdm ComplexDiagMatrix DM CDiagMatrix.h YES 0.0
-cm ComplexMatrix M CMatrix.h YES 0.0
-cnda ComplexNDArray ND CNDArray.h YES 0.0
-cs Complex S oct-cmplx.h NO 0.0
-dm DiagMatrix DM dDiagMatrix.h YES 0.0
-m Matrix M dMatrix.h YES 0.0
-nda NDArray ND dNDArray.h YES 0.0
-s double S NONE NO 0.0
-fcdm FloatComplexDiagMatrix DM fCDiagMatrix.h YES 0.0f
-fcm FloatComplexMatrix M fCMatrix.h YES 0.0f
-fcnda FloatComplexNDArray ND fCNDArray.h YES 0.0f
-fcs FloatComplex S oct-cmplx.h NO 0.0f
-fdm FloatDiagMatrix DM fDiagMatrix.h YES 0.0f
-fm FloatMatrix M fMatrix.h YES 0.0f
-fnda FloatNDArray ND fNDArray.h YES 0.0f
-fs float S NONE NO 0.0f
-i8 octave_int8 S oct-inttypes.h YES octave_int8::zero int8_t
-ui8 octave_uint8 S oct-inttypes.h YES octave_uint8::zero uint8_t
-i16 octave_int16 S oct-inttypes.h YES octave_int16::zero int16_t
-ui16 octave_uint16 S oct-inttypes.h YES octave_uint16::zero uint16_t
-i32 octave_int32 S oct-inttypes.h YES octave_int32::zero int32_t
-ui32 octave_uint32 S oct-inttypes.h YES octave_uint32::zero uint32_t
-i64 octave_int64 S oct-inttypes.h YES octave_int64::zero int64_t
-ui64 octave_uint64 S oct-inttypes.h YES octave_uint64::zero uint64_t
-i8nda int8NDArray ND int8NDArray.h YES octave_int8::zero int8_t
-ui8nda uint8NDArray ND uint8NDArray.h YES octave_uint8::zero uint8_t
-i16nda int16NDArray ND int16NDArray.h YES octave_int16::zero int16_t
-ui16nda uint16NDArray ND uint16NDArray.h YES octave_uint16::zero uint16_t
-i32nda int32NDArray ND int32NDArray.h YES octave_int32::zero int32_t
-ui32nda uint32NDArray ND uint32NDArray.h YES octave_uint32::zero uint32_t
-i64nda int64NDArray ND int64NDArray.h YES octave_int64::zero int64_t
-ui64nda uint64NDArray ND uint64NDArray.h YES octave_uint64::zero uint64_t
-pm PermMatrix PM PermMatrix.h YES static_cast<octave_idx_type>(0)
+x NONE NONE NONE NO
+b bool S NONE NO
+bm boolMatrix ND boolMatrix.h YES
+bnda boolNDArray ND boolNDArray.h YES
+cdm ComplexDiagMatrix DM CDiagMatrix.h YES
+cm ComplexMatrix M CMatrix.h YES
+cnda ComplexNDArray ND CNDArray.h YES
+cs Complex S oct-cmplx.h NO
+dm DiagMatrix DM dDiagMatrix.h YES
+m Matrix M dMatrix.h YES
+nda NDArray ND dNDArray.h YES
+s double S NONE NO
+fcdm FloatComplexDiagMatrix DM fCDiagMatrix.h YES
+fcm FloatComplexMatrix M fCMatrix.h YES
+fcnda FloatComplexNDArray ND fCNDArray.h YES
+fcs FloatComplex S oct-cmplx.h NO
+fdm FloatDiagMatrix DM fDiagMatrix.h YES
+fm FloatMatrix M fMatrix.h YES
+fnda FloatNDArray ND fNDArray.h YES
+fs float S NONE NO
+i8 octave_int8 S oct-inttypes.h YES int8_t
+ui8 octave_uint8 S oct-inttypes.h YES uint8_t
+i16 octave_int16 S oct-inttypes.h YES int16_t
+ui16 octave_uint16 S oct-inttypes.h YES uint16_t
+i32 octave_int32 S oct-inttypes.h YES int32_t
+ui32 octave_uint32 S oct-inttypes.h YES uint32_t
+i64 octave_int64 S oct-inttypes.h YES int64_t
+ui64 octave_uint64 S oct-inttypes.h YES uint64_t
+i8nda int8NDArray ND int8NDArray.h YES int8_t
+ui8nda uint8NDArray ND uint8NDArray.h YES uint8_t
+i16nda int16NDArray ND int16NDArray.h YES int16_t
+ui16nda uint16NDArray ND uint16NDArray.h YES uint16_t
+i32nda int32NDArray ND int32NDArray.h YES int32_t
+ui32nda uint32NDArray ND uint32NDArray.h YES uint32_t
+i64nda int64NDArray ND int64NDArray.h YES int64_t
+ui64nda uint64NDArray ND uint64NDArray.h YES uint64_t
+pm PermMatrix PM PermMatrix.h YES
 #
 # full-matrix operators
 #
-# result_t lhs_t rhs_t op-type lhs_conv rhs_conv headers ...
+# result_t lhs_t rhs_t op-type headers ...
 #
 # op-type is one of
 #
@@ -88,54 +88,54 @@
 cdm cdm dm B
 cdm dm cdm B
 cdm cs dm B
-cm cs m BCL real NONE boolMatrix.h
-cnda cs nda BCL real NONE boolMatrix.h boolNDArray.h
+cm cs m BCL boolMatrix.h
+cnda cs nda BCL boolMatrix.h boolNDArray.h
 cm cdm cm B
 cm cdm m B
 cdm cdm s B
 cm cm cdm B
 cm cm dm B
-cm cm m BCL real NONE boolMatrix.h
-cnda cnda nda BCL real NONE boolMatrix.h boolNDArray.h
-cm cm s BCL real NONE boolMatrix.h
-cnda cnda s BCL real NONE boolMatrix.h boolNDArray.h
+cm cm m BCL boolMatrix.h
+cnda cnda nda BCL boolMatrix.h boolNDArray.h
+cm cm s BCL boolMatrix.h
+cnda cnda s BCL boolMatrix.h boolNDArray.h
 cdm dm cs B
 cm dm cm B
-cm m cs BCL NONE real boolMatrix.h
-cnda nda cs BCL NONE real boolMatrix.h boolNDArray.h
+cm m cs BCL boolMatrix.h
+cnda nda cs BCL boolMatrix.h boolNDArray.h
 cm m cdm B
-cm m cm BCL NONE real boolMatrix.h
-cnda nda cnda BCL NONE real boolMatrix.h boolNDArray.h
+cm m cm BCL boolMatrix.h
+cnda nda cnda BCL boolMatrix.h boolNDArray.h
 cdm s cdm B
-cm s cm BCL NONE real boolMatrix.h
-cnda s cnda BCL NONE real boolMatrix.h boolNDArray.h
+cm s cm BCL boolMatrix.h
+cnda s cnda BCL boolMatrix.h boolNDArray.h
 m dm m B
 m m dm B
 #
 fcdm fcdm fdm B
 fcdm fdm fcdm B
 fcdm fcs fdm B
-fcm fcs fm BCL real NONE boolMatrix.h
-fcnda fcs fnda BCL real NONE boolMatrix.h boolNDArray.h
+fcm fcs fm BCL boolMatrix.h
+fcnda fcs fnda BCL boolMatrix.h boolNDArray.h
 fcm fcdm fcm B
 fcm fcdm fm B
 fcdm fcdm fs B
 fcm fcm fcdm B
 fcm fcm fdm B
-fcm fcm fm BCL real NONE boolMatrix.h
-fcnda fcnda fnda BCL real NONE boolMatrix.h boolNDArray.h
-fcm fcm fs BCL real NONE boolMatrix.h
-fcnda fcnda fs BCL real NONE boolMatrix.h boolNDArray.h
+fcm fcm fm BCL boolMatrix.h
+fcnda fcnda fnda BCL boolMatrix.h boolNDArray.h
+fcm fcm fs BCL boolMatrix.h
+fcnda fcnda fs BCL boolMatrix.h boolNDArray.h
 fcdm fdm fcs B
 fcm fdm fcm B
-fcm fm fcs BCL NONE real boolMatrix.h
-fcnda fnda fcs BCL NONE real boolMatrix.h boolNDArray.h
+fcm fm fcs BCL boolMatrix.h
+fcnda fnda fcs BCL boolMatrix.h boolNDArray.h
 fcm fm fcdm B
-fcm fm fcm BCL NONE real boolMatrix.h
-fcnda fnda fcnda BCL NONE real boolMatrix.h boolNDArray.h
+fcm fm fcm BCL boolMatrix.h
+fcnda fnda fcnda BCL boolMatrix.h boolNDArray.h
 fcdm fs fcdm B
-fcm fs fcm BCL NONE real boolMatrix.h
-fcnda fs fcnda BCL NONE real boolMatrix.h boolNDArray.h
+fcm fs fcm BCL boolMatrix.h
+fcnda fs fcnda BCL boolMatrix.h boolNDArray.h
 fm fdm fm B
 fm fm fdm B
 #
@@ -148,293 +148,293 @@
 fcm pm fcm B
 fcm fcm pm B
 #
-i8nda s i8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda s ui8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda s i16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda s ui16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda s i32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda s ui32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda s i64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda s ui64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64nda s BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda fs i8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda fs ui8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda fs i16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda fs ui16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda fs i32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda fs ui32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda fs i64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda fs ui64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64nda fs BCL NONE NONE boolMatrix.h boolNDArray.h
+i8nda s i8nda BCL boolMatrix.h boolNDArray.h
+i8nda i8nda s BCL boolMatrix.h boolNDArray.h
+ui8nda s ui8nda BCL boolMatrix.h boolNDArray.h
+ui8nda ui8nda s BCL boolMatrix.h boolNDArray.h
+i16nda s i16nda BCL boolMatrix.h boolNDArray.h
+i16nda i16nda s BCL boolMatrix.h boolNDArray.h
+ui16nda s ui16nda BCL boolMatrix.h boolNDArray.h
+ui16nda ui16nda s BCL boolMatrix.h boolNDArray.h
+i32nda s i32nda BCL boolMatrix.h boolNDArray.h
+i32nda i32nda s BCL boolMatrix.h boolNDArray.h
+ui32nda s ui32nda BCL boolMatrix.h boolNDArray.h
+ui32nda ui32nda s BCL boolMatrix.h boolNDArray.h
+i64nda s i64nda BCL boolMatrix.h boolNDArray.h
+i64nda i64nda s BCL boolMatrix.h boolNDArray.h
+ui64nda s ui64nda BCL boolMatrix.h boolNDArray.h
+ui64nda ui64nda s BCL boolMatrix.h boolNDArray.h
+i8nda fs i8nda BCL boolMatrix.h boolNDArray.h
+i8nda i8nda fs BCL boolMatrix.h boolNDArray.h
+ui8nda fs ui8nda BCL boolMatrix.h boolNDArray.h
+ui8nda ui8nda fs BCL boolMatrix.h boolNDArray.h
+i16nda fs i16nda BCL boolMatrix.h boolNDArray.h
+i16nda i16nda fs BCL boolMatrix.h boolNDArray.h
+ui16nda fs ui16nda BCL boolMatrix.h boolNDArray.h
+ui16nda ui16nda fs BCL boolMatrix.h boolNDArray.h
+i32nda fs i32nda BCL boolMatrix.h boolNDArray.h
+i32nda i32nda fs BCL boolMatrix.h boolNDArray.h
+ui32nda fs ui32nda BCL boolMatrix.h boolNDArray.h
+ui32nda ui32nda fs BCL boolMatrix.h boolNDArray.h
+i64nda fs i64nda BCL boolMatrix.h boolNDArray.h
+i64nda i64nda fs BCL boolMatrix.h boolNDArray.h
+ui64nda fs ui64nda BCL boolMatrix.h boolNDArray.h
+ui64nda ui64nda fs BCL boolMatrix.h boolNDArray.h
 #
-i8nda nda i8 BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda nda ui8 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda nda i16 BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda nda ui16 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda nda i32 BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda nda ui32 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda nda i64 BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda nda ui64 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64 nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda fnda i8 BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda fnda ui8 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda fnda i16 BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda fnda ui16 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda fnda i32 BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda fnda ui32 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda fnda i64 BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda fnda ui64 BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64 fnda BCL NONE NONE boolMatrix.h boolNDArray.h
+i8nda nda i8 BCL boolMatrix.h boolNDArray.h
+i8nda i8 nda BCL boolMatrix.h boolNDArray.h
+ui8nda nda ui8 BCL boolMatrix.h boolNDArray.h
+ui8nda ui8 nda BCL boolMatrix.h boolNDArray.h
+i16nda nda i16 BCL boolMatrix.h boolNDArray.h
+i16nda i16 nda BCL boolMatrix.h boolNDArray.h
+ui16nda nda ui16 BCL boolMatrix.h boolNDArray.h
+ui16nda ui16 nda BCL boolMatrix.h boolNDArray.h
+i32nda nda i32 BCL boolMatrix.h boolNDArray.h
+i32nda i32 nda BCL boolMatrix.h boolNDArray.h
+ui32nda nda ui32 BCL boolMatrix.h boolNDArray.h
+ui32nda ui32 nda BCL boolMatrix.h boolNDArray.h
+i64nda nda i64 BCL boolMatrix.h boolNDArray.h
+i64nda i64 nda BCL boolMatrix.h boolNDArray.h
+ui64nda nda ui64 BCL boolMatrix.h boolNDArray.h
+ui64nda ui64 nda BCL boolMatrix.h boolNDArray.h
+i8nda fnda i8 BCL boolMatrix.h boolNDArray.h
+i8nda i8 fnda BCL boolMatrix.h boolNDArray.h
+ui8nda fnda ui8 BCL boolMatrix.h boolNDArray.h
+ui8nda ui8 fnda BCL boolMatrix.h boolNDArray.h
+i16nda fnda i16 BCL boolMatrix.h boolNDArray.h
+i16nda i16 fnda BCL boolMatrix.h boolNDArray.h
+ui16nda fnda ui16 BCL boolMatrix.h boolNDArray.h
+ui16nda ui16 fnda BCL boolMatrix.h boolNDArray.h
+i32nda fnda i32 BCL boolMatrix.h boolNDArray.h
+i32nda i32 fnda BCL boolMatrix.h boolNDArray.h
+ui32nda fnda ui32 BCL boolMatrix.h boolNDArray.h
+ui32nda ui32 fnda BCL boolMatrix.h boolNDArray.h
+i64nda fnda i64 BCL boolMatrix.h boolNDArray.h
+i64nda i64 fnda BCL boolMatrix.h boolNDArray.h
+ui64nda fnda ui64 BCL boolMatrix.h boolNDArray.h
+ui64nda ui64 fnda BCL boolMatrix.h boolNDArray.h
 #
-i8nda nda i8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda nda ui8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda nda i16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda nda ui16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda nda i32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda nda ui32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda nda i64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda nda ui64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64nda nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda fnda i8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i8nda i8nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda fnda ui8nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui8nda ui8nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda fnda i16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i16nda i16nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda fnda ui16nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui16nda ui16nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda fnda i32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i32nda i32nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda fnda ui32nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui32nda ui32nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda fnda i64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-i64nda i64nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda fnda ui64nda BCL NONE NONE boolMatrix.h boolNDArray.h
-ui64nda ui64nda fnda BCL NONE NONE boolMatrix.h boolNDArray.h
+i8nda nda i8nda BCL boolMatrix.h boolNDArray.h
+i8nda i8nda nda BCL boolMatrix.h boolNDArray.h
+ui8nda nda ui8nda BCL boolMatrix.h boolNDArray.h
+ui8nda ui8nda nda BCL boolMatrix.h boolNDArray.h
+i16nda nda i16nda BCL boolMatrix.h boolNDArray.h
+i16nda i16nda nda BCL boolMatrix.h boolNDArray.h
+ui16nda nda ui16nda BCL boolMatrix.h boolNDArray.h
+ui16nda ui16nda nda BCL boolMatrix.h boolNDArray.h
+i32nda nda i32nda BCL boolMatrix.h boolNDArray.h
+i32nda i32nda nda BCL boolMatrix.h boolNDArray.h
+ui32nda nda ui32nda BCL boolMatrix.h boolNDArray.h
+ui32nda ui32nda nda BCL boolMatrix.h boolNDArray.h
+i64nda nda i64nda BCL boolMatrix.h boolNDArray.h
+i64nda i64nda nda BCL boolMatrix.h boolNDArray.h
+ui64nda nda ui64nda BCL boolMatrix.h boolNDArray.h
+ui64nda ui64nda nda BCL boolMatrix.h boolNDArray.h
+i8nda fnda i8nda BCL boolMatrix.h boolNDArray.h
+i8nda i8nda fnda BCL boolMatrix.h boolNDArray.h
+ui8nda fnda ui8nda BCL boolMatrix.h boolNDArray.h
+ui8nda ui8nda fnda BCL boolMatrix.h boolNDArray.h
+i16nda fnda i16nda BCL boolMatrix.h boolNDArray.h
+i16nda i16nda fnda BCL boolMatrix.h boolNDArray.h
+ui16nda fnda ui16nda BCL boolMatrix.h boolNDArray.h
+ui16nda ui16nda fnda BCL boolMatrix.h boolNDArray.h
+i32nda fnda i32nda BCL boolMatrix.h boolNDArray.h
+i32nda i32nda fnda BCL boolMatrix.h boolNDArray.h
+ui32nda fnda ui32nda BCL boolMatrix.h boolNDArray.h
+ui32nda ui32nda fnda BCL boolMatrix.h boolNDArray.h
+i64nda fnda i64nda BCL boolMatrix.h boolNDArray.h
+i64nda i64nda fnda BCL boolMatrix.h boolNDArray.h
+ui64nda fnda ui64nda BCL boolMatrix.h boolNDArray.h
+ui64nda ui64nda fnda BCL boolMatrix.h boolNDArray.h
 #
-x i8nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x i8nda ui8 CL boolMatrix.h boolNDArray.h
+x i8nda i16 CL boolMatrix.h boolNDArray.h
+x i8nda ui16 CL boolMatrix.h boolNDArray.h
+x i8nda i32 CL boolMatrix.h boolNDArray.h
+x i8nda ui32 CL boolMatrix.h boolNDArray.h
+x i8nda i64 CL boolMatrix.h boolNDArray.h
+x i8nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x i16nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x i16nda i8 CL boolMatrix.h boolNDArray.h
+x i16nda ui8 CL boolMatrix.h boolNDArray.h
+x i16nda ui16 CL boolMatrix.h boolNDArray.h
+x i16nda i32 CL boolMatrix.h boolNDArray.h
+x i16nda ui32 CL boolMatrix.h boolNDArray.h
+x i16nda i64 CL boolMatrix.h boolNDArray.h
+x i16nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x i32nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x i32nda i8 CL boolMatrix.h boolNDArray.h
+x i32nda ui8 CL boolMatrix.h boolNDArray.h
+x i32nda i16 CL boolMatrix.h boolNDArray.h
+x i32nda ui16 CL boolMatrix.h boolNDArray.h
+x i32nda ui32 CL boolMatrix.h boolNDArray.h
+x i32nda i64 CL boolMatrix.h boolNDArray.h
+x i32nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x i64nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x i64nda i8 CL boolMatrix.h boolNDArray.h
+x i64nda ui8 CL boolMatrix.h boolNDArray.h
+x i64nda i16 CL boolMatrix.h boolNDArray.h
+x i64nda ui16 CL boolMatrix.h boolNDArray.h
+x i64nda i32 CL boolMatrix.h boolNDArray.h
+x i64nda ui32 CL boolMatrix.h boolNDArray.h
+x i64nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x ui8nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x ui8nda i8 CL boolMatrix.h boolNDArray.h
+x ui8nda i16 CL boolMatrix.h boolNDArray.h
+x ui8nda ui16 CL boolMatrix.h boolNDArray.h
+x ui8nda i32 CL boolMatrix.h boolNDArray.h
+x ui8nda ui32 CL boolMatrix.h boolNDArray.h
+x ui8nda i64 CL boolMatrix.h boolNDArray.h
+x ui8nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x ui16nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x ui16nda i8 CL boolMatrix.h boolNDArray.h
+x ui16nda ui8 CL boolMatrix.h boolNDArray.h
+x ui16nda i16 CL boolMatrix.h boolNDArray.h
+x ui16nda i32 CL boolMatrix.h boolNDArray.h
+x ui16nda ui32 CL boolMatrix.h boolNDArray.h
+x ui16nda i64 CL boolMatrix.h boolNDArray.h
+x ui16nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x ui32nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui64 CL NONE NONE boolMatrix.h boolNDArray.h
+x ui32nda i8 CL boolMatrix.h boolNDArray.h
+x ui32nda ui8 CL boolMatrix.h boolNDArray.h
+x ui32nda i16 CL boolMatrix.h boolNDArray.h
+x ui32nda ui16 CL boolMatrix.h boolNDArray.h
+x ui32nda i32 CL boolMatrix.h boolNDArray.h
+x ui32nda i64 CL boolMatrix.h boolNDArray.h
+x ui32nda ui64 CL boolMatrix.h boolNDArray.h
 #
-x ui64nda i8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui8 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui16 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui32 CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i64 CL NONE NONE boolMatrix.h boolNDArray.h
+x ui64nda i8 CL boolMatrix.h boolNDArray.h
+x ui64nda ui8 CL boolMatrix.h boolNDArray.h
+x ui64nda i16 CL boolMatrix.h boolNDArray.h
+x ui64nda ui16 CL boolMatrix.h boolNDArray.h
+x ui64nda i32 CL boolMatrix.h boolNDArray.h
+x ui64nda ui32 CL boolMatrix.h boolNDArray.h
+x ui64nda i64 CL boolMatrix.h boolNDArray.h
 #
-x i8 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i8 ui8nda CL boolMatrix.h boolNDArray.h
+x i8 i16nda CL boolMatrix.h boolNDArray.h
+x i8 ui16nda CL boolMatrix.h boolNDArray.h
+x i8 i32nda CL boolMatrix.h boolNDArray.h
+x i8 ui32nda CL boolMatrix.h boolNDArray.h
+x i8 i64nda CL boolMatrix.h boolNDArray.h
+x i8 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i16 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i16 i8nda CL boolMatrix.h boolNDArray.h
+x i16 ui8nda CL boolMatrix.h boolNDArray.h
+x i16 ui16nda CL boolMatrix.h boolNDArray.h
+x i16 i32nda CL boolMatrix.h boolNDArray.h
+x i16 ui32nda CL boolMatrix.h boolNDArray.h
+x i16 i64nda CL boolMatrix.h boolNDArray.h
+x i16 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i32 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i32 i8nda CL boolMatrix.h boolNDArray.h
+x i32 ui8nda CL boolMatrix.h boolNDArray.h
+x i32 i16nda CL boolMatrix.h boolNDArray.h
+x i32 ui16nda CL boolMatrix.h boolNDArray.h
+x i32 ui32nda CL boolMatrix.h boolNDArray.h
+x i32 i64nda CL boolMatrix.h boolNDArray.h
+x i32 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i64 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i64 i8nda CL boolMatrix.h boolNDArray.h
+x i64 ui8nda CL boolMatrix.h boolNDArray.h
+x i64 i16nda CL boolMatrix.h boolNDArray.h
+x i64 ui16nda CL boolMatrix.h boolNDArray.h
+x i64 i32nda CL boolMatrix.h boolNDArray.h
+x i64 ui32nda CL boolMatrix.h boolNDArray.h
+x i64 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui8 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui8 i8nda CL boolMatrix.h boolNDArray.h
+x ui8 i16nda CL boolMatrix.h boolNDArray.h
+x ui8 ui16nda CL boolMatrix.h boolNDArray.h
+x ui8 i32nda CL boolMatrix.h boolNDArray.h
+x ui8 ui32nda CL boolMatrix.h boolNDArray.h
+x ui8 i64nda CL boolMatrix.h boolNDArray.h
+x ui8 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui16 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui16 i8nda CL boolMatrix.h boolNDArray.h
+x ui16 ui8nda CL boolMatrix.h boolNDArray.h
+x ui16 i16nda CL boolMatrix.h boolNDArray.h
+x ui16 i32nda CL boolMatrix.h boolNDArray.h
+x ui16 ui32nda CL boolMatrix.h boolNDArray.h
+x ui16 i64nda CL boolMatrix.h boolNDArray.h
+x ui16 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui32 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32 ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui32 i8nda CL boolMatrix.h boolNDArray.h
+x ui32 ui8nda CL boolMatrix.h boolNDArray.h
+x ui32 i16nda CL boolMatrix.h boolNDArray.h
+x ui32 ui16nda CL boolMatrix.h boolNDArray.h
+x ui32 i32nda CL boolMatrix.h boolNDArray.h
+x ui32 i64nda CL boolMatrix.h boolNDArray.h
+x ui32 ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui64 i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64 i64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui64 i8nda CL boolMatrix.h boolNDArray.h
+x ui64 ui8nda CL boolMatrix.h boolNDArray.h
+x ui64 i16nda CL boolMatrix.h boolNDArray.h
+x ui64 ui16nda CL boolMatrix.h boolNDArray.h
+x ui64 i32nda CL boolMatrix.h boolNDArray.h
+x ui64 ui32nda CL boolMatrix.h boolNDArray.h
+x ui64 i64nda CL boolMatrix.h boolNDArray.h
 #
-x i8nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i8nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i8nda ui8nda CL boolMatrix.h boolNDArray.h
+x i8nda i16nda CL boolMatrix.h boolNDArray.h
+x i8nda ui16nda CL boolMatrix.h boolNDArray.h
+x i8nda i32nda CL boolMatrix.h boolNDArray.h
+x i8nda ui32nda CL boolMatrix.h boolNDArray.h
+x i8nda i64nda CL boolMatrix.h boolNDArray.h
+x i8nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i16nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i16nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i16nda i8nda CL boolMatrix.h boolNDArray.h
+x i16nda ui8nda CL boolMatrix.h boolNDArray.h
+x i16nda ui16nda CL boolMatrix.h boolNDArray.h
+x i16nda i32nda CL boolMatrix.h boolNDArray.h
+x i16nda ui32nda CL boolMatrix.h boolNDArray.h
+x i16nda i64nda CL boolMatrix.h boolNDArray.h
+x i16nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i32nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i32nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i32nda i8nda CL boolMatrix.h boolNDArray.h
+x i32nda ui8nda CL boolMatrix.h boolNDArray.h
+x i32nda i16nda CL boolMatrix.h boolNDArray.h
+x i32nda ui16nda CL boolMatrix.h boolNDArray.h
+x i32nda ui32nda CL boolMatrix.h boolNDArray.h
+x i32nda i64nda CL boolMatrix.h boolNDArray.h
+x i32nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x i64nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x i64nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x i64nda i8nda CL boolMatrix.h boolNDArray.h
+x i64nda ui8nda CL boolMatrix.h boolNDArray.h
+x i64nda i16nda CL boolMatrix.h boolNDArray.h
+x i64nda ui16nda CL boolMatrix.h boolNDArray.h
+x i64nda i32nda CL boolMatrix.h boolNDArray.h
+x i64nda ui32nda CL boolMatrix.h boolNDArray.h
+x i64nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui8nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui8nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui8nda i8nda CL boolMatrix.h boolNDArray.h
+x ui8nda i16nda CL boolMatrix.h boolNDArray.h
+x ui8nda ui16nda CL boolMatrix.h boolNDArray.h
+x ui8nda i32nda CL boolMatrix.h boolNDArray.h
+x ui8nda ui32nda CL boolMatrix.h boolNDArray.h
+x ui8nda i64nda CL boolMatrix.h boolNDArray.h
+x ui8nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui16nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui16nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui16nda i8nda CL boolMatrix.h boolNDArray.h
+x ui16nda ui8nda CL boolMatrix.h boolNDArray.h
+x ui16nda i16nda CL boolMatrix.h boolNDArray.h
+x ui16nda i32nda CL boolMatrix.h boolNDArray.h
+x ui16nda ui32nda CL boolMatrix.h boolNDArray.h
+x ui16nda i64nda CL boolMatrix.h boolNDArray.h
+x ui16nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui32nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui32nda ui64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui32nda i8nda CL boolMatrix.h boolNDArray.h
+x ui32nda ui8nda CL boolMatrix.h boolNDArray.h
+x ui32nda i16nda CL boolMatrix.h boolNDArray.h
+x ui32nda ui16nda CL boolMatrix.h boolNDArray.h
+x ui32nda i32nda CL boolMatrix.h boolNDArray.h
+x ui32nda i64nda CL boolMatrix.h boolNDArray.h
+x ui32nda ui64nda CL boolMatrix.h boolNDArray.h
 #
-x ui64nda i8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui8nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui16nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda ui32nda CL NONE NONE boolMatrix.h boolNDArray.h
-x ui64nda i64nda CL NONE NONE boolMatrix.h boolNDArray.h
+x ui64nda i8nda CL boolMatrix.h boolNDArray.h
+x ui64nda ui8nda CL boolMatrix.h boolNDArray.h
+x ui64nda i16nda CL boolMatrix.h boolNDArray.h
+x ui64nda ui16nda CL boolMatrix.h boolNDArray.h
+x ui64nda i32nda CL boolMatrix.h boolNDArray.h
+x ui64nda ui32nda CL boolMatrix.h boolNDArray.h
+x ui64nda i64nda CL boolMatrix.h boolNDArray.h
--- a/liboctave/operators/smx-ops	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/operators/smx-ops	Thu Dec 20 17:18:56 2018 -0500
@@ -21,7 +21,7 @@
 
 # types
 #
-# key typename object-type header fwd-decl-ok scalar-zero
+# key typename object-type header fwd-decl-ok
 #
 #   S:  scalar
 #   M:  matrix
@@ -29,19 +29,19 @@
 #   ND: N-d array
 #   SM: sparse matrix
 #
-sm SparseMatrix SM dSparse.h YES 0.0
-scm SparseComplexMatrix SM CSparse.h YES 0.0
-sbm SparseBoolMatrix SM boolSparse.h YES false
-b bool S NONE NO false
-bm boolMatrix M boolMatrix.h YES false
-s double S NONE NO 0.0
-cs Complex S oct-cmplx.h NO 0.0
-m Matrix M dMatrix.h YES 0.0
-cm ComplexMatrix M CMatrix.h YES 0.0
+sm SparseMatrix SM dSparse.h YES
+scm SparseComplexMatrix SM CSparse.h YES
+sbm SparseBoolMatrix SM boolSparse.h YES
+b bool S NONE NO
+bm boolMatrix M boolMatrix.h YES
+s double S NONE NO
+cs Complex S oct-cmplx.h NO
+m Matrix M dMatrix.h YES
+cm ComplexMatrix M CMatrix.h YES
 #
 # sparse-matrix operators
 #
-# result_t_1 result_t_2 lhs_t rhs_t op-type lhs_conv rhs_conv headers ...
+# result_t_1 result_t_2 lhs_t rhs_t op-type headers ...
 #
 # op-type is one of
 #
@@ -50,19 +50,19 @@
 #   E: == != (Only one of C or E can be used!!)
 #   L: logical ops, & |
 #
-cm scm sm cs BCL NONE real boolSparse.h
-cm scm cs sm BCL real NONE boolSparse.h
-cm scm scm s BCL real NONE boolSparse.h
-cm scm s scm BCL NONE real boolSparse.h
-scm scm scm sm BCL real NONE boolSparse.h
-scm scm sm scm BCL NONE real boolSparse.h
-m sm m sm BCL NONE NONE boolSparse.h
-cm scm m scm BCL NONE real boolSparse.h
-cm scm cm sm BCL real NONE boolSparse.h
-cm scm cm scm BCL real real boolSparse.h
-m sm sm m BCL NONE NONE boolSparse.h
-cm scm scm m BCL real NONE boolSparse.h
-cm scm sm cm BCL NONE real boolSparse.h
-cm scm scm cm BCL real real boolSparse.h
+cm scm sm cs BCL boolSparse.h
+cm scm cs sm BCL boolSparse.h
+cm scm scm s BCL boolSparse.h
+cm scm s scm BCL boolSparse.h
+scm scm scm sm BCL boolSparse.h
+scm scm sm scm BCL boolSparse.h
+m sm m sm BCL boolSparse.h
+cm scm m scm BCL boolSparse.h
+cm scm cm sm BCL boolSparse.h
+cm scm cm scm BCL boolSparse.h
+m sm sm m BCL boolSparse.h
+cm scm scm m BCL boolSparse.h
+cm scm sm cm BCL boolSparse.h
+cm scm scm cm BCL boolSparse.h
 bm sbm bm sbm EL
 bm sbm sbm bm EL
--- a/liboctave/system/dir-ops.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/dir-ops.h	Thu Dec 20 17:18:56 2018 -0500
@@ -97,11 +97,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::dir_entry' instead")
-typedef octave::sys::dir_entry dir_entry;
-
 #endif
-
-#endif
--- a/liboctave/system/file-ops.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/file-ops.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -33,7 +33,6 @@
 #  include <algorithm>
 #endif
 
-#include <iostream>
 #include <vector>
 
 #include "areadlink-wrapper.h"
@@ -42,6 +41,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "gen-tempname-wrapper.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
 #include "oct-passwd.h"
@@ -501,13 +501,19 @@
       return rename (from, to, msg);
     }
 
-    int rename (const std::string& from, const std::string& to, std::string& msg)
+    int rename (const std::string& from, const std::string& to,
+                std::string& msg)
     {
       int status = -1;
 
       msg = "";
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      status = _wrename (u8_to_wstring (from).c_str (),
+                         u8_to_wstring (to).c_str ());
+#else
       status = std::rename (from.c_str (), to.c_str ());
+#endif
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -549,12 +555,10 @@
 
       int status = 0;
 
-      dir_entry dir (name);
+      string_vector dirlist;
 
-      if (dir)
+      if (get_dirlist (name, dirlist, msg))
         {
-          string_vector dirlist = dir.read ();
-
           for (octave_idx_type i = 0; i < dirlist.numel (); i++)
             {
               octave_quit ();
@@ -595,17 +599,10 @@
             }
 
           if (status >= 0)
-            {
-              dir.close ();
-              status = rmdir (name, msg);
-            }
+            status = rmdir (name, msg);
         }
       else
-        {
-          status = -1;
-
-          msg = dir.error ();
-        }
+        status = -1;
 
       return status;
     }
--- a/liboctave/system/file-ops.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/file-ops.h	Thu Dec 20 17:18:56 2018 -0500
@@ -181,172 +181,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::mkdir' instead")
-inline int
-octave_mkdir (const std::string& nm, mode_t md)
-{
-  return octave::sys::mkdir (nm, md);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::mkdir' instead")
-inline int
-octave_mkdir (const std::string& nm, mode_t md, std::string& msg)
-{
-  return octave::sys::mkdir (nm, md, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::mkfifo' instead")
-inline int
-octave_mkfifo (const std::string& nm, mode_t md)
-{
-  return octave::sys::mkfifo (nm, md);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::mkfifo' instead")
-inline int
-octave_mkfifo (const std::string& nm, mode_t md, std::string& msg)
-{
-  return octave::sys::mkfifo (nm, md, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::link' instead")
-inline int
-octave_link (const std::string& old_name, const std::string& new_name)
-{
-  return octave::sys::link (old_name, new_name);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::link' instead")
-inline int
-octave_link (const std::string& old_name, const std::string& new_name,
-             std::string& msg)
-{
-  return octave::sys::link (old_name, new_name, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::symlink' instead")
-inline int
-octave_symlink (const std::string& old_name, const std::string& new_name)
-{
-  return octave::sys::symlink (old_name, new_name);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::symlink' instead")
-inline int
-octave_symlink (const std::string& old_name, const std::string& new_name,
-                std::string& msg)
-{
-  return octave::sys::symlink (old_name, new_name, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::readlink' instead")
-inline int
-octave_readlink (const std::string& path, std::string& result)
-{
-  return octave::sys::readlink (path, result);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::readlink' instead")
-inline int
-octave_readlink (const std::string& path, std::string& result, std::string& msg)
-{
-  return octave::sys::readlink (path, result, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::rename' instead")
-inline int
-octave_rename (const std::string& from, const std::string& to)
-{
-  return octave::sys::rename (from, to);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::rename' instead")
-inline int
-octave_rename (const std::string& from, const std::string& to, std::string& msg)
-{
-  return octave::sys::rename (from, to, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::rmdir' instead")
-inline int
-octave_rmdir (const std::string& nm)
-{
-  return octave::sys::rmdir (nm);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::rmdir' instead")
-inline int
-octave_rmdir (const std::string& nm, std::string& msg)
-{
-  return octave::sys::rmdir (nm, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::recursive_rmdir' instead")
-inline int
-octave_recursive_rmdir (const std::string& nm)
-{
-  return octave::sys::recursive_rmdir (nm);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::recursive_rmdir' instead")
-inline int
-octave_recursive_rmdir (const std::string& nm, std::string& msg)
-{
-  return octave::sys::recursive_rmdir (nm, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::umask' instead")
-inline int
-octave_umask (mode_t md)
-{
-  return octave::sys::umask (md);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::unlink' instead")
-inline int
-octave_unlink (const std::string& nm)
-{
-  return octave::sys::unlink (nm);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::unlink' instead")
-inline int
-octave_unlink (const std::string& nm, std::string& msg)
-{
-  return octave::sys::unlink (nm, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::tempnam' instead")
-inline std::string
-octave_tempnam (const std::string& dir, const std::string& pfx)
-{
-  return octave::sys::tempnam (dir, pfx);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::tempnam' instead")
-inline std::string
-octave_tempnam (const std::string& dir, const std::string& pfx,
-                std::string& msg)
-{
-  return octave::sys::tempnam (dir, pfx, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::canonicalize_file_name' instead")
-inline std::string
-octave_canonicalize_file_name (const std::string& nm)
-{
-  return octave::sys::canonicalize_file_name (nm);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::canonicalize_file_name' instead")
-inline std::string
-octave_canonicalize_file_name (const std::string& nm, std::string& msg)
-{
-  return octave::sys::canonicalize_file_name (nm, msg);
-}
-
 #endif
-
-#endif
--- a/liboctave/system/file-stat.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/file-stat.h	Thu Dec 20 17:18:56 2018 -0500
@@ -322,17 +322,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::base_file_stat' instead")
-typedef octave::sys::base_file_stat base_file_stat;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::file_stat' instead")
-typedef octave::sys::file_stat file_stat;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::file_fstat' instead")
-typedef octave::sys::file_fstat file_fstat;
-
 #endif
-
-#endif
--- a/liboctave/system/lo-sysdep.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/lo-sysdep.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,10 +26,21 @@
 
 #include <string>
 
+#include "dir-ops.h"
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "putenv-wrapper.h"
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
+#include "unsetenv-wrapper.h"
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+
+#  include "lo-hash.h"
+#endif
 
 namespace octave
 {
@@ -67,5 +78,329 @@
 
       return octave_chdir_wrapper (path.c_str ());
     }
+
+    bool
+    get_dirlist (const std::string& dirname, string_vector& dirlist, std::string& msg)
+    {
+      dirlist = "";
+      msg = "";
+#if defined (OCTAVE_USE_WINDOWS_API)
+      _WIN32_FIND_DATAW ffd;
+
+      std::string path_name (dirname);
+      if (path_name.empty ())
+        return true;
+
+      if (path_name.back () == '\\' || path_name.back () == '/')
+        path_name.push_back ('*');
+      else
+        path_name.append (R"(\*)");
+
+      // Find first file in directory.
+      HANDLE hFind = FindFirstFileW (u8_to_wstring (path_name).c_str (),
+                              &ffd);
+      if (INVALID_HANDLE_VALUE == hFind)
+        {
+          DWORD errCode = GetLastError ();
+          char *errorText = nullptr;
+          FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
+                         FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS,
+                         nullptr, errCode,
+                         MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                         reinterpret_cast <char *> (&errorText), 0, nullptr);
+          if (errorText != nullptr)
+            {
+              msg = std::string (errorText);
+              LocalFree (errorText);
+            }
+          return false;
+        }
+
+      std::list<std::string> dirlist_str;
+      do
+        dirlist_str.push_back (u8_from_wstring (ffd.cFileName));
+      while (FindNextFileW (hFind, &ffd) != 0);
+
+      FindClose(hFind);
+
+      dirlist = string_vector (dirlist_str);
+
+#else
+
+      dir_entry dir (dirname);
+
+      if (! dir)
+        {
+          msg = dir.error ();
+          return false;
+        }
+
+      dirlist = dir.read ();
+
+      dir.close ();
+#endif
+
+      return true;
+    }
+
+    std::FILE *
+    fopen (const std::string& filename, const std::string& mode)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      return _wfopen (u8_to_wstring (filename).c_str (),
+                      u8_to_wstring (mode).c_str ());
+#else
+      return std::fopen (filename.c_str (), mode.c_str ());
+#endif
+    }
+
+    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.
+
+      int new_len = name.length () + value.length () + 2;
+
+      // FIXME: This 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));
+
+      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);
+      std::free (static_cast<void *> (new_item));
+      if (_wputenv (wnew_item) < 0)
+        (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
+#else
+      if (octave_putenv_wrapper (new_item) < 0)
+        (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
+#endif
+    }
+
+    std::string
+    getenv_wrapper (const std::string& name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t *env = _wgetenv (u8_to_wstring (name).c_str ());
+      return env ? u8_from_wstring (env) : "";
+#else
+      char *env = ::getenv (name.c_str ());
+      return env ? env : "";
+#endif
+    }
+
+    int
+    unsetenv_wrapper (const std::string& name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      putenv_wrapper (name, "");
+
+      std::wstring wname = u8_to_wstring (name);
+      return (SetEnvironmentVariableW (wname.c_str (), nullptr) ? 0 : -1);
+#else
+      return octave_unsetenv_wrapper (name.c_str ());
+#endif
+    }
+
+    std::wstring
+    u8_to_wstring (const std::string& utf8_string)
+    {
+      size_t srclen = utf8_string.length ();
+      const uint8_t *src = reinterpret_cast<const uint8_t *>
+                           (utf8_string.c_str ());
+
+      size_t length = 0;
+      wchar_t *wchar = reinterpret_cast<wchar_t *>
+                       (octave_u8_conv_to_encoding ("wchar_t", src, srclen,
+                                                    &length));
+
+      std::wstring retval = L"";
+      if (wchar != nullptr)
+        {
+          retval = std::wstring (wchar, length / sizeof (wchar_t));
+          free (static_cast<void *> (wchar));
+        }
+
+      return retval;
+    }
+
+    std::string
+    u8_from_wstring (const std::wstring& wchar_string)
+    {
+      size_t srclen = wchar_string.length () * sizeof (wchar_t);
+      const char *src = reinterpret_cast<const char *> (wchar_string.c_str ());
+
+      size_t length = 0;
+      char *mbchar = reinterpret_cast<char *>
+                     (octave_u8_conv_from_encoding ("wchar_t", src, srclen,
+                                                    &length));
+
+      std::string retval = "";
+      if (mbchar != nullptr)
+        {
+          retval = std::string (mbchar, length);
+          free (static_cast<void *> (mbchar));
+        }
+
+      return retval;
+    }
+
+    // At quite a few places in the code we are passing file names as
+    // char arrays to external library functions.
+
+    // When these functions try to locate the corresponding file on the
+    // disc, they need to use the wide character API on Windows to
+    // correctly open files with non-ASCII characters.
+
+    // But they have no way of knowing which encoding we are using for
+    // the passed string.  So they have no way of reliably converting to
+    // a wchar_t array.  (I.e. there is no possible fix for these
+    // functions with current C or C++.)
+
+    // To solve the dilemma, the function "get_ASCII_filename" first
+    // 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.
+
+    // 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
+    // possible level that doesn't contain non-ASCII characters.  At
+    // that level a hidden folder is created that holds the hard links.
+    // That means we need to have write access on that location.  A path
+    // to that hard link is returned.
+
+    // If the file system is FAT32, there are no hard links.  But FAT32
+    // always stores short file names.  So we are safe.
+
+    // ExFAT that is occasionally used on USB sticks and SD cards stores
+    // neither short file names nor does it support hard links.  So for
+    // exFAT with this function, there is (currently) no way to generate
+    // a file name that is stripped from non-ASCII characters but still
+    // is valid.
+
+    // For Unixy systems, this function does nothing.
+
+    std::string
+    get_ASCII_filename (const std::string& orig_file_name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+
+      // Return file name that only contains ASCII characters that can
+      // be used to access the file orig_file_name.  The original file
+      // must exist in the file system before calling this function.
+      // 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.
+
+      std::string::const_iterator first_non_ASCII
+        = std::find_if (orig_file_name.begin (), orig_file_name.end (),
+                        [](char c) { return (c < 0 || c >= 128); });
+
+      if (first_non_ASCII == orig_file_name.end ())
+        return orig_file_name;
+
+      // 2. Check if file system stores short filenames (always
+      // 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 ();
+
+      // Get full path to file
+      wchar_t w_full_file_name[_MAX_PATH];
+      if (_wfullpath (w_full_file_name, w_orig_file_name, _MAX_PATH) == nullptr)
+        return orig_file_name;
+
+      std::wstring w_full_file_name_str = w_full_file_name;
+
+      // Get short filename (8.3) from UTF-16 filename.
+
+      long length = GetShortPathNameW (w_full_file_name, nullptr, 0);
+
+      if (length > 0)
+        {
+          // Dynamically allocate the correct size (terminating null char
+          // was included in length).
+
+          wchar_t *w_short_file_name = new wchar_t[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;
+        }
+
+      // 3. Create hard link with only-ASCII characters.
+      // Get longest possible part of path that only contains ASCII chars.
+
+      std::wstring::iterator w_first_non_ASCII
+        = std::find_if (w_full_file_name_str.begin (), w_full_file_name_str.end (),
+                        [](wchar_t c) { return (c < 0 || c >= 128); });
+      std::wstring tmp_substr
+        = std::wstring (w_full_file_name_str.begin (), w_first_non_ASCII);
+
+      size_t pos
+        = tmp_substr.find_last_of (u8_to_wstring (file_ops::dir_sep_chars ()));
+
+      std::string par_dir
+        = u8_from_wstring (w_full_file_name_str.substr (0, pos+1));
+
+      // Create .oct_ascii directory.
+      // FIXME: We need to have write permission in this location.
+
+      std::string oct_ascii_dir = par_dir + ".oct_ascii";
+      std::string test_dir = canonicalize_file_name (oct_ascii_dir);
+
+      if (test_dir.empty ())
+      {
+        std::string msg;
+        int status = octave::sys::mkdir (oct_ascii_dir, 0777, msg);
+
+        if (status < 0)
+          return orig_file_name;
+
+        // Set hidden property.
+        SetFileAttributesA (oct_ascii_dir.c_str (), FILE_ATTRIBUTE_HIDDEN);
+      }
+
+      // Create file from hash of full filename.
+      std::string filename_hash
+        = (oct_ascii_dir + file_ops::dir_sep_str ()
+           + octave::crypto::hash ("SHA1", orig_file_name));
+
+      std::string abs_filename_hash = canonicalize_file_name (filename_hash);
+
+      if (! abs_filename_hash.empty ())
+        octave::sys::unlink (filename_hash);
+
+      wchar_t w_filename_hash[filename_hash.length ()+1] = {0};
+
+      for (size_t i=0; i < filename_hash.length (); i++)
+        w_filename_hash[i] = filename_hash.at (i);
+
+      if (CreateHardLinkW (w_filename_hash, w_orig_file_name, nullptr))
+        return filename_hash;
+
+#endif
+
+      return orig_file_name;
+    }
   }
 }
--- a/liboctave/system/lo-sysdep.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/lo-sysdep.h	Thu Dec 20 17:18:56 2018 -0500
@@ -40,17 +40,25 @@
     extern std::string getcwd (void);
 
     extern int chdir (const std::string&);
+
+    extern bool get_dirlist (const std::string& dirname, string_vector& dirlist,
+                             std::string& msg);
+
+    extern std::FILE * fopen (const std::string& name, const std::string& mode);
+
+    extern void putenv_wrapper (const std::string& name,
+                                const std::string& value);
+
+    extern std::string getenv_wrapper (const std::string&);
+
+    extern int unsetenv_wrapper (const std::string&);
+
+    extern std::wstring u8_to_wstring (const std::string&);
+
+    extern std::string u8_from_wstring (const std::wstring&);
+
+    extern std::string get_ASCII_filename (const std::string& long_file_name);
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::getcwd' instead")
-const auto octave_getcwd = octave::sys::getcwd;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::chdir' instead")
-const auto octave_chdir = octave::sys::chdir;
-
 #endif
-
-#endif
--- a/liboctave/system/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -38,8 +38,4 @@
 
 %canon_reldir%_libsystem_la_CPPFLAGS = $(liboctave_liboctave_la_CPPFLAGS)
 
-%canon_reldir%_libsystem_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_libsystem_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/libsystem.la
--- a/liboctave/system/oct-env.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-env.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -241,7 +241,7 @@
     void
     env::putenv (const std::string& name, const std::string& value)
     {
-      octave_putenv (name, value);
+      putenv_wrapper (name, value);
     }
 
     bool
@@ -531,9 +531,7 @@
     std::string
     env::do_getenv (const std::string& name) const
     {
-      char *value = ::getenv (name.c_str ());
-
-      return value ? value : "";
+      return getenv_wrapper (name);
     }
 
     // Do the work of changing to the directory NEWDIR.
--- a/liboctave/system/oct-env.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-env.h	Thu Dec 20 17:18:56 2018 -0500
@@ -150,11 +150,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::env' instead")
-typedef octave::sys::env octave_env;
-
 #endif
-
-#endif
--- a/liboctave/system/oct-group.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-group.h	Thu Dec 20 17:18:56 2018 -0500
@@ -115,11 +115,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::group' instead")
-typedef octave::sys::group octave_group;
-
 #endif
-
-#endif
--- a/liboctave/system/oct-passwd.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-passwd.h	Thu Dec 20 17:18:56 2018 -0500
@@ -135,11 +135,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::password' instead")
-typedef octave::sys::password octave_passwd;
-
 #endif
-
-#endif
--- a/liboctave/system/oct-syscalls.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-syscalls.h	Thu Dec 20 17:18:56 2018 -0500
@@ -103,33 +103,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::popen2' instead")
-inline pid_t
-octave_popen2 (const std::string& cmd, const string_vector& args,
-               bool sync_mode, int *filedes)
-{
-  return octave::sys::popen2 (cmd, args, sync_mode, filedes);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::popen2' instead")
-inline pid_t
-popen2 (const std::string& cmd, const string_vector& args,
-        bool sync_mode, int *filedes, std::string& msg)
-{
-  return octave::sys::popen2 (cmd, args, sync_mode, filedes, msg);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::popen2' instead")
-inline pid_t
-popen2 (const std::string& cmd, const string_vector& args,
-        bool sync_mode, int *filedes, std::string& msg,
-        bool &/*interactive*/)
-{
-  return octave::sys::popen2 (cmd, args, sync_mode, filedes, msg);
-}
-
 #endif
-
-#endif
--- a/liboctave/system/oct-time.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-time.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,8 +28,8 @@
 #include <ctime>
 
 #include <iomanip>
-#include <iostream>
 #include <limits>
+#include <ostream>
 
 #include "lo-error.h"
 #include "lo-utils.h"
--- a/liboctave/system/oct-time.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-time.h	Thu Dec 20 17:18:56 2018 -0500
@@ -536,23 +536,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::time' instead")
-typedef octave::sys::time octave_time;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::base_tm' instead")
-typedef octave::sys::base_tm octave_base_tm;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::localtime' instead")
-typedef octave::sys::localtime octave_localtime;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::gmtime' instead")
-typedef octave::sys::gmtime octave_gmtime;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::strptime' instead")
-typedef octave::sys::strptime octave_strptime;
-
 #endif
-
-#endif
--- a/liboctave/system/oct-uname.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/system/oct-uname.h	Thu Dec 20 17:18:56 2018 -0500
@@ -94,11 +94,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::uname' instead")
-typedef octave::sys::uname octave_uname;
-
 #endif
-
-#endif
--- a/liboctave/util/action-container.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/action-container.h	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
 
 #include "octave-config.h"
 
-#include <cstddef>
+#include <functional>
 
 // This class allows registering actions in a list for later
 // execution, either explicitly or when the container goes out of
@@ -34,9 +34,6 @@
 
 // FIXME: is there a better name for this class?
 
-// FIXME: we should probably be using std::function, std::bind, and
-// related c++11 features to implement this functionality.
-
 namespace octave
 {
   class
@@ -71,238 +68,16 @@
     {
     public:
 
-      fcn_elem (void (*fptr) (void))
-        : e_fptr (fptr) { }
-
-      void run (void) { e_fptr (); }
-
-    private:
-
-      void (*e_fptr) (void);
-    };
-
-    // An element that stores a variable of type T along with a void (*) (T)
-    // function pointer, and calls the function with the parameter.
-
-    template <typename T>
-    class fcn_arg_elem : public elem
-    {
-    public:
-
-      fcn_arg_elem (void (*fcn) (T), T arg)
-        : e_fcn (fcn), e_arg (arg) { }
-
-      // No copying!
-
-      fcn_arg_elem (const fcn_arg_elem&) = delete;
-
-      fcn_arg_elem& operator = (const fcn_arg_elem&) = delete;
-
-      void run (void) { e_fcn (e_arg); }
-
-    private:
-
-      void (*e_fcn) (T);
-
-      T e_arg;
-    };
-
-    // An element that stores a variable of type T along with a
-    // void (*) (const T&) function pointer, and calls the function with
-    // the parameter.
-
-    template <typename T>
-    class fcn_crefarg_elem : public elem
-    {
-    public:
-
-      fcn_crefarg_elem (void (*fcn) (const T&), const T& arg)
-        : e_fcn (fcn), e_arg (arg) { }
-
-      void run (void) { e_fcn (e_arg); }
-
-    private:
+      template <typename F, typename... Args>
+      fcn_elem (F&& fcn, Args&&... args)
+        : m_fcn (std::bind (fcn, args...))
+      { }
 
-      void (*e_fcn) (const T&);
-
-      T e_arg;
-    };
-
-    // An element for calling a member function.
-
-    template <typename T>
-    class method_elem : public elem
-    {
-    public:
-
-      method_elem (T *obj, void (T::*method) (void))
-        : e_obj (obj), e_method (method) { }
-
-      method_elem (T& obj, void (T::*method) (void))
-        : e_obj (&obj), e_method (method) { }
-
-      // No copying!
-
-      method_elem (const method_elem&) = delete;
-
-      method_elem operator = (const method_elem&) = delete;
-
-      void run (void) { (e_obj->*e_method) (); }
-
-    private:
-
-      T *e_obj;
-
-      void (T::*e_method) (void);
-    };
-
-    // An element for calling a member function with a single argument
-
-    template <typename T, typename A>
-    class method_arg_elem : public elem
-    {
-    public:
-
-      method_arg_elem (T *obj, void (T::*method) (A), A arg)
-        : e_obj (obj), e_method (method), e_arg (arg) { }
-
-      method_arg_elem (T& obj, void (T::*method) (A), A arg)
-        : e_obj (&obj), e_method (method), e_arg (arg) { }
-
-      // No copying!
-
-      method_arg_elem (const method_arg_elem&) = delete;
-
-      method_arg_elem operator = (const method_arg_elem&) = delete;
-
-      void run (void) { (e_obj->*e_method) (e_arg); }
+      void run (void) { m_fcn (); }
 
     private:
 
-      T *e_obj;
-
-      void (T::*e_method) (A);
-
-      A e_arg;
-    };
-
-    // An element for calling a member function with a single argument
-
-    template <typename T, typename A>
-    class method_crefarg_elem : public elem
-    {
-    public:
-
-      method_crefarg_elem (T *obj, void (T::*method) (const A&), const A& arg)
-        : e_obj (obj), e_method (method), e_arg (arg) { }
-
-      method_crefarg_elem (T& obj, void (T::*method) (const A&), const A& arg)
-        : e_obj (&obj), e_method (method), e_arg (arg) { }
-
-      // No copying!
-
-      method_crefarg_elem (const method_crefarg_elem&) = delete;
-
-      method_crefarg_elem operator = (const method_crefarg_elem&) = delete;
-
-      void run (void) { (e_obj->*e_method) (e_arg); }
-
-    private:
-
-      T *e_obj;
-
-      void (T::*e_method) (const A&);
-
-      A e_arg;
-    };
-
-    /// An element for calling a member function with two arguments
-    template <class T, class A, class B>
-    class method_arg2_elem : public elem
-    {
-    public:
-      method_arg2_elem (T *obj, void (T::*method) (const A&, const B&),
-                        const A& arg_a, const B& arg_b)
-        : e_obj (obj), e_method (method),
-          e_arg_a (arg_a), e_arg_b (arg_b) { }
-
-      void run (void) { (e_obj->*e_method) (e_arg_a, e_arg_b); }
-
-    private:
-
-      T *e_obj;
-      void (T::*e_method) (const A&, const B&);
-      A e_arg_a;
-      B e_arg_b;
-
-      // No copying!
-
-      method_arg2_elem (const method_arg2_elem&);
-
-      method_arg2_elem operator = (const method_arg2_elem&);
-    };
-
-    /// An element for calling a member function with three arguments
-    template <class T, class A, class B, class C>
-    class method_arg3_elem : public elem
-    {
-    public:
-      method_arg3_elem (T *obj,
-                        void (T::*method) (const A&, const B&, const C&),
-                        const A& arg_a, const B& arg_b, const C& arg_c)
-        : e_obj (obj), e_method (method),
-          e_arg_a (arg_a), e_arg_b (arg_b), e_arg_c (arg_c)
-      { }
-
-      void run (void) { (e_obj->*e_method) (e_arg_a, e_arg_b, e_arg_c); }
-
-    private:
-
-      T *e_obj;
-      void (T::*e_method) (const A&, const B&, const C&);
-      A e_arg_a;
-      B e_arg_b;
-      C e_arg_c;
-
-      // No copying!
-
-      method_arg3_elem (const method_arg3_elem&);
-
-      method_arg3_elem operator = (const method_arg3_elem&);
-    };
-
-    /// An element for calling a member function with three arguments
-    template <class T, class A, class B, class C, class D>
-    class method_arg4_elem : public elem
-    {
-    public:
-      method_arg4_elem (T *obj,
-                        void (T::*method) (const A&, const B&, const C&, const D&),
-                        const A& arg_a, const B& arg_b, const C& arg_c,
-                        const D& arg_d)
-        : e_obj (obj), e_method (method),
-          e_arg_a (arg_a), e_arg_b (arg_b), e_arg_c (arg_c), e_arg_d (arg_d)
-      { }
-
-      void run (void)
-      {
-        (e_obj->*e_method) (e_arg_a, e_arg_b, e_arg_c, e_arg_d);
-      }
-
-    private:
-
-      T *e_obj;
-      void (T::*e_method) (const A&, const B&, const C&, const D&);
-      A e_arg_a;
-      B e_arg_b;
-      C e_arg_c;
-      D e_arg_d;
-
-      // No copying!
-
-      method_arg4_elem (const method_arg4_elem&);
-
-      method_arg4_elem operator = (const method_arg4_elem&);
+      std::function<void (void)> m_fcn;
     };
 
     // An element that stores arbitrary variable, and restores it.
@@ -361,94 +136,33 @@
 
     virtual ~action_container (void) = default;
 
-    virtual void add (elem *new_elem) = 0;
-
-    // Call to void func (void).
-    void add_fcn (void (*fcn) (void))
-    {
-      add (new fcn_elem (fcn));
-    }
-
-    // Call to void func (T).
-    template <typename T>
-    void add_fcn (void (*action) (T), T val)
-    {
-      add (new fcn_arg_elem<T> (action, val));
-    }
-
-    // Call to void func (const T&).
-    template <typename T>
-    void add_fcn (void (*action) (const T&), const T& val)
+    template <typename F, typename... Args>
+    void add (F&& fcn, Args&&... args)
     {
-      add (new fcn_crefarg_elem<T> (action, val));
-    }
-
-    // Call to T::method (void).
-    template <typename T>
-    void add_method (T *obj, void (T::*method) (void))
-    {
-      add (new method_elem<T> (obj, method));
-    }
-
-    template <typename T>
-    void add_method (T& obj, void (T::*method) (void))
-    {
-      add (new method_elem<T> (obj, method));
-    }
-
-    // Call to T::method (A).
-    template <typename T, typename A>
-    void add_method (T *obj, void (T::*method) (A), A arg)
-    {
-      add (new method_arg_elem<T, A> (obj, method, arg));
+      add_action (new fcn_elem (std::forward<F> (fcn),
+                                std::forward<Args> (args)...));
     }
 
-    template <typename T, typename A>
-    void add_method (T& obj, void (T::*method) (A), A arg)
-    {
-      add (new method_arg_elem<T, A> (obj, method, arg));
-    }
+    // Use separate template types for function pointer parameter
+    // declarations and captured arguments so that differences in
+    // const are handled properly.
 
-    // Call to T::method (const A&).
-    template <typename T, typename A>
-    void add_method (T *obj, void (T::*method) (const A&), const A& arg)
+    template <typename... Params, typename... Args>
+    void add_fcn (void (*fcn) (Params...), Args&&... args)
     {
-      add (new method_crefarg_elem<T, A> (obj, method, arg));
-    }
-
-    template <typename T, typename A>
-    void add_method (T& obj, void (T::*method) (const A&), const A& arg)
-    {
-      add (new method_crefarg_elem<T, A> (obj, method, arg));
+      add_action (new fcn_elem (fcn, std::forward<Args> (args)...));
     }
 
-    // Call to T::method (A, B).
-    template <class T, class A, class B>
-    void add_method (T *obj, void (T::*method) (const A&, const B&),
-                     const A& arg_a, const B& arg_b)
+    template <typename T, typename... Params, typename... Args>
+    void add_method (T *obj, void (T::*method) (Params...), Args&&... args)
     {
-      add (new method_arg2_elem<T, A, B> (obj, method, arg_a, arg_b));
+      add_action (new fcn_elem (method, obj, std::forward<Args> (args)...));
     }
 
-    // Call to T::method (A, B, C).
-    template <class T, class A, class B, class C>
-    void add_method (T *obj,
-                     void (T::*method) (const A&, const B&, const C&),
-                     const A& arg_a, const B& arg_b, const C& arg_c)
+    template <typename T, typename... Params, typename... Args>
+    void add_method (T& obj, void (T::*method) (Params...), Args&&... args)
     {
-      add (new method_arg3_elem<T, A, B, C> (obj, method, arg_a,
-                                             arg_b, arg_c));
-    }
-
-    // Call to T::method (A, B, C, D).
-    template <class T, class A, class B, class C, class D>
-    void add_method (T *obj,
-                     void (T::*method) (const A&, const B&, const C&, const D&),
-                     const A& arg_a, const B& arg_b,
-                     const C& arg_c, const D& arg_d)
-    {
-      add (new method_arg4_elem<T, A, B, C, D> (obj, method, arg_a,
-                                                arg_b, arg_c, arg_d));
+      add_action (new fcn_elem (method, &obj, std::forward<Args> (args)...));
     }
 
     // Call to delete (T*).
@@ -456,21 +170,21 @@
     template <typename T>
     void add_delete (T *obj)
     {
-      add (new delete_ptr_elem<T> (obj));
+      add_action (new delete_ptr_elem<T> (obj));
     }
 
     // Protect any variable.
     template <typename T>
     void protect_var (T& var)
     {
-      add (new restore_var_elem<T> (var, var));
+      add_action (new restore_var_elem<T> (var, var));
     }
 
     // Protect any variable, value given.
     template <typename T>
     void protect_var (T& var, const T& val)
     {
-      add (new restore_var_elem<T> (var, val));
+      add_action (new restore_var_elem<T> (var, val));
     }
 
     operator bool (void) const { return ! empty (); }
@@ -504,6 +218,10 @@
     virtual size_t size (void) const = 0;
 
     bool empty (void) const { return size () == 0; }
+
+  protected:
+
+    virtual void add_action (elem *new_elem) = 0;
   };
 }
 
--- a/liboctave/util/base-list.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/base-list.h	Thu Dec 20 17:18:56 2018 -0500
@@ -44,91 +44,63 @@
     typedef typename std::list<elt_type>::const_reverse_iterator
                                                      const_reverse_iterator;
 
-    bool empty (void) const { return lst.empty (); }
+    bool empty (void) const { return m_lst.empty (); }
 
-    size_t size (void) const { return lst.size (); }
+    size_t size (void) const { return m_lst.size (); }
     size_t length (void) const { return size (); }
 
-    iterator erase (iterator pos) { return lst.erase (pos); }
+    iterator erase (iterator pos) { return m_lst.erase (pos); }
 
     template <typename P>
     void remove_if (P pred)
     {
-      lst.remove_if (pred);
-
-      // FIXME: kluge removed 8/7/13.  Eventually this commented
-      //        code should be deleted.
-      //
-      // FIXME: this kluge should be removed at some point.
-      // We would like to simply call
-      //
-      //   lst.remove_if (pred);
-      //
-      // but the Sun Studio compiler chokes on that.
-      //
-      // iterator b = lst.begin ();
-      // iterator e = lst.end ();
-      // while (b != e)
-      //   {
-      //     iterator n = b;
-      //     n++;
-      //     if (pred (*b))
-      //       lst.erase (b);
-      //     b = n;
-      //   }
+      m_lst.remove_if (pred);
     }
 
-    void clear (void) { lst.clear (); }
+    void clear (void) { m_lst.clear (); }
 
-    iterator begin (void) { return iterator (lst.begin ()); }
-    const_iterator begin (void) const { return const_iterator (lst.begin ()); }
+    iterator begin (void) { return iterator (m_lst.begin ()); }
+    const_iterator begin (void) const { return const_iterator (m_lst.begin ()); }
 
-    iterator end (void) { return iterator (lst.end ()); }
-    const_iterator end (void) const { return const_iterator (lst.end ()); }
+    iterator end (void) { return iterator (m_lst.end ()); }
+    const_iterator end (void) const { return const_iterator (m_lst.end ()); }
 
-    reverse_iterator rbegin (void) { return reverse_iterator (lst.rbegin ()); }
+    reverse_iterator rbegin (void) { return reverse_iterator (m_lst.rbegin ()); }
     const_reverse_iterator rbegin (void) const
-    { return const_reverse_iterator (lst.rbegin ()); }
+    { return const_reverse_iterator (m_lst.rbegin ()); }
 
-    reverse_iterator rend (void) { return reverse_iterator (lst.rend ()); }
+    reverse_iterator rend (void) { return reverse_iterator (m_lst.rend ()); }
     const_reverse_iterator rend (void) const
-    { return const_reverse_iterator (lst.rend ()); }
+    { return const_reverse_iterator (m_lst.rend ()); }
 
-    elt_type& front (void) { return lst.front (); }
-    elt_type& back (void) { return lst.back (); }
+    elt_type& front (void) { return m_lst.front (); }
+    elt_type& back (void) { return m_lst.back (); }
 
-    const elt_type& front (void) const { return lst.front (); }
-    const elt_type& back (void) const { return lst.back (); }
+    const elt_type& front (void) const { return m_lst.front (); }
+    const elt_type& back (void) const { return m_lst.back (); }
 
-    void push_front (const elt_type& s) { lst.push_front (s); }
-    void push_back (const elt_type& s) { lst.push_back (s); }
+    void push_front (const elt_type& s) { m_lst.push_front (s); }
+    void push_back (const elt_type& s) { m_lst.push_back (s); }
 
-    void pop_front (void) { lst.pop_front (); }
-    void pop_back (void) { lst.pop_back (); }
+    void pop_front (void) { m_lst.pop_front (); }
+    void pop_back (void) { m_lst.pop_back (); }
 
     // For backward compatibility.
-    void append (const elt_type& s) { lst.push_back (s); }
-
-    base_list (void) : lst () { }
+    void append (const elt_type& s) { m_lst.push_back (s); }
 
-    base_list (const std::list<elt_type>& l) : lst (l) { }
-
-    base_list (const base_list& bl) : lst (bl.lst) { }
+    base_list (void) = default;
 
-    base_list& operator = (const base_list& bl)
-    {
-      if (this != &bl)
-        {
-          lst = bl.lst;
-        }
-      return *this;
-    }
+    base_list (const std::list<elt_type>& l) : m_lst (l) { }
+
+    base_list (const base_list& bl) = default;
+
+    base_list& operator = (const base_list& bl) = default;
 
     virtual ~base_list (void) = default;
 
-  private:
+  protected:
 
-    std::list<elt_type> lst;
+    std::list<elt_type> m_lst;
   };
 }
 
--- a/liboctave/util/caseless-str.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/caseless-str.h	Thu Dec 20 17:18:56 2018 -0500
@@ -49,8 +49,8 @@
 
   bool operator < (const std::string& s) const
   {
-    const_iterator p1 = begin ();
-    const_iterator p2 = s.begin ();
+    auto p1 = begin ();
+    auto p2 = s.begin ();
 
     while (p1 != end () && p2 != s.end ())
       {
@@ -75,8 +75,8 @@
   // Case-insensitive comparison.
   bool compare (const std::string& s, size_t limit = std::string::npos) const
   {
-    const_iterator p1 = begin ();
-    const_iterator p2 = s.begin ();
+    auto p1 = begin ();
+    auto p2 = s.begin ();
 
     size_t k = 0;
 
--- a/liboctave/util/cmd-edit.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/cmd-edit.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -262,16 +262,6 @@
     octave_rl_add_defun ("operate-and-get-next",
                          gnu_readline::operate_and_get_next,
                          octave_rl_ctrl ('O'));
-
-    // And the history search functions.
-
-    octave_rl_add_defun ("history-search-backward",
-                         gnu_readline::history_search_backward,
-                         octave_rl_meta ('P'));
-
-    octave_rl_add_defun ("history-search-forward",
-                         gnu_readline::history_search_forward,
-                         octave_rl_meta ('N'));
   }
 
   void
@@ -788,7 +778,7 @@
 
     ::octave_rl_recover_from_interrupt ();
 
-    throw octave::interrupt_exception ();
+    throw interrupt_exception ();
   }
 
   int
--- a/liboctave/util/cmd-edit.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/cmd-edit.h	Thu Dec 20 17:18:56 2018 -0500
@@ -371,11 +371,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::command_editor' instead")
-typedef octave::command_editor command_editor;
-
 #endif
-
-#endif
--- a/liboctave/util/cmd-hist.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/cmd-hist.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,6 @@
 #include <cstring>
 
 #include <fstream>
-#include <iostream>
 #include <sstream>
 #include <string>
 
--- a/liboctave/util/cmd-hist.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/cmd-hist.h	Thu Dec 20 17:18:56 2018 -0500
@@ -233,11 +233,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::command_history' instead")
-typedef octave::command_history command_history;
-
 #endif
-
-#endif
--- a/liboctave/util/data-conv.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/data-conv.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,8 +27,9 @@
 #include <cctype>
 #include <cstdlib>
 
-#include <iostream>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <vector>
 
 #include "byte-swap.h"
--- a/liboctave/util/data-conv.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/data-conv.h	Thu Dec 20 17:18:56 2018 -0500
@@ -25,8 +25,6 @@
 
 #include "octave-config.h"
 
-#include <limits>
-
 #include "mach-info.h"
 #include "oct-inttypes-fwd.h"
 
--- a/liboctave/util/file-info.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/file-info.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -27,11 +27,11 @@
 
 #include <deque>
 #include <fstream>
-#include <iostream>
 
 #include "file-info.h"
 #include "file-stat.h"
 #include "lo-error.h"
+#include "lo-sysdep.h"
 
 namespace octave
 {
@@ -81,7 +81,9 @@
 
     size_t sz = fs.size ();
 
-    std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+    std::string ascii_fname = octave::sys::get_ASCII_filename (fname);
+
+    std::ifstream file (ascii_fname.c_str (), std::ios::in | std::ios::binary);
 
     if (file)
       {
--- a/liboctave/util/kpse.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/kpse.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -87,10 +87,6 @@
 
 unsigned int kpse_debug = 0;
 
-static std::string kpse_var_expand (const std::string& src);
-
-static std::string kpse_expand (const std::string& s);
-
 void
 kpse_path_iterator::set_end (void)
 {
@@ -383,6 +379,95 @@
   return ret_list;
 }
 
+/* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
+   home directory, and return a new malloced string.  If no ~, or no
+   <pwd.h>, just return NAME.  */
+
+static std::string
+kpse_tilde_expand (const std::string& name)
+{
+  std::string expansion;
+
+  /* If no leading tilde, do nothing.  */
+  if (name.empty () || name[0] != '~')
+    {
+      expansion = name;
+
+      /* If a bare tilde, return the home directory or '.'.  (Very
+         unlikely that the directory name will do anyone any good, but
+         ...  */
+    }
+  else if (name.length () == 1)
+    {
+      expansion = octave::sys::env::get_home_directory ();
+
+      if (expansion.empty ())
+        expansion = ".";
+
+      /* If '~/', remove any trailing / or replace leading // in $HOME.
+         Should really check for doubled intermediate slashes, too.  */
+    }
+  else if (IS_DIR_SEP (name[1]))
+    {
+      unsigned c = 1;
+      std::string home = octave::sys::env::get_home_directory ();
+
+      if (home.empty ())
+        home = ".";
+
+      size_t home_len = home.length ();
+
+      /* handle leading // */
+      if (home_len > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
+        home = home.substr (1);
+
+      /* omit / after ~ */
+      if (IS_DIR_SEP (home[home_len - 1]))
+        c++;
+
+      expansion = home + name.substr (c);
+
+      /* If '~user' or '~user/', look up user in the passwd database (but
+         OS/2 doesn't have this concept.  */
+    }
+  else
+#if defined (HAVE_PWD_H)
+    {
+      unsigned c = 2;
+
+      /* find user name */
+      while (name.length () > c && ! IS_DIR_SEP (name[c]))
+        c++;
+
+      std::string user = name.substr (1, c-1);
+
+      /* We only need the cast here for (deficient) systems
+         which do not declare 'getpwnam' in <pwd.h>.  */
+      octave::sys::password p = octave::sys::password::getpwnam (user);
+
+      /* If no such user, just use '.'.  */
+      std::string home = (p ? p.dir () : ".");
+
+      if (home.empty ())
+        home = ".";
+
+      /* handle leading // */
+      if (home.length () > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
+        home = home.substr (1);
+
+      /* If HOME ends in /, omit the / after ~user. */
+      if (name.length () > c && IS_DIR_SEP (home.back ()))
+        c++;
+
+      expansion = (name.length () > c ? home : home + name.substr (c));
+    }
+#else /* not HAVE_PWD_H */
+  expansion = name;
+#endif /* not HAVE_PWD_H */
+
+  return expansion;
+}
+
 /* Search PATH for ORIGINAL_NAME.  If ALL is false, or ORIGINAL_NAME is
    absolute_p, check ORIGINAL_NAME itself.  Otherwise, look at each
    element of PATH for the first readable ORIGINAL_NAME.
@@ -398,8 +483,8 @@
   std::list<std::string> ret_list;
   bool absolute_p;
 
-  /* Make a leading ~ count as an absolute filename, and expand $FOO's.  */
-  std::string name = kpse_expand (original_name);
+  /* Make a leading ~ count as an absolute filename.  */
+  std::string name = kpse_tilde_expand (original_name);
 
   /* If the first name is absolute or explicitly relative, no need to
      consider PATH at all.  */
@@ -440,7 +525,7 @@
 
 /* Search PATH for the first NAME.  */
 
-/* Call 'kpse_expand' on NAME.  If the result is an absolute or
+/* Perform tilde expansion on NAME.  If the result is an absolute or
    explicitly relative filename, check whether it is a readable
    (regular) file.
 
@@ -647,235 +732,20 @@
   return find_first_of (path, names, true);
 }
 
-/* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
-   home directory, and return a new malloced string.  If no ~, or no
-   <pwd.h>, just return NAME.  */
-
-static std::string
-kpse_tilde_expand (const std::string& name)
-{
-  std::string expansion;
-
-  /* If no leading tilde, do nothing.  */
-  if (name.empty () || name[0] != '~')
-    {
-      expansion = name;
-
-      /* If a bare tilde, return the home directory or '.'.  (Very
-         unlikely that the directory name will do anyone any good, but
-         ...  */
-    }
-  else if (name.length () == 1)
-    {
-      expansion = octave::sys::env::get_home_directory ();
-
-      if (expansion.empty ())
-        expansion = ".";
-
-      /* If '~/', remove any trailing / or replace leading // in $HOME.
-         Should really check for doubled intermediate slashes, too.  */
-    }
-  else if (IS_DIR_SEP (name[1]))
-    {
-      unsigned c = 1;
-      std::string home = octave::sys::env::get_home_directory ();
-
-      if (home.empty ())
-        home = ".";
-
-      size_t home_len = home.length ();
-
-      /* handle leading // */
-      if (home_len > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
-        home = home.substr (1);
-
-      /* omit / after ~ */
-      if (IS_DIR_SEP (home[home_len - 1]))
-        c++;
-
-      expansion = home + name.substr (c);
-
-      /* If '~user' or '~user/', look up user in the passwd database (but
-         OS/2 doesn't have this concept.  */
-    }
-  else
-#if defined (HAVE_PWD_H)
-    {
-      unsigned c = 2;
-
-      /* find user name */
-      while (name.length () > c && ! IS_DIR_SEP (name[c]))
-        c++;
-
-      std::string user = name.substr (1, c-1);
-
-      /* We only need the cast here for (deficient) systems
-         which do not declare 'getpwnam' in <pwd.h>.  */
-      octave::sys::password p = octave::sys::password::getpwnam (user);
-
-      /* If no such user, just use '.'.  */
-      std::string home = (p ? p.dir () : ".");
-
-      if (home.empty ())
-        home = ".";
-
-      /* handle leading // */
-      if (home.length () > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
-        home = home.substr (1);
-
-      /* If HOME ends in /, omit the / after ~user. */
-      if (name.length () > c && IS_DIR_SEP (home.back ()))
-        c++;
-
-      expansion = (name.length () > c ? home : home + name.substr (c));
-    }
-#else /* not HAVE_PWD_H */
-  expansion = name;
-#endif /* not HAVE_PWD_H */
-
-  return expansion;
-}
-
-/* Do variable expansion first so ~${USER} works.  (Besides, it's what the
-   shells do.)  */
-
-/* Call kpse_var_expand and kpse_tilde_expand (in that order).  Result
-   is always in fresh memory, even if no expansions were done.  */
-
-static std::string
-kpse_expand (const std::string& s)
-{
-  std::string var_expansion = kpse_var_expand (s);
-  return kpse_tilde_expand (var_expansion);
-}
-
-/* Forward declarations of functions from the original expand.c  */
-static std::list<std::string> brace_expand (const std::string&);
-
-/* If $KPSE_DOT is defined in the environment, prepend it to any relative
-   path components. */
-
-static std::string
-kpse_expand_kpse_dot (const std::string& path)
-{
-  std::string ret;
-  std::string kpse_dot = octave::sys::env::getenv ("KPSE_DOT");
-
-  if (kpse_dot.empty ())
-    return path;
-
-  for (kpse_path_iterator pi (path); pi != std::string::npos; pi++)
-    {
-      std::string elt = *pi;
-
-      /* Single "." get special treatment, as does "./" or its equivalent.  */
-
-      size_t elt_len = elt.length ();
-
-      if (kpse_absolute_p (elt, false))
-        ret += elt + ENV_SEP_STRING;
-      else if (elt_len == 1 && elt[0] == '.')
-        ret += kpse_dot + ENV_SEP_STRING;
-      else if (elt_len > 1 && elt[0] == '.' && IS_DIR_SEP (elt[1]))
-        ret += kpse_dot + elt.substr (1) + ENV_SEP_STRING;
-      else
-        ret += kpse_dot + DIR_SEP_STRING + elt + ENV_SEP_STRING;
-    }
-
-  if (! ret.empty ())
-    ret.pop_back ();
-
-  return ret;
-}
-
-/* Do brace expansion on ELT; then do variable and ~ expansion on each
-   element of the result; then do brace expansion again, in case a
-   variable definition contained braces (e.g., $TEXMF).  Return a
-   string comprising all of the results separated by ENV_SEP_STRING.  */
-
-static std::string
-kpse_brace_expand_element (const std::string& elt)
-{
-  std::string ret;
-
-  std::list<std::string> expansions = brace_expand (elt);
-
-  for (const auto& expanded_elt : expansions)
-    {
-      /* Do $ and ~ expansion on each element.  */
-      std::string x = kpse_expand (expanded_elt);
-
-      if (x != elt)
-        {
-          /* If we did any expansions, do brace expansion again.  Since
-             recursive variable definitions are not allowed, this recursion
-             must terminate.  (In practice, it's unlikely there will ever be
-             more than one level of recursion.)  */
-          x = kpse_brace_expand_element (x);
-        }
-
-      ret += x + ENV_SEP_STRING;
-    }
-
-  ret.pop_back ();
-
-  return ret;
-}
-
-/* Do brace expansion and call 'kpse_expand' on each element of the
-   result; return the final expansion (always in fresh memory, even if
-   no expansions were done).  */
-
-static std::string
-kpse_brace_expand (const std::string& path)
-{
-  /* Must do variable expansion first because if we have
-       foo = .:~
-       TEXINPUTS = $foo
-     we want to end up with TEXINPUTS = .:/home/karl.
-     Since kpse_path_element is not reentrant, we must get all
-     the path elements before we start the loop.  */
-  std::string tmp = kpse_var_expand (path);
-
-  std::string ret;
-
-  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
-    {
-      std::string elt = *pi;
-
-      /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}.  */
-      std::string expansion = kpse_brace_expand_element (elt);
-      ret += expansion + ENV_SEP_STRING;
-    }
-
-  if (! ret.empty ())
-    ret.pop_back ();
-
-  return kpse_expand_kpse_dot (ret);
-}
-
-/* Expand all special constructs in a path, and include only the actually
-   existing directories in the result. */
-
-/* Do brace expansion and call 'kpse_expand' on each argument of the
-   result.  The final expansion (always in fresh memory) is a path of
-   all the existing directories that match the pattern. */
+/* Perform tilde expansion on each element of the path, and include
+   canonical directory names for only the the actually existing
+   directories in the result. */
 
 std::string
 kpse_path_expand (const std::string& path)
 {
   std::string ret;
-  unsigned len;
-
-  len = 0;
-
-  /* Expand variables and braces first.  */
-  std::string tmp = kpse_brace_expand (path);
+  unsigned len = 0;
 
   /* Now expand each of the path elements, printing the results */
-  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
+  for (kpse_path_iterator pi (path); pi != std::string::npos; pi++)
     {
-      std::string elt = *pi;
+      std::string elt = kpse_tilde_expand (*pi);
 
       std::string dir;
 
@@ -1124,64 +994,6 @@
   return c;
 }
 
-/* Expand extra colons.  */
-
-/* Check for leading colon first, then trailing, then doubled, since
-   that is fastest.  Usually it will be leading or trailing.  */
-
-/* Replace a leading or trailing or doubled : in PATH with DFLT.  If
-   no extra colons, return PATH.  Only one extra colon is replaced.
-   DFLT may not be NULL.  */
-
-std::string
-kpse_expand_default (const std::string& path, const std::string& fallback)
-{
-  std::string expansion;
-
-  size_t path_len = path.length ();
-
-  if (path_len == 0)
-    expansion = fallback;
-
-  /* Solitary or leading :?  */
-  else if (IS_ENV_SEP (path[0]))
-    {
-      expansion = (path_len == 1 ? fallback : fallback + path);
-    }
-
-  /* Sorry about the assignment in the middle of the expression, but
-     conventions were made to be flouted and all that.  I don't see the
-     point of calling strlen twice or complicating the logic just to
-     avoid the assignment (especially now that I've pointed it out at
-     such great length).  */
-  else if (IS_ENV_SEP (path[path_len-1]))
-    expansion = path + fallback;
-
-  /* OK, not leading or trailing.  Check for doubled.  */
-  else
-    {
-      /* What we'll return if we find none.  */
-      expansion = path;
-
-      for (size_t i = 0; i < path_len; i++)
-        {
-          if (i + 1 < path_len
-              && IS_ENV_SEP (path[i]) && IS_ENV_SEP (path[i+1]))
-            {
-              /* We have a doubled colon.  */
-
-              /* Copy stuff up to and including the first colon.  */
-              /* Copy in FALLBACK, and then the rest of PATH.  */
-              expansion = path.substr (0, i+1) + fallback + path.substr (i+1);
-
-              break;
-            }
-        }
-    }
-
-  return expansion;
-}
-
 /* Return true if FN is a directory or a symlink to a directory,
    false if not. */
 
@@ -1221,151 +1033,3 @@
 
   return ret;
 }
-
-/* Variable expansion.  */
-
-/* We have to keep track of variables being expanded, otherwise
-   constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
-   (Or indirectly recursive variables, etc.)  Our simple solution is to
-   add to a list each time an expansion is started, and check the list
-   before expanding.  */
-
-static std::map <std::string, bool> expansions;
-
-static void
-expanding (const std::string& var, bool xp)
-{
-  expansions[var] = xp;
-}
-
-/* Return whether VAR is currently being expanding.  */
-
-static bool
-expanding_p (const std::string& var)
-{
-  return (expansions.find (var) != expansions.end ()) ? expansions[var] : false;
-}
-
-/* Append the result of value of 'var' to EXPANSION, where 'var' begins
-   at START and ends at END.  If 'var' is not set, do not complain.
-   This is a subroutine for the more complicated expansion function.  */
-
-static void
-expand (std::string& expansion, const std::string& var)
-{
-  if (expanding_p (var))
-    {
-      (*current_liboctave_warning_with_id_handler)
-        ("Octave:pathsearch-syntax",
-         "pathsearch: variable '%s' references itself (eventually)",
-         var.c_str ());
-    }
-  else
-    {
-      /* Check for an environment variable.  */
-      std::string value = octave::sys::env::getenv (var);
-
-      if (! value.empty ())
-        {
-          expanding (var, true);
-          std::string tmp = kpse_var_expand (value);
-          expanding (var, false);
-          expansion += tmp;
-        }
-    }
-}
-
-/* Can't think of when it would be useful to change these (and the
-   diagnostic messages assume them), but ... */
-
-/* starts all variable references */
-#if ! defined (IS_VAR_START)
-#  define IS_VAR_START(c) ((c) == '$')
-#endif
-
-/* variable name constituent */
-#if ! defined (IS_VAR_CHAR)
-#  define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_')
-#endif
-
-/* start delimited variable name (after $) */
-#if ! defined (IS_VAR_BEGIN_DELIMITER)
-#  define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
-#endif
-
-#if ! defined (IS_VAR_END_DELIMITER)
-#  define IS_VAR_END_DELIMITER(c) ((c) == '}')
-#endif
-
-/* Maybe we should support some or all of the various shell ${...}
-   constructs, especially ${var-value}.  */
-
-static std::string
-kpse_var_expand (const std::string& src)
-{
-  std::string expansion;
-
-  size_t src_len = src.length ();
-
-  /* Copy everything but variable constructs.  */
-  for (size_t i = 0; i < src_len; i++)
-    {
-      if (IS_VAR_START (src[i]))
-        {
-          i++;
-
-          /* Three cases: '$VAR', '${VAR}', '$<anything-else>'.  */
-          if (IS_VAR_CHAR (src[i]))
-            {
-              /* $V: collect name constituents, then expand.  */
-              size_t var_end = i;
-
-              do
-                {
-                  var_end++;
-                }
-              while (IS_VAR_CHAR (src[var_end]));
-
-              var_end--; /* had to go one past */
-              expand (expansion, src.substr (i, var_end - i + 1));
-              i = var_end;
-
-            }
-          else if (IS_VAR_BEGIN_DELIMITER (src[i]))
-            {
-              /* ${: scan ahead for matching delimiter, then expand.  */
-              size_t var_end = ++i;
-
-              while (var_end < src_len && ! IS_VAR_END_DELIMITER (src[var_end]))
-                var_end++;
-
-              if (var_end == src_len)
-                {
-                  (*current_liboctave_warning_with_id_handler)
-                    ("Octave:pathsearch-syntax",
-                     "%s: No matching } for ${", src.c_str ());
-                  i = var_end - 1; /* will incr to eos at top of loop */
-                }
-              else
-                {
-                  expand (expansion, src.substr (i, var_end - i));
-                  i = var_end; /* will incr past } at top of loop*/
-                }
-            }
-          else
-            {
-              /* $<something-else>: error.  */
-              (*current_liboctave_warning_with_id_handler)
-                ("Octave:pathsearch-syntax",
-                 "%s: Unrecognized variable construct '$%c'",
-                 src.c_str (), src[i]);
-
-              /* Just ignore those chars and keep going.  */
-            }
-        }
-      else
-        expansion += src[i];
-    }
-
-  return expansion;
-}
--- a/liboctave/util/kpse.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/kpse.h	Thu Dec 20 17:18:56 2018 -0500
@@ -82,9 +82,6 @@
 kpse_all_path_search (const std::string& path, const std::string& name);
 
 extern std::string
-kpse_expand_default (const std::string& path, const std::string& fallback);
-
-extern std::string
 kpse_path_expand (const std::string& path);
 
 extern std::string
--- a/liboctave/util/lo-array-errwarn.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-array-errwarn.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,8 @@
 #  include "config.h"
 #endif
 
+#include <cmath>
+
 #include <sstream>
 
 #include "lo-array-errwarn.h"
@@ -215,6 +217,15 @@
   {
     std::ostringstream buf;
     buf << n + 1;
+
+    if (! std::isnan (n))
+      {
+        // if  n  not an integer, but would be printed as one, show diff
+        double nearest = std::floor (n + 1.5);
+        if (n + 1 != nearest && (buf.str ().find ('.') == std::string::npos))
+          buf << std::showpos << (n + 1 - nearest);
+      }
+
     err_invalid_index (buf.str (), nd, dim, var);
   }
 
--- a/liboctave/util/lo-array-errwarn.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-array-errwarn.h	Thu Dec 20 17:18:56 2018 -0500
@@ -157,111 +157,4 @@
   warn_singular_matrix (double rcond = 0.0);
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nan_to_logical_conversion' instead")
-OCTAVE_NORETURN inline void
-err_nan_to_logical_conversion (void)
-{
-  octave::err_nan_to_logical_conversion ();
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nan_to_character_conversion' instead")
-OCTAVE_NORETURN inline void
-err_nan_to_character_conversion (void)
-{
-  octave::err_nan_to_character_conversion ();
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN inline void
-err_nonconformant (const char *op, octave_idx_type op1_len,
-                   octave_idx_type op2_len)
-{
-  octave::err_nonconformant (op, op1_len, op2_len);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN inline 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::err_nonconformant (op, op1_nr, op1_nc, op2_nr, op2_nc);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN inline void
-err_nonconformant (const char *op,
-                   const dim_vector& op1_dims, const dim_vector& op2_dims)
-{
-  octave::err_nonconformant (op, op1_dims, op2_dims);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_index_out_of_range' instead")
-OCTAVE_NORETURN inline void
-err_index_out_of_range (int nd, int dim, octave_idx_type iext,
-                        octave_idx_type ext, const dim_vector& d)
-{
-  octave::err_index_out_of_range (nd, dim, iext, ext, d);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_index_out_of_range' instead")
-OCTAVE_NORETURN inline void
-err_index_out_of_range (int nd, int dim, octave_idx_type iext,
-                        octave_idx_type ext)
-{
-  octave::err_index_out_of_range (nd, dim, iext, ext);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_del_index_out_of_range' instead")
-OCTAVE_NORETURN inline void
-err_del_index_out_of_range (bool is1d, octave_idx_type iext,
-                            octave_idx_type ext)
-{
-  octave::err_del_index_out_of_range (is1d, iext, ext);
-}
-
-OCTAVE_NORETURN inline void
-err_invalid_index (double n, octave_idx_type nd = 0,
-                   octave_idx_type dim = 0,
-                   const std::string& var = "")
-{
-  octave::err_invalid_index (n, nd, dim, var);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_index' instead")
-OCTAVE_NORETURN inline void
-err_invalid_index (octave_idx_type n, octave_idx_type nd = 0,
-                   octave_idx_type dim = 0,
-                   const std::string& var = "")
-{
-  octave::err_invalid_index (n, nd, dim, var);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_index' instead")
-OCTAVE_NORETURN inline void
-err_invalid_index (const std::string& idx, octave_idx_type nd = 0,
-                   octave_idx_type dim = 0,
-                   const std::string& var = "")
-{
-  octave::err_invalid_index (idx, nd, dim, var);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_resize' instead")
-OCTAVE_NORETURN inline void
-err_invalid_resize (void)
-{
-  octave::err_invalid_resize ();
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::warn_singular_matrix' instead")
-inline void
-warn_singular_matrix (double rcond = 0.0)
-{
-  return octave::warn_singular_matrix (rcond);
-}
-
 #endif
-
-#endif
--- a/liboctave/util/lo-array-gripes.cc	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-/*
-
-Copyright (C) 2003-2018 John W. Eaton
-Copyright (C) 2009 VZLU Prague
-
-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/>.
-
-*/
-
-// FIXME: All gripe_XXX functions deprecated in 4.2.  Remove file in
-// version 5.
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include <sstream>
-
-#include "lo-array-gripes.h"
-#include "lo-error.h"
-
-// Text constants used to shorten code below.
-static const char *error_id_nonconformant_args = "Octave:nonconformant-args";
-
-static const char *error_id_index_out_of_bounds = "Octave:index-out-of-bounds";
-
-static const char *error_id_invalid_index = "Octave:invalid-index";
-
-static const char *warning_id_nearly_singular_matrix =
-  "Octave:nearly-singular-matrix";
-
-static const char *warning_id_singular_matrix = "Octave:singular-matrix";
-
-void
-gripe_nan_to_logical_conversion (void)
-{
-  (*current_liboctave_error_handler)
-    ("invalid conversion from NaN to logical");
-}
-
-void
-gripe_nan_to_character_conversion (void)
-{
-  (*current_liboctave_error_handler)
-    ("invalid conversion from NaN to character");
-}
-
-void
-gripe_nonconformant (const char *op, octave_idx_type op1_len,
-                     octave_idx_type op2_len)
-{
-  const char *err_id = error_id_nonconformant_args;
-
-  (*current_liboctave_error_with_id_handler)
-    (err_id, "%s: nonconformant arguments (op1 len: %d, op2 len: %d)",
-     op, op1_len, op2_len);
-}
-
-void
-gripe_nonconformant (const char *op,
-                     octave_idx_type op1_nr, octave_idx_type op1_nc,
-                     octave_idx_type op2_nr, octave_idx_type op2_nc)
-{
-  const char *err_id = error_id_nonconformant_args;
-
-  (*current_liboctave_error_with_id_handler)
-    (err_id, "%s: nonconformant arguments (op1 is %dx%d, op2 is %dx%d)",
-     op, op1_nr, op1_nc, op2_nr, op2_nc);
-}
-
-void
-gripe_nonconformant (const char *op, const dim_vector& op1_dims,
-                     const dim_vector& op2_dims)
-{
-  const char *err_id = error_id_nonconformant_args;
-
-  std::string op1_dims_str = op1_dims.str ();
-  std::string op2_dims_str = op2_dims.str ();
-
-  (*current_liboctave_error_with_id_handler)
-    (err_id, "%s: nonconformant arguments (op1 is %s, op2 is %s)",
-     op, op1_dims_str.c_str (), op2_dims_str.c_str ());
-}
-
-void
-gripe_del_index_out_of_range (bool is1d, octave_idx_type idx,
-                              octave_idx_type ext)
-{
-  const char *err_id = error_id_index_out_of_bounds;
-
-  (*current_liboctave_error_with_id_handler)
-    (err_id, "A(%s) = []: index out of bounds: value %d out of bound %d",
-     is1d ? "I" : "..,I,..", idx, ext);
-}
-
-namespace octave
-{
-  class invalid_index : public index_exception
-  {
-  public:
-
-    invalid_index (const std::string& value, octave_idx_type ndim,
-                   octave_idx_type dimen)
-      : index_exception (value, ndim, dimen)
-    { }
-
-    std::string details (void) const
-    {
-#if defined (OCTAVE_ENABLE_64)
-      return "subscripts must be either integers 1 to (2^63)-1 or logicals";
-#else
-      return "subscripts must be either integers 1 to (2^31)-1 or logicals";
-#endif
-    }
-
-    // ID of error to throw
-    const char * err_id (void) const
-    {
-      return error_id_invalid_index;
-    }
-  };
-}
-
-// Complain if an index is negative, fractional, or too big.
-
-void
-gripe_invalid_index (const std::string& idx, octave_idx_type nd,
-                     octave_idx_type dim, const std::string&)
-{
-  octave::invalid_index e (idx, nd, dim);
-
-  throw e;
-}
-
-void
-gripe_invalid_index (octave_idx_type n, octave_idx_type nd,
-                     octave_idx_type dim, const std::string& var)
-{
-  std::ostringstream buf;
-  buf << n + 1;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_invalid_index (buf.str (), nd, dim, var);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-void
-gripe_invalid_index (double n, octave_idx_type nd, octave_idx_type dim,
-                     const std::string& var)
-{
-  std::ostringstream buf;
-  buf << n + 1;
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-  gripe_invalid_index (buf.str (), nd, dim, var);
-
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
-#  pragma GCC diagnostic pop
-#endif
-}
-
-namespace octave
-{
-  // Gripe and exception for read access beyond the bounds of an array.
-
-  class out_of_range : public index_exception
-  {
-  public:
-
-    out_of_range (const std::string& value, octave_idx_type nd_in,
-                  octave_idx_type dim_in)
-      : index_exception (value, nd_in, dim_in), extent (0)
-    { }
-
-    std::string details (void) const
-    {
-      std::string expl;
-
-      if (nd >= size.ndims ())   // if not an index slice
-        {
-          if (var != "")
-            expl = "but " + var + " has size ";
-          else
-            expl = "but object has size ";
-
-          expl = expl + size.str ('x');
-        }
-      else
-        {
-          std::ostringstream buf;
-          buf << extent;
-          expl = "out of bound " + buf.str ();
-        }
-
-      return expl;
-    }
-
-    // ID of error to throw.
-    const char * err_id (void) const
-    {
-      return error_id_index_out_of_bounds;
-    }
-
-    void set_size (const dim_vector& size_in) { size = size_in; }
-
-    void set_extent (octave_idx_type ext) { extent = ext; }
-
-  private:
-
-    // Dimension of object being accessed.
-    dim_vector size;
-
-    // Length of dimension being accessed.
-    octave_idx_type extent;
-  };
-}
-
-// Complain of an index that is out of range, but we don't know matrix size
-void
-gripe_index_out_of_range (int nd, int dim, octave_idx_type idx,
-                          octave_idx_type ext)
-{
-  std::ostringstream buf;
-  buf << idx;
-  octave::out_of_range e (buf.str (), nd, dim);
-
-  e.set_extent (ext);
-  // ??? Make details method give extent not size.
-  e.set_size (dim_vector (1, 1, 1, 1, 1, 1,1));
-
-  throw e;
-}
-
-// Complain of an index that is out of range
-void
-gripe_index_out_of_range (int nd, int dim, octave_idx_type idx,
-                          octave_idx_type ext, const dim_vector& d)
-{
-  std::ostringstream buf;
-  buf << idx;
-  octave::out_of_range e (buf.str (), nd, dim);
-
-  e.set_extent (ext);
-  e.set_size (d);
-
-  throw e;
-}
-
-void
-gripe_invalid_resize (void)
-{
-  (*current_liboctave_error_with_id_handler)
-    ("Octave:invalid-resize",
-     "Invalid resizing operation or ambiguous assignment to an out-of-bounds array element");
-}
-
-void
-gripe_singular_matrix (double rcond)
-{
-  if (rcond == 0.0)
-    {
-      (*current_liboctave_warning_with_id_handler)
-        (warning_id_singular_matrix,
-         "matrix singular to machine precision");
-    }
-  else
-    {
-      (*current_liboctave_warning_with_id_handler)
-        (warning_id_nearly_singular_matrix,
-         "matrix singular to machine precision, rcond = %g", rcond);
-    }
-}
-
-/* Tests in test/index.tst */
--- a/liboctave/util/lo-array-gripes.h	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
-
-Copyright (C) 2000-2018 John W. Eaton
-
-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/>.
-
-*/
-
-// FIXME: All gripe_XXX functions deprecated in 4.2.  Remove file in
-// version 5.
-
-#if ! defined (octave_lo_array_gripes_h)
-#define octave_lo_array_gripes_h 1
-
-#include "octave-config.h"
-
-#include "lo-array-errwarn.h"
-#include "dim-vector.h"
-#include "quit.h"
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nan_to_logical_conversion' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_nan_to_logical_conversion (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nan_to_character_conversion' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_nan_to_character_conversion (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_nonconformant (const char *op,
-                     octave_idx_type op1_len,
-                     octave_idx_type op2_len);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_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_DEPRECATED (4.2, "use 'octave::err_nonconformant' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_nonconformant (const char *op, const dim_vector& op1_dims,
-                     const dim_vector& op2_dims);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_index_out_of_range' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_index_out_of_range (int nd, int dim,
-                          octave_idx_type iext, octave_idx_type ext,
-                          const dim_vector& d);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_index_out_of_range' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_index_out_of_range (int nd, int dim,
-                          octave_idx_type iext, octave_idx_type ext);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_del_index_out_of_range' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_del_index_out_of_range (bool is1d, octave_idx_type iext,
-                              octave_idx_type ext);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_index' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_invalid_index (double, octave_idx_type nd = 0,
-                     octave_idx_type dim = 0,
-                     const std::string& var = "");
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_index' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_invalid_index (octave_idx_type n, octave_idx_type nd = 0,
-                     octave_idx_type dim = 0,
-                     const std::string& var = "");
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_index' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_invalid_index (const std::string& idx, octave_idx_type nd = 0,
-                     octave_idx_type dim = 0,
-                     const std::string& var = "");
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_invalid_resize' instead")
-OCTAVE_NORETURN OCTAVE_API extern void
-gripe_invalid_resize (void);
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::err_singular_matrix' instead")
-OCTAVE_API extern void
-gripe_singular_matrix (double rcond = 0.0);
-
-#endif
--- a/liboctave/util/lo-regexp.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-regexp.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -459,7 +459,7 @@
   {
     std::string retval;
 
-    regexp::match_data rx_lst = match (buffer);
+    const regexp::match_data rx_lst = match (buffer);
 
     size_t num_matches = rx_lst.size ();
 
@@ -518,7 +518,7 @@
         // Determine replacement length
         const size_t replen = repstr.size () - 2*num_tokens;
         int delta = 0;
-        regexp::match_data::const_iterator p = rx_lst.begin ();
+        auto p = rx_lst.begin ();
         for (size_t i = 0; i < num_matches; i++)
           {
             octave_quit ();
@@ -595,7 +595,7 @@
         // Determine repstr length
         const size_t replen = repstr.size ();
         int delta = 0;
-        regexp::match_data::const_iterator p = rx_lst.begin ();
+        auto p = rx_lst.begin ();
         for (size_t i = 0; i < num_matches; i++)
           {
             octave_quit ();
--- a/liboctave/util/lo-regexp.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-regexp.h	Thu Dec 20 17:18:56 2018 -0500
@@ -258,7 +258,7 @@
 
       ~match_data (void) = default;
 
-      string_vector named_patterns (void) { return named_pats; }
+      string_vector named_patterns (void) const { return named_pats; }
 
     private:
 
@@ -287,52 +287,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::regexp' instead")
-typedef octave::regexp regexp;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::regexp::match' instead")
-inline regexp::match_data
-regexp_match (const std::string& pat,
-              const std::string& buffer,
-              const regexp::opts& opt = regexp::opts (),
-              const std::string& who = "regexp")
-{
-  return octave::regexp::match (pat, buffer, opt, who);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::regexp::is_match' instead")
-inline bool
-is_regexp_match (const std::string& pat,
-                 const std::string& buffer,
-                 const regexp::opts& opt = regexp::opts (),
-                 const std::string& who = "regexp")
-{
-  return octave::regexp::is_match (pat, buffer, opt, who);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::regexp::is_match' instead")
-inline Array<bool>
-is_regexp_match (const std::string& pat,
-                 const string_vector& buffer,
-                 const regexp::opts& opt = regexp::opts (),
-                 const std::string& who = "regexp")
-{
-  return octave::regexp::is_match (pat, buffer, opt, who);
-}
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::regexp::replace' instead")
-inline std::string
-regexp_replace (const std::string& pat,
-                const std::string& buffer,
-                const std::string& replacement,
-                const regexp::opts& opt = regexp::opts (),
-                const std::string& who = "regexp")
-{
-  return octave::regexp::replace (pat, buffer, replacement, opt, who);
-}
-
 #endif
-
-#endif
--- a/liboctave/util/lo-utils.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-utils.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,9 @@
 #include <cstring>
 
 #include <complex>
+#include <istream>
 #include <limits>
+#include <ostream>
 #include <string>
 
 #include "quit.h"
@@ -37,7 +39,6 @@
 #include "lo-ieee.h"
 #include "lo-mappers.h"
 #include "lo-utils.h"
-#include "putenv-wrapper.h"
 
 bool xis_int_or_inf_or_nan (double x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
@@ -83,30 +84,6 @@
   return tmp;
 }
 
-// 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.
-
-void
-octave_putenv (const std::string& name, const std::string& value)
-{
-  int new_len = name.length () + value.length () + 2;
-
-  // FIXME: This 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));
-
-  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 (octave_putenv_wrapper (new_item) < 0)
-    (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
-}
-
 std::string
 octave_fgets (FILE *f)
 {
@@ -237,6 +214,8 @@
                 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
--- a/liboctave/util/lo-utils.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/lo-utils.h	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,7 @@
 
 #include <cstdio>
 
-#include <iostream>
+#include <iosfwd>
 #include <string>
 
 #include "lo-cutils.h"
@@ -76,9 +76,6 @@
 
 extern OCTAVE_API char * strsave (const char *);
 
-extern OCTAVE_API void
-octave_putenv (const std::string&, const std::string&);
-
 extern OCTAVE_API std::string octave_fgets (std::FILE *);
 extern OCTAVE_API std::string octave_fgetl (std::FILE *);
 
--- a/liboctave/util/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -10,7 +10,6 @@
   %reldir%/functor.h \
   %reldir%/glob-match.h \
   %reldir%/lo-array-errwarn.h \
-  %reldir%/lo-array-gripes.h \
   %reldir%/lo-cutils.h \
   %reldir%/lo-hash.h \
   %reldir%/lo-ieee.h \
@@ -70,7 +69,6 @@
   %reldir%/glob-match.cc \
   %reldir%/kpse.cc \
   %reldir%/lo-array-errwarn.cc \
-  %reldir%/lo-array-gripes.cc \
   %reldir%/lo-hash.cc \
   %reldir%/lo-ieee.cc \
   %reldir%/lo-regexp.cc \
@@ -110,10 +108,6 @@
   $(PCRE_CPPFLAGS) \
   $(SPARSE_XCPPFLAGS)
 
-%canon_reldir%_libutil_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
-%canon_reldir%_libutil_la_CXXFLAGS = $(liboctave_liboctave_la_CXXFLAGS)
-
 %canon_reldir%_libutil_la_FFLAGS = $(F77_INTEGER_8_FLAG)
 
 liboctave_liboctave_la_LIBADD += %reldir%/libutil.la
--- a/liboctave/util/oct-base64.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-base64.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -93,7 +93,11 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
+// 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_base64_encode (const char *inc, const size_t inlen, char **out)
@@ -107,4 +111,4 @@
   return octave::base64_decode (str);
 }
 
-#endif
+// #endif
--- a/liboctave/util/oct-glob.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-glob.h	Thu Dec 20 17:18:56 2018 -0500
@@ -43,14 +43,4 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::fnmatch' instead")
-const auto octave_fnmatch = octave::sys::fnmatch;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::sys::glob' instead")
-const auto octave_glob = octave::sys::glob;
-
 #endif
-
-#endif
--- a/liboctave/util/oct-inttypes.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-inttypes.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -35,20 +35,21 @@
 template <typename T>
 const octave_int<T> octave_int<T>::one (static_cast<T> (1));
 
-// define type names.
-#define DECLARE_OCTAVE_INT_TYPENAME(TYPE, TYPENAME)     \
-  template <>                                           \
-  OCTAVE_API const char *                               \
-  octave_int<TYPE>::type_name () { return TYPENAME; }
+// Define type names.
+
+#define DEFINE_OCTAVE_INT_TYPENAME(TYPE, TYPENAME)              \
+  template <>                                                   \
+  OCTAVE_API const char *                                       \
+  octave_int<TYPE>::type_name (void) { return TYPENAME; }
 
-DECLARE_OCTAVE_INT_TYPENAME (int8_t, "int8")
-DECLARE_OCTAVE_INT_TYPENAME (int16_t, "int16")
-DECLARE_OCTAVE_INT_TYPENAME (int32_t, "int32")
-DECLARE_OCTAVE_INT_TYPENAME (int64_t, "int64")
-DECLARE_OCTAVE_INT_TYPENAME (uint8_t, "uint8")
-DECLARE_OCTAVE_INT_TYPENAME (uint16_t, "uint16")
-DECLARE_OCTAVE_INT_TYPENAME (uint32_t, "uint32")
-DECLARE_OCTAVE_INT_TYPENAME (uint64_t, "uint64")
+DEFINE_OCTAVE_INT_TYPENAME (int8_t, "int8")
+DEFINE_OCTAVE_INT_TYPENAME (int16_t, "int16")
+DEFINE_OCTAVE_INT_TYPENAME (int32_t, "int32")
+DEFINE_OCTAVE_INT_TYPENAME (int64_t, "int64")
+DEFINE_OCTAVE_INT_TYPENAME (uint8_t, "uint8")
+DEFINE_OCTAVE_INT_TYPENAME (uint16_t, "uint16")
+DEFINE_OCTAVE_INT_TYPENAME (uint32_t, "uint32")
+DEFINE_OCTAVE_INT_TYPENAME (uint64_t, "uint64")
 
 template <class T>
 template <class S>
@@ -61,17 +62,11 @@
   static const S thmax = compute_threshold (static_cast<S> (max_val ()),
                                             max_val ());
   if (octave::math::isnan (value))
-    {
-      return static_cast<T> (0);
-    }
+    return static_cast<T> (0);
   else if (value < thmin)
-    {
-      return min_val ();
-    }
+    return min_val ();
   else if (value > thmax)
-    {
-      return max_val ();
-    }
+    return max_val ();
   else
     {
       S rvalue = octave::math::round (value);
@@ -103,9 +98,9 @@
 
 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
 
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
 
-#define DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES(T)           \
+#    define DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES(T)       \
   template <typename xop>                                       \
   bool                                                          \
   octave_int_cmp_op::external_mop (double x, T y)               \
@@ -137,18 +132,19 @@
 DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES (int64_t)
 DEFINE_OCTAVE_LONG_DOUBLE_CMP_OP_TEMPLATES (uint64_t)
 
-#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(OP, T)               \
+#    define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP(OP, T)           \
   template OCTAVE_API bool                                              \
   octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (double, T);   \
+                                                                        \
   template OCTAVE_API bool                                              \
   octave_int_cmp_op::external_mop<octave_int_cmp_op::OP> (T, double)
 
-#define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS(T)  \
-  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (lt, T);   \
-  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (le, T);   \
-  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (gt, T);   \
-  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (ge, T);   \
-  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (eq, T);   \
+#    define INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS(T)      \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (lt, T);           \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (le, T);           \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (gt, T);           \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (ge, T);           \
+  INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (eq, T);           \
   INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OP (ne, T)
 
 INSTANTIATE_LONG_DOUBLE_LONG_DOUBLE_CMP_OPS (int64_t);
@@ -186,7 +182,7 @@
 // Similarly, the conversion from the 64-bit integer type to long double
 // must also occur in long double rounding mode.
 
-#define OCTAVE_LONG_DOUBLE_OP(T, OP, NAME)                      \
+#    define DEFINE_OCTAVE_LONG_DOUBLE_OP(T, OP, NAME)           \
   T                                                             \
   external_double_ ## T ## _ ## NAME (double x, T y)            \
   {                                                             \
@@ -211,16 +207,16 @@
     return retval;                                              \
   }
 
-#define OCTAVE_LONG_DOUBLE_OPS(T)               \
-  OCTAVE_LONG_DOUBLE_OP (T, +, add);            \
-  OCTAVE_LONG_DOUBLE_OP (T, -, sub);            \
-  OCTAVE_LONG_DOUBLE_OP (T, *, mul);            \
-  OCTAVE_LONG_DOUBLE_OP (T, /, div)
+#    define DEFINE_OCTAVE_LONG_DOUBLE_OPS(T)    \
+  DEFINE_OCTAVE_LONG_DOUBLE_OP (T, +, add);     \
+  DEFINE_OCTAVE_LONG_DOUBLE_OP (T, -, sub);     \
+  DEFINE_OCTAVE_LONG_DOUBLE_OP (T, *, mul);     \
+  DEFINE_OCTAVE_LONG_DOUBLE_OP (T, /, div)
 
-OCTAVE_LONG_DOUBLE_OPS(octave_int64);
-OCTAVE_LONG_DOUBLE_OPS(octave_uint64);
+DEFINE_OCTAVE_LONG_DOUBLE_OPS (octave_int64);
+DEFINE_OCTAVE_LONG_DOUBLE_OPS (octave_uint64);
 
-#endif
+#  endif
 
 #else
 
@@ -280,7 +276,7 @@
   typedef xop op;
 };
 
-#define DEFINE_REVERTED_OPERATOR(OP1,OP2)       \
+#define DEFINE_REVERTED_OPERATOR(OP1, OP2)      \
   template <>                                   \
   class rev_op<octave_int_cmp_op::OP1>          \
   {                                             \
@@ -288,10 +284,10 @@
     typedef octave_int_cmp_op::OP2 op;          \
   }
 
-DEFINE_REVERTED_OPERATOR(lt,gt);
-DEFINE_REVERTED_OPERATOR(gt,lt);
-DEFINE_REVERTED_OPERATOR(le,ge);
-DEFINE_REVERTED_OPERATOR(ge,le);
+DEFINE_REVERTED_OPERATOR (lt, gt);
+DEFINE_REVERTED_OPERATOR (gt, lt);
+DEFINE_REVERTED_OPERATOR (le, ge);
+DEFINE_REVERTED_OPERATOR (ge, le);
 
 template <typename xop>
 bool
@@ -355,7 +351,7 @@
 
   return res;
 
-overflow:
+ overflow:
   return max_val ();
 }
 
@@ -431,30 +427,28 @@
         return -static_cast<int64_t> (res);
     }
 
-overflow:
+ overflow:
   return positive ? max_val () : min_val ();
 
 }
 
-#define INT_DOUBLE_BINOP_DECL(OP,SUFFIX)                        \
-  template <>                                                   \
-  OCTAVE_API octave_ ## SUFFIX                                  \
-  operator OP (const octave_ ## SUFFIX & x, const double& y)
-
-#define DOUBLE_INT_BINOP_DECL(OP,SUFFIX)                        \
-  template <>                                                   \
-  OCTAVE_API octave_ ## SUFFIX                                  \
-  operator OP (const double& x, const octave_ ## SUFFIX & y)
-
-INT_DOUBLE_BINOP_DECL (+, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator + (const octave_uint64& x, const double& y)
 {
   return (y < 0) ? x - octave_uint64 (-y) : x + octave_uint64 (y);
 }
 
-DOUBLE_INT_BINOP_DECL (+, uint64)
-{ return y + x; }
+template <>
+OCTAVE_API octave_uint64
+operator + (const double& x, const octave_uint64& y)
+{
+  return y + x;
+}
 
-INT_DOUBLE_BINOP_DECL (+, int64)
+template <>
+OCTAVE_API octave_int64
+operator + (const octave_int64& x, const double& y)
 {
   if (fabs (y) < static_cast<double> (octave_int64::max ()))
     return x + octave_int64 (y);
@@ -473,17 +467,23 @@
     }
 }
 
-DOUBLE_INT_BINOP_DECL (+, int64)
+template <>
+OCTAVE_API octave_int64
+operator + (const double& x, const octave_int64& y)
 {
   return y + x;
 }
 
-INT_DOUBLE_BINOP_DECL (-, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator - (const octave_uint64& x, const double& y)
 {
   return x + (-y);
 }
 
-DOUBLE_INT_BINOP_DECL (-, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator - (const double& x, const octave_uint64& y)
 {
   if (x <= static_cast<double> (octave_uint64::max ()))
     return octave_uint64 (x) - y;
@@ -503,21 +503,23 @@
     }
 }
 
-INT_DOUBLE_BINOP_DECL (-, int64)
+template <>
+OCTAVE_API octave_int64
+operator - (const octave_int64& x, const double& y)
 {
   return x + (-y);
 }
 
-DOUBLE_INT_BINOP_DECL (-, int64)
+template <>
+OCTAVE_API octave_int64
+operator - (const double& x, const octave_int64& y)
 {
   static const bool twosc = (std::numeric_limits<int64_t>::min ()
                              < -std::numeric_limits<int64_t>::max ());
   // In case of symmetric integers (not two's complement), this will probably
   // be eliminated at compile time.
   if (twosc && y.value () == std::numeric_limits<int64_t>::min ())
-    {
-      return octave_int64 (x + std::pow (2.0, 63));
-    }
+    return octave_int64 (x + std::pow (2.0, 63));
   else
     return x + (-y);
 }
@@ -573,20 +575,16 @@
   return sign ? -x : x;
 }
 
-INT_DOUBLE_BINOP_DECL (*, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator * (const octave_uint64& x, const double& y)
 {
   if (y >= 0 && y < octave_uint64::max () && y == octave::math::round (y))
-    {
-      return x * octave_uint64 (static_cast<uint64_t> (y));
-    }
+    return x * octave_uint64 (static_cast<uint64_t> (y));
   else if (y == 0.5)
-    {
-      return x / octave_uint64 (static_cast<uint64_t> (2));
-    }
+    return x / octave_uint64 (static_cast<uint64_t> (2));
   else if (y < 0 || octave::math::isnan (y) || octave::math::isinf (y))
-    {
-      return octave_uint64 (x.value () * y);
-    }
+    return octave_uint64 (x.value () * y);
   else
     {
       bool sign;
@@ -605,23 +603,23 @@
     }
 }
 
-DOUBLE_INT_BINOP_DECL (*, uint64)
-{ return y * x; }
+template <>
+OCTAVE_API octave_uint64
+operator * (const double& x, const octave_uint64& y)
+{
+  return y * x;
+}
 
-INT_DOUBLE_BINOP_DECL (*, int64)
+template <>
+OCTAVE_API octave_int64
+operator * (const octave_int64& x, const double& y)
 {
   if (fabs (y) < octave_int64::max () && y == octave::math::round (y))
-    {
-      return x * octave_int64 (static_cast<int64_t> (y));
-    }
+    return x * octave_int64 (static_cast<int64_t> (y));
   else if (fabs (y) == 0.5)
-    {
-      return x / octave_int64 (static_cast<uint64_t> (4*y));
-    }
+    return x / octave_int64 (static_cast<uint64_t> (4*y));
   else if (octave::math::isnan (y) || octave::math::isinf (y))
-    {
-      return octave_int64 (x.value () * y);
-    }
+    return octave_int64 (x.value () * y);
   else
     {
       bool sign;
@@ -641,55 +639,63 @@
     }
 }
 
-DOUBLE_INT_BINOP_DECL (*, int64)
-{ return y * x; }
+template <>
+OCTAVE_API octave_int64
+operator * (const double& x, const octave_int64& y)
+{
+  return y * x;
+}
 
-DOUBLE_INT_BINOP_DECL (/, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator / (const double& x, const octave_uint64& y)
 {
   return octave_uint64 (x / static_cast<double> (y));
 }
 
-DOUBLE_INT_BINOP_DECL (/, int64)
+template <>
+OCTAVE_API octave_int64
+operator / (const double& x, const octave_int64& y)
 {
   return octave_int64 (x / static_cast<double> (y));
 }
 
-INT_DOUBLE_BINOP_DECL (/, uint64)
+template <>
+OCTAVE_API octave_uint64
+operator / (const octave_uint64& x, const double& y)
 {
   if (y >= 0 && y < octave_uint64::max () && y == octave::math::round (y))
-    {
-      return x / octave_uint64 (y);
-    }
+    return x / octave_uint64 (y);
   else
     return x * (1.0/y);
 }
 
-INT_DOUBLE_BINOP_DECL (/, int64)
+template <>
+OCTAVE_API octave_int64
+operator / (const octave_int64& x, const double& y)
 {
   if (fabs (y) < octave_int64::max () && y == octave::math::round (y))
-    {
-      return x / octave_int64 (y);
-    }
+    return x / octave_int64 (y);
   else
     return x * (1.0/y);
 }
 
-#define INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP,T1,T2)                      \
+#define INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP, T1, T2)                    \
   template OCTAVE_API bool                                              \
   octave_int_cmp_op::emulate_mop<octave_int_cmp_op::OP> (T1 x, T2 y)
 
 #define INSTANTIATE_INT64_DOUBLE_CMP_OP(OP)                     \
-  INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP, double, int64_t);        \
-  INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP, double, uint64_t);       \
-  INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP, int64_t, double);        \
-  INSTANTIATE_INT64_DOUBLE_CMP_OP0(OP, uint64_t, double)
+  INSTANTIATE_INT64_DOUBLE_CMP_OP0 (OP, double, int64_t);       \
+  INSTANTIATE_INT64_DOUBLE_CMP_OP0 (OP, double, uint64_t);      \
+  INSTANTIATE_INT64_DOUBLE_CMP_OP0 (OP, int64_t, double);       \
+  INSTANTIATE_INT64_DOUBLE_CMP_OP0 (OP, uint64_t, double)
 
-INSTANTIATE_INT64_DOUBLE_CMP_OP(lt);
-INSTANTIATE_INT64_DOUBLE_CMP_OP(le);
-INSTANTIATE_INT64_DOUBLE_CMP_OP(gt);
-INSTANTIATE_INT64_DOUBLE_CMP_OP(ge);
-INSTANTIATE_INT64_DOUBLE_CMP_OP(eq);
-INSTANTIATE_INT64_DOUBLE_CMP_OP(ne);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (lt);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (le);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (gt);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (ge);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (eq);
+INSTANTIATE_INT64_DOUBLE_CMP_OP (ne);
 
 #endif
 
@@ -699,8 +705,8 @@
 {
   octave_int<T> retval;
 
-  octave_int<T> zero = static_cast<T> (0);
-  octave_int<T> one = static_cast<T> (1);
+  const octave_int<T> zero = octave_int<T>::zero;
+  const octave_int<T> one = octave_int<T>::one;
 
   if (b == zero || a == one)
     retval = one;
@@ -786,13 +792,28 @@
 
 #define INSTANTIATE_INTTYPE(T)                                          \
   template class OCTAVE_API octave_int<T>;                              \
-  template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> pow (const double&, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const double&); \
-  template OCTAVE_API octave_int<T> pow (const float&, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const float&); \
-  template OCTAVE_API octave_int<T> powf (const float&, const octave_int<T>&); \
-  template OCTAVE_API octave_int<T> powf (const octave_int<T>&, const float&); \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  pow (const octave_int<T>&, const octave_int<T>&);                     \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  pow (const double&, const octave_int<T>&);                            \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  pow (const octave_int<T>&, const double&);                            \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  pow (const float&, const octave_int<T>&);                             \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  pow (const octave_int<T>&, const float&);                             \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  powf (const float&, const octave_int<T>&);                            \
+                                                                        \
+  template OCTAVE_API octave_int<T>                                     \
+  powf (const octave_int<T>&, const float&);                            \
+                                                                        \
   template OCTAVE_API octave_int<T>                                     \
   bitshift (const octave_int<T>&, int, const octave_int<T>&);
 
--- a/liboctave/util/oct-inttypes.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-inttypes.h	Thu Dec 20 17:18:56 2018 -0500
@@ -53,265 +53,334 @@
 {
   namespace math
   {
-    inline long double round (long double x) { return std::roundl (x); }
+    inline long double round (long double x)
+    {
+      return std::roundl (x);
+    }
 
-    inline long double isnan (long double x) { return isnan (static_cast<double> (x)); }
+    inline long double isnan (long double x)
+    {
+      return isnan (static_cast<double> (x));
+    }
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::round' instead")
-inline long double xround (long double x) { return octave::math::round (x); }
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-inline bool xisnan (long double x) { return octave::math::isnan (x); }
-
-#endif
-
 #endif
 
 // FIXME: we define this by our own because some compilers, such as
 // MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t).  In
 // the future, it should go away in favor of std::abs.
+
 template <typename T>
-inline T octave_int_abs (T x) { return (x >= 0 ? x : -x); }
+inline T
+octave_int_abs (T x)
+{
+  return (x >= 0 ? x : -x);
+}
 
 // Query for an integer type of certain sizeof, and signedness.
+
 template <int qsize, bool qsigned>
 struct query_integer_type
 {
 public:
+
   static const bool registered = false;
-  typedef void type; // Void shall result in a compile-time error if we
-                     // attempt to use it in computations.
+
+  // Void shall result in a compile-time error if we attempt to use it
+  // in computations.
+
+  typedef void type;
 };
 
-#define REGISTER_INT_TYPE(TYPE)                                         \
+#define OCTAVE_REGISTER_INT_TYPE(TYPE)                                  \
   template <>                                                           \
-  class query_integer_type<sizeof (TYPE), std::numeric_limits<TYPE>::is_signed> \
+  class query_integer_type<sizeof (TYPE),                               \
+                           std::numeric_limits<TYPE>::is_signed>        \
   {                                                                     \
   public:                                                               \
+                                                                        \
     static const bool registered = true;                                \
+                                                                        \
     typedef TYPE type;                                                  \
   }
 
 // No two registered integers can share sizeof and signedness.
-REGISTER_INT_TYPE (int8_t);
-REGISTER_INT_TYPE (uint8_t);
-REGISTER_INT_TYPE (int16_t);
-REGISTER_INT_TYPE (uint16_t);
-REGISTER_INT_TYPE (int32_t);
-REGISTER_INT_TYPE (uint32_t);
-REGISTER_INT_TYPE (int64_t);
-REGISTER_INT_TYPE (uint64_t);
+OCTAVE_REGISTER_INT_TYPE (int8_t);
+OCTAVE_REGISTER_INT_TYPE (uint8_t);
+OCTAVE_REGISTER_INT_TYPE (int16_t);
+OCTAVE_REGISTER_INT_TYPE (uint16_t);
+OCTAVE_REGISTER_INT_TYPE (int32_t);
+OCTAVE_REGISTER_INT_TYPE (uint32_t);
+OCTAVE_REGISTER_INT_TYPE (int64_t);
+OCTAVE_REGISTER_INT_TYPE (uint64_t);
 
-// Rationale: Comparators have a single static method, rel(), that returns the
-// result of the binary relation.  They also have two static boolean fields:
-// ltval, gtval determine the value of x OP y if x < y, x > y, respectively.
-#define REGISTER_OCTAVE_CMP_OP(NM,OP)                   \
-  class NM                                              \
-  {                                                     \
-  public:                                               \
-    static const bool ltval = (0 OP 1);                 \
-    static const bool gtval = (1 OP 0);                 \
-    template <typename T>                               \
-    static bool op (T x, T y) { return x OP y; }        \
-  }
+#undef OCTAVE_REGISTER_INT_TYPE
 
-// We also provide two special relations: ct, yielding always true, and cf,
-// yielding always false.
-#define REGISTER_OCTAVE_CONST_OP(NM,value)      \
-  class NM                                      \
-  {                                             \
-  public:                                       \
-    static const bool ltval = value;            \
-    static const bool gtval = value;            \
-    template <typename T>                       \
-    static bool op (T, T) { return value; }     \
-  }
+// Handles non-homogeneous integer comparisons.  Avoids doing useless
+// tests.
 
-// Handles non-homogeneous integer comparisons.  Avoids doing useless tests.
 class octave_int_cmp_op
 {
-  // This determines a suitable promotion type for T1 when meeting T2 in a
-  // binary relation.  If promotion to int or T2 is safe, it is used.
-  // Otherwise, the signedness of T1 is preserved and it is widened if T2 is
-  // wider.
-  // Notice that if this is applied to both types, they must end up with equal
-  // size.
+  // This determines a suitable promotion type for T1 when meeting T2
+  // in a binary relation.  If promotion to int or T2 is safe, it is
+  // used.  Otherwise, the signedness of T1 is preserved and it is
+  // widened if T2 is wider.  Notice that if this is applied to both
+  // types, they must end up with equal size.
+
   template <typename T1, typename T2>
   class prom
   {
     // Promote to int?
     static const bool pint = (sizeof (T1) < sizeof (int)
                               && sizeof (T2) < sizeof (int));
+
     static const bool t1sig = std::numeric_limits<T1>::is_signed;
     static const bool t2sig = std::numeric_limits<T2>::is_signed;
+
     static const bool psig =
       (pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);
+
     static const int psize =
       (pint ? sizeof (int) : (sizeof (T2) > sizeof (T1)
                               ? sizeof (T2) : sizeof (T1)));
   public:
+
     typedef typename query_integer_type<psize, psig>::type type;
   };
 
   // Implements comparisons between two types of equal size but
   // possibly different signedness.
+
   template <typename xop, int size>
   class uiop
   {
     typedef typename query_integer_type<size, false>::type utype;
     typedef typename query_integer_type<size, true>::type stype;
+
   public:
+
     static bool op (utype x, utype y)
-    { return xop::op (x, y); }
+    {
+      return xop::op (x, y);
+    }
+
     static bool op (stype x, stype y)
-    { return xop::op (x, y); }
+    {
+      return xop::op (x, y);
+    }
+
     static bool op (stype x, utype y)
-    { return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y); }
+    {
+      return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y);
+    }
+
     static bool op (utype x, stype y)
-    { return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y)); }
+    {
+      return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y));
+    }
   };
 
 public:
-  REGISTER_OCTAVE_CMP_OP (lt, <);
-  REGISTER_OCTAVE_CMP_OP (le, <=);
-  REGISTER_OCTAVE_CMP_OP (gt, >);
-  REGISTER_OCTAVE_CMP_OP (ge, >=);
-  REGISTER_OCTAVE_CMP_OP (eq, ==);
-  REGISTER_OCTAVE_CMP_OP (ne, !=);
-  REGISTER_OCTAVE_CONST_OP (ct, true);
-  REGISTER_OCTAVE_CONST_OP (cf, false);
+
+  // Rationale: Comparators have a single static method, rel(), that
+  // returns the result of the binary relation.  They also have two
+  // static boolean fields: ltval, gtval determine the value of x OP y
+  // if x < y, x > y, respectively.
+
+#define OCTAVE_REGISTER_INT_CMP_OP(NM, OP)              \
+  class NM                                              \
+  {                                                     \
+  public:                                               \
+                                                        \
+    static const bool ltval = (0 OP 1);                 \
+    static const bool gtval = (1 OP 0);                 \
+                                                        \
+    template <typename T>                               \
+    static bool op (T x, T y) { return x OP y; }        \
+  }
+
+  OCTAVE_REGISTER_INT_CMP_OP (lt, <);
+  OCTAVE_REGISTER_INT_CMP_OP (le, <=);
+  OCTAVE_REGISTER_INT_CMP_OP (gt, >);
+  OCTAVE_REGISTER_INT_CMP_OP (ge, >=);
+  OCTAVE_REGISTER_INT_CMP_OP (eq, ==);
+  OCTAVE_REGISTER_INT_CMP_OP (ne, !=);
+
+#undef OCTAVE_REGISTER_INT_CMP_OP
+
+  // We also provide two special relations: ct, yielding always true,
+  // and cf, yielding always false.
+
+#define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE)     \
+  class NM                                      \
+  {                                             \
+  public:                                       \
+                                                \
+    static const bool ltval = VALUE;            \
+    static const bool gtval = VALUE;            \
+                                                \
+    template <typename T>                       \
+    static bool op (T, T) { return VALUE; }     \
+  }
+
+  OCTAVE_REGISTER_INT_CONST_OP (ct, true);
+  OCTAVE_REGISTER_INT_CONST_OP (cf, false);
+
+#undef OCTAVE_REGISTER_INT_CONST_OP
 
   // Universal comparison operation.
+
   template <typename xop, typename T1, typename T2>
   static bool
   op (T1 x, T2 y)
   {
     typedef typename prom<T1, T2>::type PT1;
     typedef typename prom<T2, T1>::type PT2;
+
     return uiop<xop, sizeof (PT1)>::op (static_cast<PT1> (x),
                                         static_cast<PT2> (y));
   }
 
 public:
 
-  // Mixed comparisons
+  // Mixed comparisons.
+
   template <typename xop, typename T>
-  static bool
-  mop (T x, double y)
-  { return xop::op (static_cast<double> (x), y); }
+  static bool mop (T x, double y)
+  {
+    return xop::op (static_cast<double> (x), y);
+  }
 
   template <typename xop, typename T>
-  static bool
-  mop (double x, T y)
-  { return xop::op (x, static_cast<double> (y)); }
+  static bool mop (double x, T y)
+  {
+    return xop::op (x, static_cast<double> (y));
+  }
 
 #if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
-#  define DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS(T)       \
-  template <typename xop> static OCTAVE_API bool        \
-  external_mop (double, T);                             \
-  template <typename xop> static OCTAVE_API bool        \
-  external_mop (T, double)
 
-  DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS (int64_t);
-  DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS (uint64_t);
+#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS(T)    \
+  template <typename xop>                                       \
+  static OCTAVE_API bool external_mop (double, T);              \
+                                                                \
+  template <typename xop>                                       \
+  static OCTAVE_API bool external_mop (T, double)
+
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (int64_t);
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (uint64_t);
+
 #endif
 
   // Typecasting to doubles won't work properly for 64-bit integers --
-  // they lose precision.
-  // If we have long doubles, use them...
+  // they lose precision.  If we have long doubles, use them...
+
 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
+
 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
-#    define DEFINE_LONG_DOUBLE_CMP_OP(T)        \
-  template <typename xop>                       \
-  static bool                                   \
-  mop (double x, T y)                           \
-  {                                             \
-    return external_mop<xop> (x, y);            \
-  }                                             \
-  template <typename xop>                       \
-  static bool                                   \
-  mop (T x, double y)                           \
-  {                                             \
-    return external_mop<xop> (x, y);            \
+
+#    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
+  template <typename xop>                               \
+  static bool mop (double x, T y)                       \
+  {                                                     \
+    return external_mop<xop> (x, y);                    \
+  }                                                     \
+                                                        \
+  template <typename xop>                               \
+  static bool mop (T x, double y)                       \
+  {                                                     \
+    return external_mop<xop> (x, y);                    \
   }
+
 #  else
-#    define DEFINE_LONG_DOUBLE_CMP_OP(T)        \
+
+#    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
   template <typename xop>                               \
-  static bool                                           \
-  mop (double x, T y)                                   \
+  static bool mop (double x, T y)                       \
   {                                                     \
     return xop::op (static_cast<long double> (x),       \
                     static_cast<long double> (y));      \
   }                                                     \
+                                                        \
   template <typename xop>                               \
-  static bool                                           \
-  mop (T x, double y)                                   \
+  static bool mop (T x, double y)                       \
   {                                                     \
     return xop::op (static_cast<long double> (x),       \
                     static_cast<long double> (y));      \
   }
+
 #  endif
+
 #else
+
   // ... otherwise, use external handlers
 
-  // FIXME: We could declare directly the mop methods as external,
-  // but we can't do this because bugs in gcc (<= 4.3) prevent
-  // explicit instantiations later in that case.
-#  define DEFINE_LONG_DOUBLE_CMP_OP(T)                  \
-  template <typename xop> static OCTAVE_API bool        \
-  emulate_mop (double, T);                              \
+  // FIXME: We could declare directly the mop methods as external, but
+  // we can't do this because bugs in gcc (<= 4.3) prevent explicit
+  // instantiations later in that case.
+
+#  define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)       \
   template <typename xop>                               \
-  static bool                                           \
-  mop (double x, T y)                                   \
+  static OCTAVE_API bool emulate_mop (double, T);       \
+                                                        \
+  template <typename xop>                               \
+  static bool mop (double x, T y)                       \
   {                                                     \
     return emulate_mop<xop> (x, y);                     \
   }                                                     \
-  template <typename xop> static OCTAVE_API bool        \
-  emulate_mop (T, double);                              \
+                                                        \
   template <typename xop>                               \
-  static bool                                           \
-  mop (T x, double y)                                   \
+  static OCTAVE_API bool emulate_mop (T, double);       \
+                                                        \
+  template <typename xop>                               \
+  static bool mop (T x, double y)                       \
   {                                                     \
     return emulate_mop<xop> (x, y);                     \
   }
+
 #endif
 
-  DEFINE_LONG_DOUBLE_CMP_OP(int64_t)
-  DEFINE_LONG_DOUBLE_CMP_OP(uint64_t)
+  OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (int64_t)
+  OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (uint64_t)
 
-#undef DEFINE_LONG_DOUBLE_CMP_OP
+#undef OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP
 };
 
-// Base integer class.  No data, just conversion methods and exception flags.
+// Base integer class.  No data, just conversion methods and exception
+// flags.
+
 template <typename T>
 class octave_int_base
 {
 public:
 
-  static T min_val () { return std::numeric_limits<T>::min (); }
-  static T max_val () { return std::numeric_limits<T>::max (); }
+  static T min_val (void) { return std::numeric_limits<T>::min (); }
+  static T max_val (void) { return std::numeric_limits<T>::max (); }
 
   // Convert integer value.
+
   template <typename S>
-  static T
-  truncate_int (const S& value)
+  static T truncate_int (const S& value)
   {
-    // An exhaustive test whether the max and/or min check can be omitted.
+    // An exhaustive test whether the max and/or min check can be
+    // omitted.
+
     static const bool t_is_signed = std::numeric_limits<T>::is_signed;
     static const bool s_is_signed = std::numeric_limits<S>::is_signed;
+
     static const int t_size = sizeof (T);
     static const int s_size = sizeof (S);
 
     static const bool omit_chk_min =
       (! s_is_signed || (t_is_signed && t_size >= s_size));
+
     static const bool omit_chk_max =
       (t_size > s_size || (t_size == s_size
                            && (! t_is_signed || s_is_signed)));
-    // If the check can be omitted, substitute constant false relation.
+
+    // If the check can be omitted, substitute constant false
+    // relation.
+
     typedef octave_int_cmp_op::cf cf;
     typedef octave_int_cmp_op::lt lt;
     typedef octave_int_cmp_op::gt gt;
@@ -319,157 +388,152 @@
     typedef typename if_then_else<omit_chk_max, cf, gt>::result chk_max;
 
     // Efficiency of the following depends on inlining and dead code
-    // elimination, but that should be a piece of cake for most compilers.
+    // elimination, but that should be a piece of cake for most
+    // compilers.
+
     if (chk_min::op (value, static_cast<S> (min_val ())))
-      {
-        return min_val ();
-      }
+      return min_val ();
     else if (chk_max::op (value, static_cast<S> (max_val ())))
-      {
-        return max_val ();
-      }
+      return max_val ();
     else
       return static_cast<T> (value);
   }
 
 private:
 
-  // Computes a real-valued threshold for a max/min check.
+  // Compute a real-valued threshold for a max/min check.
+
   template <typename S>
-  static S
-  compute_threshold (S val, T orig_val)
+  static S compute_threshold (S val, T orig_val)
   {
-    val = octave::math::round (val); // Fool optimizations (maybe redundant)
+    // Fool optimizations (maybe redundant).
+
+    val = octave::math::round (val);
+
     // If val is even, but orig_val is odd, we're one unit off.
+
     if (orig_val % 2 && val / 2 == octave::math::round (val / 2))
       // FIXME: is this always correct?
       val *= (static_cast<S> (1) - (std::numeric_limits<S>::epsilon () / 2));
+
     return val;
   }
 
 public:
 
   // Convert a real number (check NaN and non-int).
+
   template <typename S>
-  static T
-  convert_real (const S& value);
+  static T convert_real (const S& value);
 };
 
-// Saturated (homogeneous) integer arithmetics.  The signed and unsigned
-// implementations are significantly different, so we implement another layer
-// and completely specialize.  Arithmetics inherits from octave_int_base so
-// that it can use its exceptions and truncation functions.
+// Saturated (homogeneous) integer arithmetics.  The signed and
+// unsigned implementations are significantly different, so we
+// implement another layer and completely specialize.  Arithmetics
+// inherits from octave_int_base so that it can use its exceptions and
+// truncation functions.
 
 template <typename T, bool is_signed>
 class octave_int_arith_base
 { };
 
-// Unsigned arithmetics.  C++ standard requires it to be modular, so the
-// overflows can be handled efficiently and reliably.
+// Unsigned arithmetics.  C++ standard requires it to be modular, so
+// the overflows can be handled efficiently and reliably.
+
 template <typename T>
 class octave_int_arith_base<T, false> : octave_int_base<T>
 {
 public:
 
-  static T
-  abs (T x) { return x; }
+  static T abs (T x) { return x; }
 
-  static T
-  signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }
+  static T signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }
 
   // Shifts do not overflow.
-  static T
-  rshift (T x, int n) { return x >> n; }
 
-  static T
-  lshift (T x, int n) { return x << n; }
+  static T rshift (T x, int n) { return x >> n; }
+
+  static T lshift (T x, int n) { return x << n; }
 
-  static T
-  minus (T)
-  {
-    return static_cast<T> (0);
-  }
+  static T minus (T) { return static_cast<T> (0); }
 
-  // the overflow behavior for unsigned integers is guaranteed by C/C++,
-  // so the following should always work.
-  static T
-  add (T x, T y)
+  // The overflow behavior for unsigned integers is guaranteed by
+  // C and C++, so the following should always work.
+
+  static T add (T x, T y)
   {
     T u = x + y;
+
     if (u < x)
-      {
-        u = octave_int_base<T>::max_val ();
-      }
+      u = octave_int_base<T>::max_val ();
+
     return u;
   }
 
-  static T
-  sub (T x, T y)
+  static T sub (T x, T y)
   {
     T u = x - y;
+
     if (u > x)
-      {
-        u = 0;
-      }
+      u = 0;
+
     return u;
   }
 
-  // Multiplication is done using promotion to wider integer type.  If there is
-  // no suitable promotion type, this operation *MUST* be specialized.
+  // Multiplication is done using promotion to wider integer type.  If
+  // there is no suitable promotion type, this operation *MUST* be
+  // specialized.
+
   static T mul (T x, T y) { return mul_internal (x, y); }
 
-  static T
-  mul_internal (T x, T y)
+  static T mul_internal (T x, T y)
   {
     // Promotion type for multiplication (if exists).
+
     typedef typename query_integer_type<2*sizeof (T), false>::type mptype;
+
     return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
-           * static_cast<mptype> (y));
+                                             * static_cast<mptype> (y));
   }
 
-  // Division with rounding to nearest.  Note that / and % are probably
-  // computed by a single instruction.
-  static T
-  div (T x, T y)
+  // Division with rounding to nearest.  Note that / and % are
+  // probably computed by a single instruction.
+
+  static T div (T x, T y)
   {
     if (y != 0)
       {
         T z = x / y;
         T w = x % y;
-        if (w >= y-w) z += 1;
+
+        if (w >= y-w)
+          z += 1;
+
         return z;
       }
     else
-      {
-        return x ? octave_int_base<T>::max_val () : 0;
-      }
+      return x ? octave_int_base<T>::max_val () : 0;
   }
 
   // Remainder.
-  static T
-  rem (T x, T y)
-  {
-    return y != 0 ? x % y : 0;
-  }
+
+  static T rem (T x, T y) { return y != 0 ? x % y : 0; }
 
   // Modulus.  Note the weird y = 0 case for Matlab compatibility.
-  static T
-  mod (T x, T y)
-  {
-    return y != 0 ? x % y : x;
-  }
+
+  static T mod (T x, T y) { return y != 0 ? x % y : x; }
 };
 
 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
 
-// Handle 64-bit multiply using long double
+// Handle 64-bit multiply using long double.
 
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
 
 extern OCTAVE_API uint64_t
 octave_external_uint64_uint64_mul (uint64_t, uint64_t);
 
-#endif
+#  endif
 
 template <>
 inline uint64_t
@@ -491,16 +555,17 @@
 inline uint64_t
 octave_int_arith_base<uint64_t, false>::mul (uint64_t x, uint64_t y)
 {
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
   return octave_external_uint64_uint64_mul (x, y);
-#else
+#  else
   return mul_internal (x, y);
-#endif
+#  endif
 }
 
 #else
 
 // Special handler for 64-bit integer multiply.
+
 template <>
 OCTAVE_API uint64_t
 octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t, uint64_t);
@@ -512,17 +577,14 @@
 {
   // The corresponding unsigned type.
   typedef typename query_integer_type<sizeof (T), false>::type UT;
+
 public:
 
   // Returns 1 for negative number, 0 otherwise.
-  static T
-  __signbit (T x)
-  {
-    return (x < 0) ? 1 : 0;
-  }
 
-  static T
-  abs (T x)
+  static T __signbit (T x) { return (x < 0) ? 1 : 0; }
+
+  static T abs (T x)
   {
     // -INT_MAX is safe because C++ actually allows only three
     // implementations of integers: sign & magnitude, ones complement
@@ -536,27 +598,24 @@
             : ((x < 0) ? -x : x));
   }
 
-  static T
-  signum (T x)
+  static T signum (T x)
   {
     // With modest optimizations, this will compile without a jump.
+
     return ((x > 0) ? 1 : 0) - __signbit (x);
   }
 
   // FIXME: we do not have an authority what signed shifts should
-  // exactly do, so we define them the easy way.  Note that Matlab does
-  // not define signed shifts.
+  // exactly do, so we define them the easy way.  Note that Matlab
+  // does not define signed shifts.
 
-  static T
-  rshift (T x, int n) { return x >> n; }
+  static T rshift (T x, int n) { return x >> n; }
 
-  static T
-  lshift (T x, int n) { return x << n; }
+  static T lshift (T x, int n) { return x << n; }
 
   // Minus has problems similar to abs.
 
-  static T
-  minus (T x)
+  static T minus (T x)
   {
     return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
              && x == octave_int_base<T>::min_val ())
@@ -564,8 +623,7 @@
             : -x);
   }
 
-  static T
-  add (T x, T y)
+  static T add (T x, T y)
   {
     // Avoid anything that may overflow.
 
@@ -578,8 +636,7 @@
                : x + y));
   }
 
-  static T
-  sub (T x, T y)
+  static T sub (T x, T y)
   {
     // Avoid anything that may overflow.
 
@@ -592,24 +649,28 @@
                : x - y));
   }
 
-  // Multiplication is done using promotion to wider integer type.  If there is
-  // no suitable promotion type, this operation *MUST* be specialized.
+  // Multiplication is done using promotion to wider integer type.  If
+  // there is no suitable promotion type, this operation *MUST* be
+  // specialized.
+
   static T mul (T x, T y) { return mul_internal (x, y); }
 
-  static T
-  mul_internal (T x, T y)
+  static T mul_internal (T x, T y)
   {
     // Promotion type for multiplication (if exists).
+
     typedef typename query_integer_type<2*sizeof (T), true>::type mptype;
+
     return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
            * static_cast<mptype> (y));
   }
 
   // Division.
-  static T
-  div (T x, T y)
+
+  static T div (T x, T y)
   {
     T z;
+
     if (y == 0)
       {
         if (x < 0)
@@ -623,9 +684,7 @@
       {
         // This is a special case that overflows as well.
         if (y == -1 && x == octave_int_base<T>::min_val ())
-          {
-            z = octave_int_base<T>::max_val ();
-          }
+          z = octave_int_base<T>::max_val ();
         else
           {
             z = x / y;
@@ -638,6 +697,7 @@
     else
       {
         z = x / y;
+
         // FIXME: this is a workaround due to MSVC's absence of
         // std::abs (int64_t).  The call to octave_int_abs can't
         // overflow, but std::abs (x) can!
@@ -650,15 +710,15 @@
   }
 
   // Remainder.
-  static T
-  rem (T x, T y)
+
+  static T rem (T x, T y)
   {
     return y != 0 ? x % y : 0;
   }
 
   // Modulus.  Note the weird y = 0 case for Matlab compatibility.
-  static T
-  mod (T x, T y)
+
+  static T mod (T x, T y)
   {
     if (y != 0)
       {
@@ -674,12 +734,12 @@
 
 // Handle 64-bit multiply using long double
 
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
 
 extern OCTAVE_API int64_t
 octave_external_int64_int64_mul (int64_t, int64_t);
 
-#endif
+#  endif
 
 template <>
 inline int64_t
@@ -703,16 +763,17 @@
 inline int64_t
 octave_int_arith_base<int64_t, true>::mul (int64_t x, int64_t y)
 {
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
   return octave_external_int64_int64_mul (x, y);
-#else
+#  else
   return mul_internal (x, y);
-#endif
+#  endif
 }
 
 #else
 
 // Special handler for 64-bit integer multiply.
+
 template <>
 OCTAVE_API int64_t
 octave_int_arith_base<int64_t, true>::mul_internal (int64_t, int64_t);
@@ -730,6 +791,7 @@
 octave_int : public octave_int_base<T>
 {
 public:
+
   typedef T val_type;
 
   octave_int (void) : ival () { }
@@ -737,24 +799,32 @@
   octave_int (T i) : ival (i) { }
 
 #if defined (OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES)
+
   // Always treat characters as unsigned.
   octave_int (char c)
     : ival (octave_int_base<T>::truncate_int (static_cast<unsigned char> (c)))
   { }
+
 #endif
 
-  octave_int (double d) : ival (octave_int_base<T>::convert_real (d)) { }
+  octave_int (double d)
+    : ival (octave_int_base<T>::convert_real (d)) { }
 
-  octave_int (float d) : ival (octave_int_base<T>::convert_real (d)) { }
+  octave_int (float d)
+    : ival (octave_int_base<T>::convert_real (d)) { }
 
 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
-  octave_int (long double d) : ival (octave_int_base<T>::convert_real (d)) { }
+
+  octave_int (long double d)
+    : ival (octave_int_base<T>::convert_real (d)) { }
+
 #endif
 
   octave_int (bool b) : ival (b) { }
 
   template <typename U>
-  octave_int (const U& i) : ival(octave_int_base<T>::truncate_int (i)) { }
+  octave_int (const U& i)
+    : ival(octave_int_base<T>::truncate_int (i)) { }
 
   template <typename U>
   octave_int (const octave_int<U>& i)
@@ -771,7 +841,9 @@
   T value (void) const { return ival; }
 
   const unsigned char * iptr (void) const
-  { return reinterpret_cast<const unsigned char *> (& ival); }
+  {
+    return reinterpret_cast<const unsigned char *> (& ival);
+  }
 
   bool operator ! (void) const { return ! ival; }
 
@@ -785,21 +857,19 @@
 
   operator T (void) const { return value (); }
 
-  octave_int<T>
-  operator + () const
-  { return *this; }
+  octave_int<T> operator + () const { return *this; }
 
   // unary operators & mappers
-#define OCTAVE_INT_UN_OP(OPNAME,NAME)           \
+#define OCTAVE_INT_UN_OP(OPNAME, NAME)          \
   inline octave_int<T>                          \
   OPNAME () const                               \
   {                                             \
     return octave_int_arith<T>::NAME (ival);    \
   }
 
-  OCTAVE_INT_UN_OP(operator -, minus)
-  OCTAVE_INT_UN_OP(abs, abs)
-  OCTAVE_INT_UN_OP(signum, signum)
+  OCTAVE_INT_UN_OP (operator -, minus)
+  OCTAVE_INT_UN_OP (abs, abs)
+  OCTAVE_INT_UN_OP (signum, signum)
 
 #undef OCTAVE_INT_UN_OP
 
@@ -810,6 +880,7 @@
   {                                             \
     return octave_int_arith<T>::NAME (ival, y); \
   }                                             \
+                                                \
   inline octave_int<T>&                         \
   operator OP##= (const ARGT& y)                \
   {                                             \
@@ -817,13 +888,13 @@
     return *this;                               \
   }
 
-  OCTAVE_INT_BIN_OP(+, add, octave_int<T>)
-  OCTAVE_INT_BIN_OP(-, sub, octave_int<T>)
-  OCTAVE_INT_BIN_OP(*, mul, octave_int<T>)
-  OCTAVE_INT_BIN_OP(/, div, octave_int<T>)
-  OCTAVE_INT_BIN_OP(%, rem, octave_int<T>)
-  OCTAVE_INT_BIN_OP(<<, lshift, int)
-  OCTAVE_INT_BIN_OP(>>, rshift, int)
+  OCTAVE_INT_BIN_OP (+, add, octave_int<T>)
+  OCTAVE_INT_BIN_OP (-, sub, octave_int<T>)
+  OCTAVE_INT_BIN_OP (*, mul, octave_int<T>)
+  OCTAVE_INT_BIN_OP (/, div, octave_int<T>)
+  OCTAVE_INT_BIN_OP (%, rem, octave_int<T>)
+  OCTAVE_INT_BIN_OP (<<, lshift, int)
+  OCTAVE_INT_BIN_OP (>>, rshift, int)
 
 #undef OCTAVE_INT_BIN_OP
 
@@ -877,18 +948,6 @@
   }
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-template <typename T>
-OCTAVE_DEPRECATED (4.2, "use 'octave::math::isnan' instead")
-bool
-xisnan (const octave_int<T>& x)
-{
-  return octave::math::isnan (x);
-}
-
-#endif
-
 // FIXME: can/should any of these be inline?
 
 template <typename T>
@@ -914,6 +973,7 @@
 // FIXME: Do we really need a differently named single-precision
 //        function integer power function here instead of an overloaded
 //        one?
+
 template <typename T>
 extern OCTAVE_API octave_int<T>
 powf (const float& a, const octave_int<T>& b);
@@ -970,6 +1030,7 @@
 operator << (std::ostream& os, const octave_int<int8_t>& ival)
 {
   os << static_cast<int> (ival.value ());
+
   return os;
 }
 
@@ -978,6 +1039,7 @@
 operator << (std::ostream& os, const octave_int<uint8_t>& ival)
 {
   os << static_cast<unsigned int> (ival.value ());
+
   return os;
 }
 
@@ -988,6 +1050,7 @@
   int tmp = 0;
   is >> tmp;
   ival = static_cast<int8_t> (tmp);
+
   return is;
 }
 
@@ -998,6 +1061,7 @@
   unsigned int tmp = 0;
   is >> tmp;
   ival = static_cast<uint8_t> (tmp);
+
   return is;
 }
 
@@ -1033,30 +1097,32 @@
 
 #if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
 
-#define DECLARE_EXTERNAL_LONG_DOUBLE_OP(T, OP)          \
-  extern OCTAVE_API T                                   \
-  external_double_ ## T ## _ ## OP (double x, T y);     \
-  extern OCTAVE_API T                                   \
+#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP(T, OP)     \
+  extern OCTAVE_API T                                           \
+  external_double_ ## T ## _ ## OP (double x, T y);             \
+                                                                \
+  extern OCTAVE_API T                                           \
   external_ ## T ## _double_ ## OP (T x, double y)
 
-#define DECLARE_EXTERNAL_LONG_DOUBLE_OPS(T)     \
-  DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, add);     \
-  DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, sub);     \
-  DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, mul);     \
-  DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, div)
+#  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS(T)        \
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, add);          \
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, sub);          \
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, mul);          \
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, div)
 
-DECLARE_EXTERNAL_LONG_DOUBLE_OPS (octave_int64);
-DECLARE_EXTERNAL_LONG_DOUBLE_OPS (octave_uint64);
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_int64);
+  OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_uint64);
 
 #endif
 
-#define OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
-  template <typename T> \
-  inline octave_int<T> \
+#define OCTAVE_INT_DOUBLE_BIN_OP0(OP)                           \
+  template <typename T>                                         \
+  inline octave_int<T>                                          \
   operator OP (const octave_int<T>& x, const double& y)         \
   {                                                             \
     return octave_int<T> (static_cast<double> (x) OP y);        \
   }                                                             \
+                                                                \
   template <typename T>                                         \
   inline octave_int<T>                                          \
   operator OP (const double& x, const octave_int<T>& y)         \
@@ -1065,75 +1131,96 @@
   }
 
 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
-// Handle mixed op using long double
-#if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
-#  define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                    \
+
+// Handle mixed op using long double.
+
+#  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
+
+#    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                  \
   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                 \
+                                                                \
   template <>                                                   \
   inline octave_int64                                           \
   operator OP (const double& x, const octave_int64& y)          \
   {                                                             \
     return external_double_octave_int64_ ## NAME (x, y);        \
   }                                                             \
+                                                                \
   template <>                                                   \
   inline octave_uint64                                          \
   operator OP (const double& x, const octave_uint64& y)         \
   {                                                             \
     return external_double_octave_uint64_ ## NAME (x, y);       \
   }                                                             \
+                                                                \
   template <>                                                   \
   inline octave_int64                                           \
   operator OP (const octave_int64& x, const double& y)          \
   {                                                             \
     return external_octave_int64_double_ ## NAME (x, y);        \
   }                                                             \
+                                                                \
   template <>                                                   \
   inline octave_uint64                                          \
   operator OP (const octave_uint64& x, const double& y)         \
   {                                                             \
     return external_octave_uint64_double_ ## NAME (x, y);       \
   }
-#else
-#  define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
+
+#  else
+
+#    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                          \
   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                         \
+                                                                        \
   template <>                                                           \
   inline octave_int64                                                   \
   operator OP (const double& x, const octave_int64& y)                  \
   {                                                                     \
     return octave_int64 (x OP static_cast<long double> (y.value ()));   \
   }                                                                     \
+                                                                        \
   template <>                                                           \
   inline octave_uint64                                                  \
   operator OP (const double& x, const octave_uint64& y)                 \
   {                                                                     \
     return octave_uint64 (x OP static_cast<long double> (y.value ()));  \
   }                                                                     \
+                                                                        \
   template <>                                                           \
   inline octave_int64                                                   \
   operator OP (const octave_int64& x, const double& y)                  \
   {                                                                     \
     return octave_int64 (static_cast<long double> (x.value ()) OP y);   \
   }                                                                     \
+                                                                        \
   template <>                                                           \
   inline octave_uint64                                                  \
   operator OP (const octave_uint64& x, const double& y)                 \
   {                                                                     \
     return octave_uint64 (static_cast<long double> (x.value ()) OP y);  \
   }
-#endif
+
+#  endif
+
 #else
-// external handlers
-#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
+
+// External handlers.
+
+#  define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)            \
   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                         \
+                                                        \
   template <>                                           \
   OCTAVE_API octave_int64                               \
   operator OP (const double&, const octave_int64&);     \
+                                                        \
   template <>                                           \
   OCTAVE_API octave_uint64                              \
   operator OP (const double&, const octave_uint64&);    \
+                                                        \
   template <>                                           \
   OCTAVE_API octave_int64                               \
   operator OP (const octave_int64&, const double&);     \
+                                                        \
   template <>                                           \
   OCTAVE_API octave_uint64                              \
   operator OP (const octave_uint64&, const double&);
@@ -1147,16 +1234,17 @@
 
 #undef OCTAVE_INT_DOUBLE_BIN_OP0
 #undef OCTAVE_INT_DOUBLE_BIN_OP
-#undef DECLARE_EXTERNAL_LONG_DOUBLE_OP
-#undef DECLARE_EXTERNAL_LONG_DOUBLE_OPS
+#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP
+#undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS
 
-#define OCTAVE_INT_DOUBLE_CMP_OP(OP,NAME)                               \
+#define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME)                              \
   template <typename T>                                                 \
   inline bool                                                           \
   operator OP (const octave_int<T>& x, const double& y)                 \
   {                                                                     \
     return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x.value (), y); \
   }                                                                     \
+                                                                        \
   template <typename T>                                                 \
   inline bool                                                           \
   operator OP (const double& x, const octave_int<T>& y)                 \
@@ -1182,6 +1270,7 @@
   {                                             \
     return x OP static_cast<double> (y);        \
   }                                             \
+                                                \
   template <typename T>                         \
   inline octave_int<T>                          \
   operator OP (float x, const octave_int<T>& y) \
@@ -1203,6 +1292,7 @@
   {                                                     \
     return x OP static_cast<double> (y);                \
   }                                                     \
+                                                        \
   template <typename T>                                 \
   bool                                                  \
   operator OP (const float& x, const octave_int<T>& y)  \
@@ -1225,6 +1315,7 @@
 {
   const T xv = x.value ();
   const T yv = y.value ();
+
   return octave_int<T> (xv >= yv ? xv : yv);
 }
 
@@ -1234,6 +1325,7 @@
 {
   const T xv = x.value ();
   const T yv = y.value ();
+
   return octave_int<T> (xv <= yv ? xv : yv);
 }
 
--- a/liboctave/util/oct-shlib.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-shlib.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -62,6 +62,10 @@
 #include "oct-shlib.h"
 #include "str-vec.h"
 
+#if defined (HAVE_LOADLIBRARY_API)
+#  include "lo-sysdep.h"
+#endif
+
 namespace octave
 {
   dynamic_library::dynlib_rep::dynlib_rep (const std::string& f)
@@ -371,7 +375,8 @@
   static void
   set_dll_directory (const std::string& dir = "")
   {
-    SetDllDirectory (dir.empty () ? nullptr : dir.c_str ());
+    SetDllDirectoryW (dir.empty () ? nullptr
+                                   : sys::u8_to_wstring (dir).c_str ());
   }
 
   octave_w32_shlib::octave_w32_shlib (const std::string& f)
@@ -387,7 +392,7 @@
 
     set_dll_directory (dir);
 
-    handle = LoadLibrary (file.c_str ());
+    handle = LoadLibraryW (sys::u8_to_wstring (file).c_str ());
 
     set_dll_directory ();
 
--- a/liboctave/util/oct-shlib.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-shlib.h	Thu Dec 20 17:18:56 2018 -0500
@@ -202,11 +202,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::dynamic_library' instead")
-typedef octave::dynamic_library octave_shlib;
-
 #endif
-
-#endif
--- a/liboctave/util/oct-sort.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-sort.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -111,6 +111,7 @@
 #include <cstring>
 #include <stack>
 
+#include "lo-error.h"
 #include "lo-mappers.h"
 #include "quit.h"
 #include "oct-sort.h"
@@ -493,10 +494,10 @@
 }
 
 static inline octave_idx_type
-roundupsize (octave_idx_type n)
+roundupsize (size_t n)
 {
   unsigned int nbits = 3;
-  octave_idx_type n2 = static_cast<octave_idx_type> (n) >> 8;
+  size_t n2 = n >> 8;
 
   /* Round up:
    * If n <       256, to a multiple of        8.
@@ -526,7 +527,13 @@
       nbits += 3;
     }
 
-  return ((n >> nbits) + 1) << nbits;
+  size_t new_size = ((n >> nbits) + 1) << nbits;
+
+  if (new_size == 0 || new_size > std::numeric_limits<octave_idx_type>::max ())
+    (*current_liboctave_error_handler)
+      ("unable to allocate sufficient memory for sort");
+
+  return static_cast<octave_idx_type> (new_size);
 }
 
 /* Ensure enough temp memory for 'need' array slots is available.
@@ -1394,7 +1401,7 @@
   if (! ms) ms = new MergeState;
 
   ms->reset ();
-  ms->getmem (1024);
+  ms->getmem (MERGESTATE_TEMP_SIZE);
 
   if (nel > 1)
     {
@@ -1451,7 +1458,7 @@
   if (! ms) ms = new MergeState;
 
   ms->reset ();
-  ms->getmemi (1024);
+  ms->getmemi (MERGESTATE_TEMP_SIZE);
 
   if (nel > 1)
     {
--- a/liboctave/util/oct-sort.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-sort.h	Thu Dec 20 17:18:56 2018 -0500
@@ -87,20 +87,6 @@
 
 #include "lo-traits.h"
 
-// The maximum number of entries in a MergeState's pending-runs stack.
-// This is enough to sort arrays of size up to about
-//     32 * phi ** MAX_MERGE_PENDING
-// where phi ~= 1.618.  85 is ridiculously large enough, good for an array
-// with 2**64 elements.
-#define MAX_MERGE_PENDING 85
-
-// When we get into galloping mode, we stay there until both runs win less
-// often than MIN_GALLOP consecutive times.  See listsort.txt for more info.
-#define MIN_GALLOP 7
-
-// Avoid malloc for small temp arrays.
-#define MERGESTATE_TEMP_SIZE 1024
-
 // Enum for type of sort function
 enum sortmode { UNSORTED = 0, ASCENDING, DESCENDING };
 
@@ -179,6 +165,20 @@
 
 private:
 
+  // The maximum number of entries in a MergeState's pending-runs stack.
+  // This is enough to sort arrays of size up to about
+  //     32 * phi ** MAX_MERGE_PENDING
+  // where phi ~= 1.618.  85 is ridiculously large enough, good for an array
+  // with 2**64 elements.
+  static const int MAX_MERGE_PENDING = 85;
+
+  // When we get into galloping mode, we stay there until both runs win less
+  // often than MIN_GALLOP consecutive times.  See listsort.txt for more info.
+  static const int MIN_GALLOP = 7;
+
+  // Avoid malloc for small temp arrays.
+  static const int MERGESTATE_TEMP_SIZE = 1024;
+
   // One MergeState exists on the stack per invocation of mergesort.
   // It's just a convenient way to pass state around among the helper
   // functions.
--- a/liboctave/util/oct-string.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-string.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -25,12 +25,15 @@
 
 #include "oct-string.h"
 
+#include <algorithm>
 #include <cctype>
 #include <cstring>
-
+#include <iomanip>
 #include <string>
 
 #include "Array.h"
+#include "lo-ieee.h"
+#include "lo-mappers.h"
 
 template <typename T>
 static bool
@@ -146,8 +149,13 @@
 octave::string::strncmp (const T& str_a, const T& str_b,
                          const typename T::size_type n)
 {
-  return (numel (str_a) >= n && numel (str_b) >= n
-          && str_data_cmp<T> (str_a.data (), str_b.data (), n));
+  typename T::size_type neff;
+  auto len_a = numel (str_a);
+  auto len_b = numel (str_b);
+  neff = std::min (std::max (len_a, len_b), n);
+
+  return (len_a >= neff && len_b >= neff
+          && str_data_cmp<T> (str_a.data (), str_b.data (), neff));
 }
 
 template<typename T>
@@ -155,8 +163,13 @@
 octave::string::strncmp (const T& str_a, const typename T::value_type *str_b,
                          const typename T::size_type n)
 {
-  return (numel (str_a) >= n && strlen<T> (str_b) >= n
-          && str_data_cmp<T> (str_a.data (), str_b, n));
+  typename T::size_type neff;
+  auto len_a = numel (str_a);
+  auto len_b = strlen<T> (str_b);
+  neff = std::min (std::max (len_a, len_b), n);
+
+  return (len_a >= neff && len_b >= neff
+          && str_data_cmp<T> (str_a.data (), str_b, neff));
 }
 
 
@@ -165,8 +178,13 @@
 octave::string::strncmpi (const T& str_a, const T& str_b,
                           const typename T::size_type n)
 {
-  return (numel (str_a) >= n && numel (str_b) >= n
-          && str_data_cmpi<T> (str_a.data (), str_b.data (), n));
+  typename T::size_type neff;
+  auto len_a = numel (str_a);
+  auto len_b = numel (str_b);
+  neff = std::min (std::max (len_a, len_b), n);
+
+  return (len_a >= neff && len_b >= neff
+          && str_data_cmpi<T> (str_a.data (), str_b.data (), neff));
 }
 
 template<typename T>
@@ -174,8 +192,13 @@
 octave::string::strncmpi (const T& str_a, const typename T::value_type *str_b,
                           const typename T::size_type n)
 {
-  return (numel (str_a) >= n && strlen<T> (str_b) >= n
-          && str_data_cmpi<T> (str_a.data (), str_b, n));
+  typename T::size_type neff;
+  auto len_a = numel (str_a);
+  auto len_b = strlen<T> (str_b);
+  neff = std::min (std::max (len_a, len_b), n);
+
+  return (len_a >= neff && len_b >= neff
+          && str_data_cmpi<T> (str_a.data (), str_b, neff));
 }
 
 
@@ -204,3 +227,363 @@
 INSTANTIATE_OCTAVE_STRING(Array<char>)
 
 #undef INSTANTIATE_OCTAVE_STRING
+
+static inline bool
+is_imag_unit (int c)
+{ return c == 'i' || c == 'j'; }
+
+static double
+single_num (std::istringstream& is)
+{
+  double num = 0.0;
+
+  char c = is.peek ();
+
+  // Skip spaces.
+  while (isspace (c))
+    {
+      is.get ();
+      c = is.peek ();
+    }
+
+  if (std::toupper (c) == 'I')
+    {
+      // It's infinity.
+      is.get ();
+      char c1 = is.get ();
+      char c2 = is.get ();
+      if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f')
+        {
+          num = octave::numeric_limits<double>::Inf ();
+          is.peek (); // May set EOF bit.
+        }
+      else
+        is.setstate (std::ios::failbit); // indicate that read has failed.
+    }
+  else if (c == 'N')
+    {
+      // It's NA or NaN
+      is.get ();
+      char c1 = is.get ();
+      if (c1 == 'A')
+        {
+          num = octave_NA;
+          is.peek (); // May set EOF bit.
+        }
+      else
+        {
+          char c2 = is.get ();
+          if (c1 == 'a' && c2 == 'N')
+            {
+              num = octave::numeric_limits<double>::NaN ();
+              is.peek (); // May set EOF bit.
+            }
+          else
+            is.setstate (std::ios::failbit); // indicate that read has failed.
+        }
+    }
+  else
+    is >> num;
+
+  return num;
+}
+
+static std::istringstream&
+extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign)
+{
+  have_sign = imag = false;
+
+  char c = is.peek ();
+
+  // Skip leading spaces.
+  while (isspace (c))
+    {
+      is.get ();
+      c = is.peek ();
+    }
+
+  bool negative = false;
+
+  // Accept leading sign.
+  if (c == '+' || c == '-')
+    {
+      have_sign = true;
+      negative = c == '-';
+      is.get ();
+      c = is.peek ();
+    }
+
+  // Skip spaces after sign.
+  while (isspace (c))
+    {
+      is.get ();
+      c = is.peek ();
+    }
+
+  // Imaginary number (i*num or just i), or maybe 'inf'.
+  if (c == 'i')
+    {
+      // possible infinity.
+      is.get ();
+      c = is.peek ();
+
+      if (is.eof ())
+        {
+          // just 'i' and string is finished.  Return immediately.
+          imag = true;
+          num = (negative ? -1.0 : 1.0);
+          return is;
+        }
+      else
+        {
+          if (std::tolower (c) != 'n')
+            imag = true;
+          is.unget ();
+        }
+    }
+  else if (c == 'j')
+    imag = true;
+
+  // It's i*num or just i
+  if (imag)
+    {
+      is.get ();
+      c = is.peek ();
+      // Skip spaces after imaginary unit.
+      while (isspace (c))
+        {
+          is.get ();
+          c = is.peek ();
+        }
+
+      if (c == '*')
+        {
+          // Multiplier follows, we extract it as a number.
+          is.get ();
+          num = single_num (is);
+          if (is.good ())
+            c = is.peek ();
+        }
+      else
+        num = 1.0;
+    }
+  else
+    {
+      // It's num, num*i, or numi.
+      num = single_num (is);
+      if (is.good ())
+        {
+          c = is.peek ();
+
+          // Skip spaces after number.
+          while (isspace (c))
+            {
+              is.get ();
+              c = is.peek ();
+            }
+
+          if (c == '*')
+            {
+              is.get ();
+              c = is.peek ();
+
+              // Skip spaces after operator.
+              while (isspace (c))
+                {
+                  is.get ();
+                  c = is.peek ();
+                }
+
+              if (is_imag_unit (c))
+                {
+                  imag = true;
+                  is.get ();
+                  c = is.peek ();
+                }
+              else
+                is.setstate (std::ios::failbit); // indicate read has failed.
+            }
+          else if (is_imag_unit (c))
+            {
+              imag = true;
+              is.get ();
+              c = is.peek ();
+            }
+        }
+    }
+
+  if (is.good ())
+    {
+      // Skip trailing spaces.
+      while (isspace (c))
+        {
+          is.get ();
+          c = is.peek ();
+        }
+    }
+
+  if (negative)
+    num = -num;
+
+  return is;
+}
+
+static inline void
+set_component (Complex& c, double num, bool imag)
+{
+#if defined (HAVE_CXX_COMPLEX_SETTERS)
+  if (imag)
+    c.imag (num);
+  else
+    c.real (num);
+#elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
+  if (imag)
+    c.imag () = num;
+  else
+    c.real () = num;
+#else
+  if (imag)
+    c = Complex (c.real (), num);
+  else
+    c = Complex (num, c.imag ());
+#endif
+}
+
+Complex
+octave::string::str2double (const std::string& str_arg)
+{
+  Complex val (0.0, 0.0);
+
+  std::string str = str_arg;
+
+  // FIXME: removing all commas doesn't allow actual parsing.
+  //        Example: "1,23.45" is wrong, but passes Octave.
+  str.erase (std::remove (str.begin (), str.end(), ','), str.end ());
+  std::istringstream is (str);
+
+  double num;
+  bool i1, i2, s1, s2;
+
+  if (is.eof ())
+    val = octave::numeric_limits<double>::NaN ();
+  else if (! extract_num (is, num, i1, s1))
+    val = octave::numeric_limits<double>::NaN ();
+  else
+    {
+      set_component (val, num, i1);
+
+      if (! is.eof ())
+        {
+          if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
+            val = octave::numeric_limits<double>::NaN ();
+          else
+            set_component (val, num, i2);
+        }
+    }
+
+  return val;
+}
+
+template <typename T>
+std::string
+rational_approx (T val, int len)
+{
+  std::string s;
+
+  if (len <= 0)
+    len = 10;
+
+  if (octave::math::isinf (val))
+    {
+      if (val > 0)
+        s = "1/0";
+      else
+        s = "-1/0";
+    }
+  else if (octave::math::isnan (val))
+    s = "0/0";
+  else if (val < std::numeric_limits<int>::min ()
+           || val > std::numeric_limits<int>::max ()
+           || octave::math::x_nint (val) == val)
+    {
+      std::ostringstream buf;
+      buf.flags (std::ios::fixed);
+      buf << std::setprecision (0) << octave::math::round (val);
+      s = buf.str ();
+    }
+  else
+    {
+      T lastn = 1;
+      T lastd = 0;
+      T n = octave::math::round (val);
+      T d = 1;
+      T frac = val - n;
+      int m = 0;
+
+      std::ostringstream buf2;
+      buf2.flags (std::ios::fixed);
+      buf2 << std::setprecision (0) << static_cast<int> (n);
+      s = buf2.str ();
+
+      while (true)
+        {
+          T flip = 1 / frac;
+          T step = octave::math::round (flip);
+          T nextn = n;
+          T nextd = d;
+
+          // Have we converged to 1/intmax ?
+          if (std::abs (flip) > static_cast<T> (std::numeric_limits<int>::max ()))
+            {
+              lastn = n;
+              lastd = d;
+              break;
+            }
+
+          frac = flip - step;
+          n = step * n + lastn;
+          d = step * d + lastd;
+          lastn = nextn;
+          lastd = nextd;
+
+          std::ostringstream buf;
+          buf.flags (std::ios::fixed);
+          buf << std::setprecision (0) << static_cast<int> (n)
+              << '/' << static_cast<int> (d);
+          m++;
+
+          if (n < 0 && d < 0)
+            {
+              // Double negative, string can be two characters longer.
+              if (buf.str ().length () > static_cast<unsigned int> (len + 2))
+                break;
+            }
+          else if (buf.str ().length () > static_cast<unsigned int> (len))
+            break;
+
+          if (std::abs (n) > std::numeric_limits<int>::max ()
+              || std::abs (d) > std::numeric_limits<int>::max ())
+            break;
+
+          s = buf.str ();
+        }
+
+      if (lastd < 0)
+        {
+          // Move sign to the top
+          lastd = - lastd;
+          lastn = - lastn;
+          std::ostringstream buf;
+          buf.flags (std::ios::fixed);
+          buf << std::setprecision (0) << static_cast<int> (lastn)
+              << '/' << static_cast<int> (lastd);
+          s = buf.str ();
+        }
+    }
+
+  return s;
+}
+
+// instanciate 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);
--- a/liboctave/util/oct-string.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/oct-string.h	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,8 @@
 
 #include "octave-config.h"
 
+#include "oct-cmplx.h"
+
 namespace octave
 {
   //! Octave string utility functions.
@@ -120,7 +122,14 @@
     template <typename T>
     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);
   }
 }
 
+template <typename T>
+extern OCTAVE_API std::string
+rational_approx (T val, int len);
+
 #endif
--- a/liboctave/util/pathsearch.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/pathsearch.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,9 +36,9 @@
 
 namespace octave
 {
-  directory_path::directory_path (const std::string& s, const std::string& d)
-    : m_orig_path (s), m_default_path (d), m_initialized (false),
-      m_expanded_path (), m_path_elements ()
+  directory_path::directory_path (const std::string& s)
+    : m_orig_path (s), m_initialized (false), m_expanded_path (),
+      m_path_elements ()
   {
     if (! m_orig_path.empty ())
       init ();
@@ -108,10 +108,7 @@
         octave_kpse_initialized = true;
       }
 
-    m_expanded_path
-      = kpse_path_expand (m_default_path.empty ()
-                          ? m_orig_path
-                          : kpse_expand_default (m_orig_path, m_default_path));
+    m_expanded_path = kpse_path_expand (m_orig_path);
 
     for (kpse_path_iterator pi (m_expanded_path); pi != std::string::npos; pi++)
       m_path_elements.push_back (*pi);
--- a/liboctave/util/pathsearch.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/pathsearch.h	Thu Dec 20 17:18:56 2018 -0500
@@ -36,7 +36,7 @@
   {
   public:
 
-    directory_path (const std::string& s = "", const std::string& d = "");
+    directory_path (const std::string& s = "");
 
     directory_path (const directory_path&) = default;
 
@@ -85,10 +85,6 @@
     // The colon separated list that we were given.
     std::string m_orig_path;
 
-    // The default path.  If specified, replaces leading, trailing, or
-    // doubled colons in p_orig.
-    std::string m_default_path;
-
     // TRUE means we've unpacked the path p.
     bool m_initialized;
 
@@ -103,11 +99,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::directory_path' instead")
-typedef octave::directory_path dir_path;
-
 #endif
-
-#endif
--- a/liboctave/util/quit.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/quit.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,6 @@
 
 #include <cstring>
 
-#include <iostream>
 #include <new>
 
 #include "quit.h"
@@ -94,7 +93,7 @@
 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #endif
 
-  throw octave_exit_exception (exit_status, safe_to_return);
+  throw octave::exit_exception (exit_status, safe_to_return);
 
 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
 #  pragma GCC diagnostic pop
--- a/liboctave/util/quit.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/quit.h	Thu Dec 20 17:18:56 2018 -0500
@@ -121,15 +121,6 @@
   };
 }
 
-OCTAVE_DEPRECATED (4.2, "use 'octave::execution_exception' instead")
-typedef octave::execution_exception octave_execution_exception;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::exit_exception' instead")
-typedef octave::exit_exception octave_exit_exception;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::interrupt_exception' instead")
-typedef octave::interrupt_exception octave_interrupt_exception;
-
 #endif
 
 enum octave_exception
--- a/liboctave/util/str-vec.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/str-vec.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -32,7 +32,7 @@
 #  include "config.h"
 #endif
 
-#include <iostream>
+#include <ostream>
 #include <string>
 
 #include "cmd-edit.h"
@@ -181,6 +181,9 @@
 void
 string_vector::delete_c_str_vec (const char * const *v)
 {
+  if (! v)
+    return;
+
   const char * const *p = v;
 
   while (*p)
--- a/liboctave/util/unwind-prot.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/unwind-prot.h	Thu Dec 20 17:18:56 2018 -0500
@@ -55,11 +55,6 @@
 
     ~unwind_protect (void) { run (); }
 
-    virtual void add (elem *new_elem)
-    {
-      lifo.push (new_elem);
-    }
-
     operator bool (void) const { return ! empty (); }
 
     void run_first (void)
@@ -87,6 +82,11 @@
 
   protected:
 
+    virtual void add_action (elem *new_elem)
+    {
+      lifo.push (new_elem);
+    }
+
     std::stack<elem *> lifo;
   };
 
@@ -129,14 +129,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::unwind_protect' instead")
-typedef octave::unwind_protect unwind_protect;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::unwind_protect_safe' instead")
-typedef octave::unwind_protect_safe unwind_protect_safe;
-
 #endif
-
-#endif
--- a/liboctave/util/url-transfer.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/url-transfer.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,6 +36,7 @@
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "unwind-prot.h"
 #include "url-transfer.h"
@@ -48,6 +49,25 @@
 
 namespace octave
 {
+  base_url_transfer::base_url_transfer (void)
+    : host_or_url (), valid (false), ftp (false),
+      ascii_mode (false), ok (true), errmsg (),
+      curr_istream (&std::cin), curr_ostream (&std::cout) { }
+
+  base_url_transfer::base_url_transfer (const std::string& host,
+                                        const std::string& /* user_arg */,
+                                        const std::string& /* passwd */,
+                                        std::ostream& os)
+    : host_or_url (host), valid (false), ftp (true),
+      ascii_mode (false), ok (true), errmsg (), curr_istream (&std::cin),
+      curr_ostream (&os) { }
+
+  base_url_transfer::base_url_transfer (const std::string& url,
+                                        std::ostream& os)
+    : host_or_url (url), valid (false), ftp (false),
+      ascii_mode (false), ok (true), errmsg (),
+      curr_istream (&std::cin), curr_ostream (&os) { }
+
   void
   base_url_transfer::delete_file (const std::string& file)
   {
@@ -150,62 +170,62 @@
 
         frame.add_fcn (reset_path, this);
 
-        sys::dir_entry dirlist (realdir);
-
-        if (dirlist)
-          {
-            string_vector files = dirlist.read ();
+        string_vector files;
+        std::string msg;
 
-            for (octave_idx_type i = 0; i < files.numel (); i++)
-              {
-                std::string file = files (i);
+        if (sys::get_dirlist (realdir, files, msg))
+          for (octave_idx_type i = 0; i < files.numel (); i++)
+            {
+              std::string file = files (i);
 
-                if (file == "." || file == "..")
-                  continue;
+              if (file == "." || file == "..")
+                continue;
 
-                std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
-                sys::file_stat fs (realfile);
+              std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
+              sys::file_stat fs (realfile);
 
-                if (! fs.exists ())
-                  {
-                    ok = false;
-                    errmsg = "__ftp__mput: file '" + realfile
-                             + "' does not exist";
-                    break;
-                  }
+              if (! fs.exists ())
+                {
+                  ok = false;
+                  errmsg = "__ftp__mput: file '" + realfile
+                           + "' does not exist";
+                  break;
+                }
 
-                if (fs.is_dir ())
-                  {
-                    file_list.append (mput_directory (realdir, file));
+              if (fs.is_dir ())
+                {
+                  file_list.append (mput_directory (realdir, file));
 
-                    if (! good ())
-                      break;
-                  }
-                else
-                  {
-                    // FIXME: Does ascii mode need to be flagged here?
-                    std::ifstream ifile (realfile.c_str (), std::ios::in |
-                                         std::ios::binary);
+                  if (! good ())
+                    break;
+                }
+              else
+                {
+                  // FIXME: Does ascii mode need to be flagged here?
+                  std::string ascii_fname
+                    = octave::sys::get_ASCII_filename (realfile);
+
+                  std::ifstream ifile (ascii_fname.c_str (),
+                                       std::ios::in | std::ios::binary);
 
-                    if (! ifile.is_open ())
-                      {
-                        ok = false;
-                        errmsg = "__ftp_mput__: unable to open file '"
-                                 + realfile + "'";
-                        break;
-                      }
-
-                    put (file, ifile);
+                  if (! ifile.is_open ())
+                    {
+                      ok = false;
+                      errmsg = "__ftp_mput__: unable to open file '"
+                               + realfile + "'";
+                      break;
+                    }
 
-                    ifile.close ();
+                  put (file, ifile);
 
-                    if (! good ())
-                      break;
+                  ifile.close ();
 
-                    file_list.append (realfile);
-                  }
-              }
-          }
+                  if (! good ())
+                    break;
+
+                  file_list.append (realfile);
+                }
+            }
         else
           {
             ok = false;
@@ -241,7 +261,7 @@
   static size_t
   throw_away (void *, size_t size, size_t nmemb, void *)
   {
-    return static_cast<size_t>(size * nmemb);
+    return static_cast<size_t> (size * nmemb);
   }
 
   // I'd love to rewrite this as a private method of the url_transfer
--- a/liboctave/util/url-transfer.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/util/url-transfer.h	Thu Dec 20 17:18:56 2018 -0500
@@ -30,8 +30,9 @@
 
 #include "octave-config.h"
 
-#include <iosfwd>
+#include <istream>
 #include <memory>
+#include <ostream>
 #include <string>
 
 #include "str-vec.h"
@@ -57,23 +58,14 @@
 
     friend class url_transfer;
 
-    base_url_transfer (void)
-      : host_or_url (), valid (false), ftp (false),
-        ascii_mode (false), ok (true), errmsg (),
-        curr_istream (&std::cin), curr_ostream (&std::cout) { }
+    base_url_transfer (void);
 
     base_url_transfer (const std::string& host,
                        const std::string& /* user_arg */,
                        const std::string& /* passwd */,
-                       std::ostream& os)
-      : host_or_url (host), valid (false), ftp (true),
-        ascii_mode (false), ok (true), errmsg (), curr_istream (&std::cin),
-        curr_ostream (&os) { }
+                       std::ostream& os);
 
-    base_url_transfer (const std::string& url, std::ostream& os)
-      : host_or_url (url), valid (false), ftp (false),
-        ascii_mode (false), ok (true), errmsg (),
-        curr_istream (&std::cin), curr_ostream (&os) { }
+    base_url_transfer (const std::string& url, std::ostream& os);
 
     // No copying!
 
@@ -269,14 +261,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::base_url_transfer' instead")
-typedef octave::base_url_transfer base_url_transfer;
-
-OCTAVE_DEPRECATED (4.2, "use 'octave::url_transfer' instead")
-typedef octave::url_transfer url_transfer;
-
 #endif
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/version.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,132 @@
+/*
+
+Copyright (C) 2013-2018 John W. Eaton
+
+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 <string>
+
+#include "version.h"
+
+static std::string
+octave_warranty_statement (const std::string& extra_info = "")
+{
+  return "There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or\n\
+FITNESS FOR A PARTICULAR PURPOSE."
+         + extra_info;
+}
+
+static std::string
+format_url (bool html, const std::string& url)
+{
+  return html ? R"(<a href=")" + url + R"(">)" + url + "</a>" : url;
+}
+
+std::string
+octave_www_statement (bool html)
+{
+  return "Additional information about Octave is available at "
+         + format_url (html, "https://www.octave.org") + ".";
+}
+
+std::string
+octave_contrib_statement (bool html)
+{
+  return "Please contribute if you find this software useful.\n\
+For more information, visit "
+         + format_url (html, "https://www.octave.org/get-involved.html");
+}
+
+std::string
+octave_bugs_statement (bool html)
+{
+  return "Read " + format_url (html, "https://www.octave.org/bugs.html")
+         + " to learn how to submit bug reports.";
+}
+
+std::string
+octave_name_version_and_copyright (void)
+{
+  // The GNU coding standards say that on the first line printed by
+  // --version, the version number should follow the last space on the
+  // line.
+
+  return "GNU Octave, version " OCTAVE_VERSION "\n" OCTAVE_COPYRIGHT;
+}
+
+std::string
+octave_name_version_copyright_copying_and_warranty
+  (bool html, const std::string& extra_info)
+{
+  std::string br = (html ? "<br>\n" : "\n");
+  std::string sep = (html ? "\n</p>\n<p>\n" : "\n\n");
+
+  return octave_name_version_and_copyright ()
+         + br
+         + "This is free software; see the source code for copying conditions."
+         + br
+         + octave_warranty_statement (extra_info)
+         + sep
+         + R"(Octave was configured for ")"
+         + OCTAVE_CANONICAL_HOST_TYPE
+         + R"(".)";
+}
+
+std::string
+octave_name_version_copyright_copying_warranty_and_bugs
+  (bool html, const std::string& extra_info)
+{
+  std::string sep = (html ? "\n</p>\n<p>\n" : "\n\n");
+
+  std::string msg;
+
+  if (html)
+    msg = "<p>\n";
+
+  msg += octave_name_version_copyright_copying_and_warranty (html, extra_info)
+         + sep
+         + octave_www_statement (html)
+         + sep
+         + octave_contrib_statement (html)
+         + sep
+         + octave_bugs_statement (html)
+         + (html ? "\n</p>" : "");
+
+  return msg;
+}
+
+std::string
+octave_startup_message (bool html)
+{
+  std::string msg
+    = octave_name_version_copyright_copying_warranty_and_bugs
+        (html, "  For details, type 'warranty'.");
+
+  msg += (html ? "<p>\n" : "\n");
+
+  msg += "For information about changes from previous versions, type 'news'.";
+
+  msg += (html ? "\n</p>" : "");
+
+  return msg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/version.in.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,73 @@
+// %NO_EDIT_WARNING%
+/*
+
+Copyright (C) 1992-2018 John W. Eaton
+
+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_version_h)
+#define octave_version_h 1
+
+#include "octave-config.h"
+
+#define OCTAVE_VERSION %OCTAVE_VERSION%
+
+#define OCTAVE_MAJOR_VERSION %OCTAVE_MAJOR_VERSION%
+
+#define OCTAVE_MINOR_VERSION %OCTAVE_MINOR_VERSION%
+
+#define OCTAVE_PATCH_VERSION %OCTAVE_PATCH_VERSION%
+
+// The "API version" is used as a way of checking that interfaces in the
+// liboctave and libinterp libraries haven't changed in a backwardly
+// incompatible way when loading .oct files.  A better way to do that is
+// with library versioning, but not all systems support that.
+// NOTE: This macro will be removed in a future version of Octave.  If
+// you insist on checking for features using a version number, use the
+// OCTAVE_MAJOR_VERSION, OCTAVE_MINOR_VERSION, and
+// OCTAVE_PATCH_VERSION macros instead.
+#define OCTAVE_API_VERSION %OCTAVE_API_VERSION%
+
+#define OCTAVE_RELEASE_DATE %OCTAVE_RELEASE_DATE%
+
+#define OCTAVE_CANONICAL_HOST_TYPE %OCTAVE_CANONICAL_HOST_TYPE%
+
+#define OCTAVE_COPYRIGHT %OCTAVE_COPYRIGHT%
+
+#include <string>
+
+extern OCTINTERP_API std::string octave_www_statement (bool html = false);
+
+extern OCTINTERP_API std::string octave_contrib_statement (bool html = false);
+
+extern OCTINTERP_API std::string octave_bugs_statement (bool html = false);
+
+extern OCTINTERP_API std::string octave_name_version_and_copyright (void);
+
+extern OCTINTERP_API std::string
+octave_name_version_copyright_copying_and_warranty
+  (bool html = false, const std::string& extra_info = "");
+
+extern OCTINTERP_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);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/iconv-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,41 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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 "iconv.h"
+
+#include "iconv-wrappers.h"
+
+iconv_t
+octave_iconv_open_wrapper (const char *tocode, const char *fromcode)
+{
+  return iconv_open (tocode, fromcode);
+}
+
+int
+octave_iconv_close_wrapper (iconv_t cd)
+{
+  return iconv_close (cd);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/iconv-wrappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,40 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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_iconv_wrappers_h)
+#define octave_iconv_wrappers_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern void *
+octave_iconv_open_wrapper (const char *tocode, const char *fromcode);
+
+extern int
+octave_iconv_close_wrapper (void *cd);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/mkostemps-wrapper.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,40 @@
+/*
+
+Copyright (C) 2016-2018 John W. Eaton
+
+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/>.
+
+*/
+
+// mkostemp may be 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_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "mkostemps-wrapper.h"
+
+int
+octave_mkostemps_wrapper (char *tmpl, int suffixlen)
+{
+  return mkostemps (tmpl, suffixlen, O_BINARY);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/mkostemps-wrapper.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,36 @@
+/*
+
+Copyright (C) 2016-2018 John W. Eaton
+
+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_mkostemps_wrapper_h)
+#define octave_mkostemps_wrapper_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern int octave_mkostemps_wrapper (char *tmpl, int suffixlen);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/liboctave/wrappers/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/wrappers/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -11,9 +11,11 @@
   %reldir%/getopt-wrapper.h \
   %reldir%/glob-wrappers.h \
   %reldir%/hash-wrappers.h \
+  %reldir%/iconv-wrappers.h \
   %reldir%/localcharset-wrapper.h \
   %reldir%/math-wrappers.h \
   %reldir%/mkostemp-wrapper.h \
+  %reldir%/mkostemps-wrapper.h \
   %reldir%/nanosleep-wrapper.h \
   %reldir%/nproc-wrapper.h \
   %reldir%/octave-popen2.h \
@@ -28,8 +30,11 @@
   %reldir%/time-wrappers.h \
   %reldir%/tmpfile-wrapper.h \
   %reldir%/uname-wrapper.h \
+  %reldir%/unicase-wrappers.h \
   %reldir%/uniconv-wrappers.h \
+  %reldir%/unictype-wrappers.h \
   %reldir%/unistd-wrappers.h \
+  %reldir%/unistr-wrappers.h \
   %reldir%/unsetenv-wrapper.h \
   %reldir%/vasprintf-wrapper.h \
   %reldir%/wait-for-input.h \
@@ -48,9 +53,11 @@
   %reldir%/getopt-wrapper.c \
   %reldir%/glob-wrappers.c \
   %reldir%/hash-wrappers.c \
+  %reldir%/iconv-wrappers.c \
   %reldir%/localcharset-wrapper.c \
   %reldir%/math-wrappers.c \
   %reldir%/mkostemp-wrapper.c \
+  %reldir%/mkostemps-wrapper.c \
   %reldir%/nanosleep-wrapper.c \
   %reldir%/nproc-wrapper.c \
   %reldir%/octave-popen2.c \
@@ -65,8 +72,11 @@
   %reldir%/time-wrappers.c \
   %reldir%/tmpfile-wrapper.c \
   %reldir%/uname-wrapper.c \
+  %reldir%/unicase-wrappers.c \
   %reldir%/uniconv-wrappers.c \
+  %reldir%/unictype-wrappers.c \
   %reldir%/unistd-wrappers.c \
+  %reldir%/unistr-wrappers.c \
   %reldir%/unsetenv-wrapper.c \
   %reldir%/vasprintf-wrapper.c \
   %reldir%/wait-for-input.c \
@@ -80,6 +90,4 @@
 %canon_reldir%_libwrappers_la_CPPFLAGS = \
   -Ilibgnu -I$(srcdir)/libgnu
 
-%canon_reldir%_libwrappers_la_CFLAGS = $(liboctave_liboctave_la_CFLAGS)
-
 liboctave_liboctave_la_LIBADD += %reldir%/libwrappers.la
--- a/liboctave/wrappers/stat-wrappers.c	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/wrappers/stat-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -35,11 +35,25 @@
 #include <sys/stat.h>
 
 #include "stat-wrappers.h"
+#include "uniconv-wrappers.h"
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#endif
 
 int
 octave_mkdir_wrapper (const char *name, mode_t mode)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wname = u8_to_wchar (name);
+  int status = _wmkdir (wname);
+  free ((void *) wname);
+  octave_unused_parameter (mode);
+  return status;
+#else
   return mkdir (name, mode);
+#endif
 }
 
 int
@@ -100,7 +114,13 @@
 {
   struct stat buf;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wfname = u8_to_wchar (fname);
+  int status = _wstati64 (wfname, &buf);
+  free ((void *) wfname);
+#else
   int status = stat (fname, &buf);
+#endif
 
   assign_stat_fields (&buf, mode, ino, dev, nlink, uid, gid, size,
                       atime, mtime, ctime, rdev, blksize, blocks);
@@ -117,7 +137,14 @@
 {
   struct stat buf;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+  // Windows doesn't have an lstat. Use stat instead
+  wchar_t *wlname = u8_to_wchar (lname);
+  int status = _wstati64 (wlname, &buf);
+  free ((void *) wlname);
+#else
   int status = lstat (lname, &buf);
+#endif
 
   assign_stat_fields (&buf, mode, ino, dev, nlink, uid, gid, size,
                       atime, mtime, ctime, rdev, blksize, blocks);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unicase-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,45 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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 "unicase.h"
+
+#include "unicase-wrappers.h"
+
+uint8_t *
+octave_u8_tolower_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp)
+{
+  return u8_tolower (s, n, iso639_language, NULL, resultbuf, lengthp);
+}
+
+uint8_t *
+octave_u8_toupper_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp)
+{
+  return u8_toupper (s, n, iso639_language, NULL, resultbuf, lengthp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unicase-wrappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,44 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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_unicase_wrappers_h)
+#define octave_unicase_wrappers_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern 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 *
+octave_u8_toupper_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/liboctave/wrappers/uniconv-wrappers.c	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -29,6 +29,10 @@
 #  include "config.h"
 #endif
 
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
 #include "uniconv.h"
 
 #include "uniconv-wrappers.h"
@@ -41,10 +45,54 @@
                                 src, srclen, NULL, NULL, lengthp);
 }
 
-extern char *
+char *
 octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
                             size_t srclen, size_t *lengthp)
 {
   return u8_conv_to_encoding (tocode, iconveh_question_mark,
                               src, srclen, NULL, NULL, lengthp);
 }
+
+char *
+u8_from_wchar (const wchar_t *wc)
+{
+  // Convert wide char array to multibyte UTF-8 char array
+  // The memory at the returned pointer must be freed after use.
+
+  size_t srclen = wcslen (wc) * sizeof (wchar_t);
+  const char *src = (const char *) wc;
+
+  size_t length = 0;
+  uint8_t *mbchar = u8_conv_from_encoding ("wchar_t", iconveh_question_mark,
+                                           src, srclen, NULL, NULL, &length);
+
+  // result might not be 0 terminated
+  char *retval = malloc (length + 1);
+  memcpy (retval, mbchar, length);
+  free ((void *) mbchar);
+  retval[length] = 0; // 0 terminate string
+
+  return retval;
+}
+
+wchar_t *
+u8_to_wchar (const char *u8)
+{
+  // Convert multibyte UTF-8 char array to wide char array
+  // The memory at the returned pointer must be freed after use.
+
+  size_t srclen = strlen (u8);
+  const uint8_t *src = (const uint8_t *) u8;
+
+  size_t length = 0;
+
+  char *wchar = u8_conv_to_encoding ("wchar_t", iconveh_question_mark,
+                                     src, srclen, NULL, NULL, &length);
+  // result might not be 0 terminated
+  wchar_t *retval = malloc (length + 1 * sizeof (wchar_t));
+  memcpy (retval, wchar, length);
+  free ((void *) wchar);
+  retval[length / sizeof (wchar_t)] = 0; // 0 terminate string
+
+  return retval;
+}
--- a/liboctave/wrappers/uniconv-wrappers.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -46,6 +46,12 @@
 octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
                             size_t srclen, size_t *lengthp);
 
+extern char *
+u8_from_wchar (const wchar_t *wc);
+
+extern wchar_t *
+u8_to_wchar (const char *u8_char);
+
 #if defined __cplusplus
 }
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unictype-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,101 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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 "unictype.h"
+
+#include "unictype-wrappers.h"
+
+bool
+octave_uc_is_alnum_wrapper (ucs4_t uc)
+{
+  return uc_is_alnum (uc);
+}
+
+bool
+octave_uc_is_alpha_wrapper (ucs4_t uc)
+{
+  return uc_is_alpha (uc);
+}
+
+bool
+octave_uc_is_blank_wrapper (ucs4_t uc)
+{
+  return uc_is_blank (uc);
+}
+
+bool
+octave_uc_is_cntrl_wrapper (ucs4_t uc)
+{
+  return uc_is_cntrl (uc);
+}
+
+bool
+octave_uc_is_digit_wrapper (ucs4_t uc)
+{
+  return uc_is_digit (uc);
+}
+
+bool
+octave_uc_is_graph_wrapper (ucs4_t uc)
+{
+  return uc_is_graph (uc);
+}
+
+bool
+octave_uc_is_lower_wrapper (ucs4_t uc)
+{
+  return uc_is_lower (uc);
+}
+
+bool
+octave_uc_is_print_wrapper (ucs4_t uc)
+{
+  return uc_is_print (uc);
+}
+
+bool
+octave_uc_is_punct_wrapper (ucs4_t uc)
+{
+  return uc_is_punct (uc);
+}
+
+bool
+octave_uc_is_space_wrapper (ucs4_t uc)
+{
+  return uc_is_space (uc);
+}
+
+bool
+octave_uc_is_upper_wrapper (ucs4_t uc)
+{
+  return uc_is_upper (uc);
+}
+
+bool
+octave_uc_is_xdigit_wrapper (ucs4_t uc)
+{
+  return uc_is_xdigit (uc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unictype-wrappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,72 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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_unictype_wrappers_h)
+#define octave_unictype_wrappers_h 1
+
+typedef uint32_t ucs4_t;
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern bool
+octave_uc_is_alnum_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_alpha_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_blank_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_cntrl_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_digit_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_graph_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_lower_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_print_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_punct_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_space_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_upper_wrapper (ucs4_t uc);
+
+extern bool
+octave_uc_is_xdigit_wrapper (ucs4_t uc);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/liboctave/wrappers/unistd-wrappers.c	Tue Dec 04 10:12:41 2018 -0800
+++ b/liboctave/wrappers/unistd-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -31,8 +31,6 @@
 
 #include <stdio.h>
 
-#include <stdio.h>
-
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -40,6 +38,12 @@
 #  include <process.h>
 #endif
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#endif
+
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
 int
@@ -75,7 +79,14 @@
 int
 octave_chdir_wrapper (const char *nm)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wnm = u8_to_wchar (nm);
+  int status = _wchdir (wnm);
+  free ((void *) wnm);
+  return status;
+#else
   return chdir (nm);
+#endif
 }
 
 int
@@ -281,7 +292,28 @@
 char *
 octave_getcwd_wrapper (char *nm, size_t len)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *tmp = _wgetcwd (NULL, 0);
+  char *retval = NULL;
+
+  if (! tmp)
+    return retval;
+
+  retval = u8_from_wchar (tmp);
+  if (! nm)
+    return retval;
+  else
+    {
+      if (strlen (retval) > len)
+        return NULL;
+
+      memcpy (nm, retval, len);
+      free (retval);
+      return nm;
+    }
+#else
   return getcwd (nm, len);
+#endif
 }
 
 gid_t
@@ -381,7 +413,14 @@
 int
 octave_rmdir_wrapper (const char *nm)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wnm = u8_to_wchar (nm);
+  int status = _wrmdir (wnm);
+  free ((void *) wnm);
+  return status;
+#else
   return rmdir (nm);
+#endif
 }
 
 pid_t
@@ -415,7 +454,14 @@
 int
 octave_unlink_wrapper (const char *nm)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wnm = u8_to_wchar (nm);
+  int status = _wunlink (wnm);
+  free ((void *) wnm);
+  return status;
+#else
   return unlink (nm);
+#endif
 }
 
 pid_t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unistr-wrappers.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,48 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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 "unistr.h"
+
+#include "unistr-wrappers.h"
+
+int
+octave_u8_strmblen_wrapper (const uint8_t *src)
+{
+  return u8_strmblen (src);
+}
+
+int
+octave_u8_strmbtouc_wrapper (uint32_t *puc, const uint8_t *src)
+{
+  return u8_strmbtouc (puc, src);
+}
+
+uint32_t *
+octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
+                          uint32_t *result_buf, size_t *lengthp)
+{
+  return u8_to_u32 (src, src_len, result_buf, lengthp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unistr-wrappers.h	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,44 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+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_unistr_wrappers_h)
+#define octave_unistr_wrappers_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern int
+octave_u8_strmblen_wrapper (const uint8_t *src);
+
+extern int
+octave_u8_strmbtouc_wrapper (uint32_t *puc, const uint8_t *src);
+
+extern uint32_t *
+octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
+                          uint32_t *result_buf, size_t *lengthp);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/m4/acinclude.m4	Tue Dec 04 10:12:41 2018 -0800
+++ b/m4/acinclude.m4	Thu Dec 20 17:18:56 2018 -0500
@@ -666,6 +666,36 @@
   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
+AC_DEFUN([OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO], [
+  AC_CACHE_CHECK([for QScreen::devicePixelRatio in <QScreen>],
+    [octave_cv_func_qscreen_devicepixelratio],
+    [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 <QApplication>
+        #include <QScreen>
+        ]], [[
+        QScreen *screen = QApplication::primaryScreen ();
+        qreal ratio = screen->devicePixelRatio ();
+        ]])],
+      octave_cv_func_qscreen_devicepixelratio=yes,
+      octave_cv_func_qscreen_devicepixelratio=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    CXXFLAGS="$ac_octave_save_CXXFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_func_qscreen_devicepixelratio = yes; then
+    AC_DEFINE(HAVE_QSCREEN_DEVICEPIXELRATIO, 1,
+      [Define to 1 if you have the `QScreen::devicePixelRatio' member function.])
+  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
@@ -1846,7 +1876,7 @@
   ac_octave_save_CXXFLAGS="$CXXFLAGS"
   CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
   CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-  AC_CHECK_HEADERS([QOpenGLWidget QGLWidget])
+  AC_CHECK_HEADERS([QOpenGLWidget QGLWidget QGLFunctions_1_1])
   AC_CACHE_CHECK([whether Qt works with OpenGL and GLU],
     [octave_cv_qt_opengl_ok],
     [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -1944,10 +1974,12 @@
   ## Check for Qt libraries
   case "$qt_version" in
     4)
-      QT_MODULES="QtCore QtGui QtNetwork QtOpenGL QtHelp"
+      QT_OPENGL_MODULE="QtOpenGL"
+      QT_MODULES="QtCore QtGui QtNetwork QtHelp QtXml"
     ;;
     5)
-      QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5OpenGL Qt5PrintSupport Qt5Help"
+      QT_OPENGL_MODULE="Qt5OpenGL"
+      QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5PrintSupport Qt5Help Qt5Xml"
     ;;
     *)
       AC_MSG_ERROR([Unrecognized Qt version $qt_version])
@@ -1977,6 +2009,7 @@
     QT_CPPFLAGS="$($PKG_CONFIG --cflags-only-I $QT_MODULES | $SED -e 's/^ *$//')"
     QT_LDFLAGS="$($PKG_CONFIG --libs-only-L $QT_MODULES | $SED -e 's/^ *$//')"
     QT_LIBS="$($PKG_CONFIG --libs-only-l $QT_MODULES | $SED -e 's/^ *$//')"
+    QT_OPENGL_LIBS="$($PKG_CONFIG --libs-only-l $QT_OPENGL_MODULE | $SED -e 's/^ *$//')"
 
     case $host_os in
       *darwin*)
@@ -1984,6 +2017,7 @@
         if test -z "$QT_LIBS"; then
           QT_LDFLAGS="`$PKG_CONFIG --libs-only-other $QT_MODULES | tr ' ' '\n' | $GREP -e '-F' | uniq | tr '\n' ' '`"
           QT_LIBS="`$PKG_CONFIG --libs-only-other $QT_MODULES | tr ' ' '\n' | $GREP -v -e '-F' | uniq | tr '\n' ' '`"
+          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],
@@ -2107,6 +2141,7 @@
     OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT
     OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS
     OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS
+    OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO
     OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE
     OCTAVE_CHECK_FUNC_QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT
     OCTAVE_CHECK_MEMBER_QFONT_FORCE_INTEGER_METRICS
@@ -2138,6 +2173,7 @@
   AC_SUBST(QT_CPPFLAGS)
   AC_SUBST(QT_LDFLAGS)
   AC_SUBST(QT_LIBS)
+  AC_SUBST(QT_OPENGL_LIBS)
 ])
 dnl
 dnl Check if the default Fortran INTEGER is 64 bits wide.
@@ -3104,72 +3140,18 @@
       ])
   fi
 
-  AC_SUBST(BISON_API_PREFIX_DECL_STYLE, $octave_cv_bison_api_prefix_decl_style)
-
-  if test -z "$octave_cv_bison_api_prefix_decl_style"; then
+  if test -z "$octave_cv_bison_api_prefix_decl_style" \
+    || test "$octave_cv_bison_api_prefix_decl_style" != "api brace"; then
     tmp_have_bison=no
     warn_bison_api_prefix_decl_style="
 
 I wasn't able to find a suitable style for declaring the api prefix
-in a bison input file so I'm disabling bison.
+in a bison input file so I'm disabling bison.  We expect bison to
+understand the '%define api.prefix { PREFIX }' syntax.
 "
     OCTAVE_CONFIGURE_WARNING([warn_bison_api_prefix_decl_style])
   fi
 
-  if test $tmp_have_bison = yes; then
-    AC_CACHE_CHECK([syntax of bison push/pull declaration],
-                   [octave_cv_bison_push_pull_decl_style], [
-      style="dash underscore"
-      quote="noquote quote"
-      for s in $style; do
-        for q in $quote; do
-          if test $s = "dash"; then
-            def="%define api.push-pull"
-          else
-            def="%define api.push_pull"
-          fi
-          if test $q = "quote"; then
-            def="$def \"both\""
-          else
-            def="$def both"
-          fi
-          cat << EOF > conftest.yy
-$def
-%start input
-%%
-input:;
-%%
-EOF
-          octave_bison_output=`$YACC conftest.yy 2>&1`
-          ac_status=$?
-          if test $ac_status -eq 0 && test -z "$octave_bison_output"; then
-            if test $q = noquote; then
-              q=
-            fi
-            octave_cv_bison_push_pull_decl_style="$s $q"
-            break
-          fi
-        done
-        if test -n "$octave_cv_bison_push_pull_decl_style"; then
-          break
-        fi
-      done
-      rm -f conftest.yy y.tab.h y.tab.c
-      ])
-  fi
-
-  AC_SUBST(BISON_PUSH_PULL_DECL_STYLE, $octave_cv_bison_push_pull_decl_style)
-
-  if test -z "$octave_cv_bison_push_pull_decl_style"; then
-    tmp_have_bison=no
-    warn_bison_push_pull_decl_style="
-
-I wasn't able to find a suitable style for declaring a push-pull
-parser in a bison input file so I'm disabling bison.
-"
-    OCTAVE_CONFIGURE_WARNING([warn_bison_push_pull_decl_style])
-  fi
-
   if test $tmp_have_bison = no; then
     YACC='${top_srcdir}/build-aux/missing bison'
     warn_bison="
--- a/m4/pkg.m4	Tue Dec 04 10:12:41 2018 -0800
+++ b/m4/pkg.m4	Thu Dec 20 17:18:56 2018 -0500
@@ -1,32 +1,68 @@
-# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
-#
-# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
-#
-# 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
-# the Free Software Foundation; either version 2 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
-# 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
+# pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+# serial 12 (pkg-config-0.29.2)
+
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
 
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29.2])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
 AC_DEFUN([PKG_PROG_PKG_CONFIG],
 [m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
 if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
 	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
 fi
@@ -39,48 +75,49 @@
 		AC_MSG_RESULT([no])
 		PKG_CONFIG=""
 	fi
-		
 fi[]dnl
-])# PKG_PROG_PKG_CONFIG
+])dnl PKG_PROG_PKG_CONFIG
 
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists.  Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-#
-# Similar to PKG_CHECK_MODULES, make sure that the first instance of
-# this or PKG_CHECK_MODULES is called, or make sure to call
-# PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
 AC_DEFUN([PKG_CHECK_EXISTS],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 if test -n "$PKG_CONFIG" && \
     AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
-  m4_ifval([$2], [$2], [:])
+  m4_default([$2], [:])
 m4_ifvaln([$3], [else
   $3])dnl
 fi])
 
-
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
 m4_define([_PKG_CONFIG],
-[if test -n "$PKG_CONFIG"; then
-    if test -n "$$1"; then
-        pkg_cv_[]$1="$$1"
-    else
-        PKG_CHECK_EXISTS([$3],
-                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
-			 [pkg_failed=yes])
-    fi
-else
-	pkg_failed=untried
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes ],
+		     [pkg_failed=yes])
+ else
+    pkg_failed=untried
 fi[]dnl
-])# _PKG_CONFIG
+])dnl _PKG_CONFIG
 
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
 AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -88,26 +125,24 @@
 else
         _pkg_short_errors_supported=no
 fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
 
 
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 AC_DEFUN([PKG_CHECK_MODULES],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
 AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
 
 pkg_failed=no
-AC_MSG_CHECKING([for $1])
+AC_MSG_CHECKING([for $2])
 
 _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
 _PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -117,16 +152,17 @@
 See the pkg-config man page for more details.])
 
 if test $pkg_failed = yes; then
+        AC_MSG_RESULT([no])
         _PKG_SHORT_ERRORS_SUPPORTED
         if test $_pkg_short_errors_supported = yes; then
-	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
         else
-	        $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
 
-	ifelse([$4], , [AC_MSG_ERROR(dnl
+	m4_default([$4], [AC_MSG_ERROR(
 [Package requirements ($2) were not met:
 
 $$1_PKG_ERRORS
@@ -134,24 +170,106 @@
 Consider adjusting the PKG_CONFIG_PATH environment variable if you
 installed software in a non-standard prefix.
 
-_PKG_TEXT
-])],
-		[AC_MSG_RESULT([no])
-                $4])
+_PKG_TEXT])[]dnl
+        ])
 elif test $pkg_failed = untried; then
-	ifelse([$4], , [AC_MSG_FAILURE(dnl
+        AC_MSG_RESULT([no])
+	m4_default([$4], [AC_MSG_FAILURE(
 [The pkg-config script could not be found or is too old.  Make sure it
 is in your PATH or set the PKG_CONFIG environment variable to the full
 path to pkg-config.
 
 _PKG_TEXT
 
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
-		[$4])
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+        ])
 else
 	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
 	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
         AC_MSG_RESULT([yes])
-	ifelse([$3], , :, [$3])
+	$3
 fi[]dnl
-])# PKG_CHECK_MODULES
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
--- a/oct-conf-post.in.h	Tue Dec 04 10:12:41 2018 -0800
+++ b/oct-conf-post.in.h	Thu Dec 20 17:18:56 2018 -0500
@@ -50,6 +50,28 @@
 #  define OCTAVE_UNUSED
 #endif
 
+#if defined (__MINGW32__)
+  /* MinGW requires special handling due to different format specifiers
+   * on different platforms.  The macro __MINGW_PRINTF_FORMAT maps to
+   * either gnu_printf or ms_printf depending on where we are compiling
+   * to avoid warnings on format specifiers that are legal.
+   * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331349  */
+#  define OCTAVE_FORMAT_PRINTF(stringIndex, firstToCheck) \
+     __attribute__ ((format (__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck)))
+
+#  define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#elif defined (__GNUC__)
+   /* The following attributes are used with gcc and clang compilers.  */
+#  define OCTAVE_FORMAT_PRINTF(index, first) \
+     __attribute__ ((__format__(printf, index, first)))
+
+#  define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#else
+#  define OCTAVE_FORMAT_PRINTF(index, first)
+
+/* #  undef HAVE_OCTAVE_FORMAT_PRINTF_ATTR */
+#endif
+
 #if ! defined (OCTAVE_FALLTHROUGH)
 #  if defined (__cplusplus) && __cplusplus > 201402L
 #    define OCTAVE_FALLTHROUGH [[fallthrough]]
@@ -201,6 +223,13 @@
 #endif
 
 typedef OCTAVE_IDX_TYPE octave_idx_type;
+
+#if defined (OCTAVE_ENABLE_64)
+#  define OCTAVE_IDX_TYPE_FORMAT PRId64
+#else
+#  define OCTAVE_IDX_TYPE_FORMAT PRId32
+#endif
+
 typedef OCTAVE_F77_INT_TYPE octave_f77_int_type;
 
 #define OCTAVE_HAVE_F77_INT_TYPE 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/octave.doap	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:foaf="http://xmlns.com/foaf/0.1/"
+         xmlns="http://usefulinc.com/ns/doap#">
+
+  <name xml:lang="en">GNU Octave</name>
+  <shortname>octave</shortname>
+
+  <shortdesc xml:lang="en">Interactive programming environment for numerical computations</shortdesc>
+
+  <homepage rdf:resource="https://www.octave.org" />
+  <license rdf:resource="https://www.gnu.org/licenses/gpl-3.0.txt" />
+  <bug-database rdf:resource="https://savannah.gnu.org/bugs/?group=octave" />
+  <download-page rdf:resource="https://ftp.gnu.org/gnu/octave/" />
+  <mailing-list rdf:resource="https://lists.gnu.org/mailman/listinfo/help-octave" />
+  <wiki rdf:resource="https://wiki.octave.org" />
+
+  <programming-language>C++</programming-language>
+
+  <maintainer>
+    <foaf:Person>
+      <foaf:name>John W. Eaton</foaf:name>
+      <foaf:mbox rdf:resource="mailto:jwe@octave.org" />
+    </foaf:Person>
+  </maintainer>
+
+  <repository>
+    <HgRepository>
+      <browse rdf:resource="https://hg.savannah.gnu.org/hgweb/octave"/>
+      <location rdf:resource="https://hg.savannah.gnu.org/hgweb/octave"/>
+    </HgRepository>
+  </repository>
+
+</Project>
--- a/run-octave.in	Tue Dec 04 10:12:41 2018 -0800
+++ b/run-octave.in	Thu Dec 20 17:18:56 2018 -0500
@@ -35,6 +35,7 @@
 d2="$builddir/scripts"
 d3="$builddir/libinterp"
 d4="$top_srcdir/examples/data"
+d5="$builddir/libgui/graphics"
 
 d1_list=`$FIND "$d1" -type d -a ! \( \( -name private -o -name '@*' -o -name '+*' -o -name '.deps' -o -name '.libs' \) -a -prune \) -exec echo '{}' ';' | $SED 's/$/:/'`
 d2_list=`$FIND "$d2" -type d -a ! \( \( -name private -o -name '@*' -o -name '+*' -o -name '.deps' -o -name '.libs' \) -a -prune \) -exec echo '{}' ';' | $SED 's/$/:/'`
@@ -48,7 +49,7 @@
 
 octave_executable="$builddir/src/octave"
 
-LOADPATH="$d1_path:$d2_path:$d3_path:$d4_path"
+LOADPATH="$d1_path:$d2_path:$d3_path:$d4_path:$d5"
 IMAGEPATH=".:$top_srcdir/scripts/image"
 DOCFILE="$builddir/doc/interpreter/doc-cache"
 BUILT_IN_DOCSTRINGS_FILE="$builddir/libinterp/DOCSTRINGS"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+lang/makeUniqueStrings.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,231 @@
+## Copyright (C) 2017-2018 Guillaume Flandin
+##
+## 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{uniqstr} =} matlab.lang.makeUniqueStrings (@var{str})
+## @deftypefnx {} {@var{uniqstr} =} matlab.lang.makeUniqueStrings (@var{str}, @var{ex})
+## @deftypefnx {} {@var{uniqstr} =} matlab.lang.makeUniqueStrings (@var{str}, @var{ex}, @var{maxlength})
+## @deftypefnx {} {[@var{uniqstr}, @var{ismodified}] =} matlab.lang.makeUniqueStrings (@dots{})
+##
+## Construct a list of unique strings from a list of strings.
+##
+## The input @var{str} must be a string or a cell array of strings.
+## The output @var{uniqstr} will be of the same type.
+##
+## The algorithm makes two strings unique by appending an underscore
+## (@qcode{"_"} and a numeric count to the second string.
+##
+## If @var{ex} is a string or a cell array of strings, @var{uniqstr} will
+## contain elements that are unique between themselves and with respect to
+## @var{ex}.
+##
+## If @var{ex} is an index array or a logical array for @var{str} then it
+## selects the subset of @var{str} that are made unique.  Unselected elements
+## are not modified.
+##
+## The optional input @var{maxlength} specifies the maximum length of any
+## string in @var{uniqstr}.  If an input string cannot be made unique without
+## exceeding @var{maxlength} an error is emitted.
+## 
+## The optional output @var{ismodified} is a logical array indicating whether
+## each element in @var{str} was modified to make it unique.
+##
+## @seealso{unique, matlab.lang.makeValidName}
+## @end deftypefn
+
+function [uniqstr, ismodified] = makeUniqueStrings (str, ex = {}, maxlength = Inf)
+
+  if (nargin == 0 || nargout > 3)
+    print_usage ();
+  endif
+
+  ##  Validate first input
+  if (! ischar (str) && ! iscellstr (str))
+    error ("makeUniqueStrings: STR must be a string or cellstr");
+  endif
+
+  convert2char = ischar (str);
+  uniqstr = cellstr (str);
+  sz = size (uniqstr);
+  uniqstr = uniqstr(:)';
+
+  ## Initialize array of strings to exclude
+  excludedstrings = {};
+
+  ## Validate optional exclusion list input
+  if (nargin > 1)
+    if (ischar (ex) || iscellstr (ex))
+      excludedstrings = cellstr (ex);
+    elseif (islogical (ex))
+      if (numel (ex) != numel (uniqstr))
+        error ("makeUniqueStrings: STR and EX logical array must have the same length");
+      endif
+      excludedstrings = uniqstr(! ex);
+      uniqstr = uniqstr(ex);
+    elseif (isnumeric (ex))
+      if (! isindex (ex, numel (uniqstr)))
+        error ("makeUniqueStrings: invalid array of indices EX");
+      endif
+      excludedstrings = uniqstr(setdiff (1:numel (uniqstr), ex));
+      uniqstr = uniqstr(ex);
+    else
+      error ("makeUniqueStrings: invalid input");
+    endif
+    excludedstrings = excludedstrings(:)';
+  endif
+
+  ## Validate optional maxlength input
+  if (nargin > 2)
+    if (! isindex (maxlength))
+      error ("makeUniqueStrings: MAXLENGTH must be a positive integer");
+    endif
+  endif
+  chk_length = ! isinf (maxlength);
+
+  ismodified = false (size (uniqstr));
+  if (chk_length)
+    ## Truncate output strings
+    ismodified = (cellfun (@length, uniqstr) > maxlength);
+    uniqstr(ismodified) = cellindexmat (uniqstr(ismodified), 1:maxlength);
+  endif
+
+  ## Make unique strings
+  ## FIXME: lots of call to ismember are slow.
+  [~, I, J] = unique (uniqstr, "first");
+  for i = 1:numel (I)
+    R = ! ismember (uniqstr{I(i)}, excludedstrings);
+    K = find (J == J(I(i)));
+    n = 1 + ceil (log10 (numel (K)));
+
+    if (! chk_length)
+      sub = uniqstr{K(1)};
+    else
+      if (length (uniqstr{K(1)}) + n > maxlength)
+        if (n >= maxlength)
+          error ("makeUniqueStrings: cannot create unique elements within MAXLENGTH");
+        endif
+        sub = uniqstr{K(1)}(1:maxlength-n);
+      else
+        sub = uniqstr{K(1)};
+      endif
+    endif
+
+    for k = (1 + R):numel (K)
+      while (true)
+        N = k - R;
+        proposal = [sub sprintf("_%d", N)];
+        if (! ismember (proposal, [excludedstrings, uniqstr(I(i+1:end))]))
+          uniqstr{K(k)} = proposal;
+          break;
+        else
+          R--;  # i.e. increments N
+        endif
+      endwhile
+      ismodified(K(k)) |= true;
+    endfor
+  endfor
+
+  ## Return outputs with correct type and size
+  if (convert2char)
+    uniqstr = char (uniqstr);
+    if (isempty (uniqstr))
+      uniqstr = char ();
+    endif
+  else
+    if (isnumeric (ex) || islogical (ex))
+      tmp = uniqstr;
+      uniqstr = cell (1, prod (sz));
+      uniqstr(ex) = tmp;
+      if (isnumeric (ex))
+        uniqstr(setdiff (1:prod (sz), ex)) = excludedstrings;
+      else
+        uniqstr(! ex) = excludedstrings;
+      endif
+      tmp = ismodified;
+      ismodified = false (sz);
+      ismodified(ex) = tmp;
+    endif
+    uniqstr = reshape (uniqstr, sz);
+  endif
+
+endfunction
+
+
+## Test first input
+%!test
+%! assert (matlab.lang.makeUniqueStrings ("a"), "a");
+%! assert (matlab.lang.makeUniqueStrings ({"a","b","c"}), {"a","b","c"});
+%! assert (matlab.lang.makeUniqueStrings (''), '');
+%! assert (matlab.lang.makeUniqueStrings ({}), {});
+
+## Test exclusion list
+%!test
+%! str = {"jwe", "Marco", "Rik", "jwe", "Kai", "jwe", "Torsten"};
+%! uniqstr = matlab.lang.makeUniqueStrings (str);
+%! assert (uniqstr,
+%!         {"jwe", "Marco", "Rik", "jwe_1", "Kai", "jwe_2", "Torsten"});
+%! uniqstr = matlab.lang.makeUniqueStrings (str, "Rik");
+%! assert (uniqstr,
+%!         {"jwe", "Marco", "Rik_1", "jwe_1", "Kai", "jwe_2", "Torsten"});
+%! [uniqstr, m] = matlab.lang.makeUniqueStrings (str, {"Kai", "Rik"});
+%! assert (uniqstr,
+%!         {"jwe", "Marco", "Rik_1", "jwe_1", "Kai_1", "jwe_2", "Torsten"});
+%! assert (m, logical ([0 0 1 1 1 1 0]));
+
+## Test index array
+%!test
+%! str = {"a", "a", "a", "b", "a", "b"};
+%! uniqstr = matlab.lang.makeUniqueStrings (str, 1:4);
+%! assert (uniqstr, {"a_1", "a_2", "a_3", "b_1", "a", "b"});
+%! str(end+1) = "a";
+%! [uniqstr, m] = matlab.lang.makeUniqueStrings (str, 1:4);
+%! assert (uniqstr, {"a_1", "a_2", "a_3", "b_1", "a", "b", "a"});
+%! assert (m ,logical ([1 1 1 1 0 0 0]));
+
+## Test logical array
+%!test
+%! str = {"a", "a", "a", "b", "a", "b"};
+%! [uniqstr, m] = matlab.lang.makeUniqueStrings (str, logical ([1 1 1 1 0 0]));
+%! assert (uniqstr, {"a_1", "a_2", "a_3", "b_1", "a", "b"});
+%! assert (m, logical ([1 1 1 1 0 0]));
+
+## Test maxlength
+%!test
+%! str = {"maxlength", "maxlength", "maxlength", "maxlength"};
+%! [uniqstr, m] = matlab.lang.makeUniqueStrings (str, 1:3, 5);
+%! assert (uniqstr, {"maxle", "max_1", "max_2", "maxlength"});
+%! assert (m, logical ([1 1 1 0]));
+%!error <cannot create unique elements within MAXLENGTH>
+%! matlab.lang.makeUniqueStrings (repmat ({"a"}, 1, 10), {}, 2);
+
+%!test
+%! assert (matlab.lang.makeUniqueStrings ("a", {"a"}), "a_1");
+%! assert (matlab.lang.makeUniqueStrings ("a", {"a","a_1"}), "a_2");
+%! uniqstr = matlab.lang.makeUniqueStrings ({"a","a","a","a_6","a"},
+%!                                          {"a","a_3"});
+%! 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 <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]);
+%!error <invalid array of indices EX> matlab.lang.makeUniqueStrings ("a", 2)
+%!error <MAXLENGTH must be a positive integer>
+%! matlab.lang.makeUniqueStrings ("a", {}, pi);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+lang/makeValidName.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,226 @@
+## Copyright (C) 2017-2018 Guillaume Flandin
+##
+## 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{varname} =} matlab.lang.makeValidName (@var{str})
+## @deftypefnx {} {@var{varname} =} matlab.lang.makeValidName (@dots{}, @qcode{"ReplacementStyle"}, @var{rs})
+## @deftypefnx {} {@var{varname} =} matlab.lang.makeValidName (@dots{}, @qcode{"Prefix"}, @var{pfx})
+## @deftypefnx {} {[@var{varname}, @var{ismodified}] =} matlab.lang.makeValidName (@dots{})
+##
+## Create valid variable name @var{varname} from @var{str}.
+##
+## The input @var{str} must be a string or a cell array of strings.
+## The output @var{varname} will be of the same type.
+##
+## A valid variable name is a sequence of letters, digits, and underscores that
+## does not begin with a digit.
+##
+## The @qcode{"ReplacementStyle"} option specifies how invalid characters
+## are handled.  Acceptable values are
+##
+## @table @asis
+## @item @qcode{"underscore"} (default)
+## Replace all invalid characters with an underscore (@qcode{"_"}).
+##
+## @item @qcode{"delete"}
+## Remove any invalid character.
+##
+## @item @qcode{"hex"}
+## Replace all invalid characters with their hexadecimal representation.
+## @end table
+##
+## Whitespace characters are always removed @strong{prior} to the application
+## of the @qcode{"ReplacementStyle"}.  Lowercase letters following a whitespace
+## will be changed to uppercase.
+##
+## The @qcode{"Prefix"} option specifies the string @var{pfx} to add as a
+## prefix to the input if it begins with a digit.  @var{pfx} must be a valid
+## variable name itself.  The default prefix is @qcode{"x"}.
+##
+## The optional output @var{ismodified} is a logical array indicating whether
+## the respective element in @var{str} was a valid name or not.
+##
+## @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
+
+  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
+
+endfunction
+
+
+## Test char vector input
+%!test
+%! varname = matlab.lang.makeValidName ("octave");
+%! assert (varname, "octave");
+
+## Test cellstr input
+%!test
+%! varname = matlab.lang.makeValidName ({"gnu", "octave"});
+%! assert (varname, {"gnu", "octave"});
+
+## Test default flags
+%!test
+%! str = {"Octave", "3d plot", "GNU/Octave", "laplace_*"};
+%! varname = matlab.lang.makeValidName (str);
+%! assert (varname, {"Octave", "x3dPlot", "GNU_Octave", "laplace__"});
+
+## Test ReplacementStyle flag
+%!test
+%! str = {"Octave", "3d plot", "GNU/Octave", "laplace_*"};
+%! varname = matlab.lang.makeValidName (str, "ReplacementStyle", "underscore");
+%! assert (varname, {"Octave", "x3dPlot", "GNU_Octave", "laplace__"});
+%! varname = matlab.lang.makeValidName (str, "ReplacementStyle", "hex");
+%! assert (varname, {"Octave", "x3dPlot", "GNU0x2FOctave", "laplace_0x2A"});
+%! varname = matlab.lang.makeValidName (str, "ReplacementStyle", "delete");
+%! assert (varname, {"Octave", "x3dPlot", "GNUOctave", "laplace_"});
+
+## Test Prefix flag
+%!test
+%! assert (matlab.lang.makeValidName ({"", " "}), {"x", "x"});
+%! str = {"Octave", "3d plot", "GNU/Octave", "laplace_*"};
+%! varname = matlab.lang.makeValidName (str, "prefix", "oct_");
+%! assert (varname, {"Octave", "oct_3dPlot", "GNU_Octave", "laplace__"});
+
+## Test second output
+%!test
+%! str = {"Octave", "3d plot", "GNU/Octave", "laplace_*"};
+%! [varname, modified] = matlab.lang.makeValidName (str);
+%! assert (modified, [false, true, true, true]);
+
+## Test whitespace followed by a lowercase letter
+%!test
+%! varname = matlab.lang.makeValidName ("gnu octave");
+%! assert (varname, "gnuOctave");
+%! varname = matlab.lang.makeValidName (" octave  ");
+%! assert (varname, "octave");
+
+## Check for keywords
+%!test
+%! assert (matlab.lang.makeValidName ("for"), "xFor")
+%! assert (matlab.lang.makeValidName ("For"), "For")
+%!error matlab.lang.makeValidName ("for", "Prefix", "for")
+
+## Test input validation
+%!error 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>
+%! matlab.lang.makeValidName ("a", "ReplacementStyle", 1);
+%!error <invalid "ReplacementStyle" value "foobar">
+%! matlab.lang.makeValidName ("a", "ReplacementStyle", "foobar");
+%!error <invalid "Prefix" value "1_">
+%! matlab.lang.makeValidName ("a", "Prefix", "1_");
+%!error <unknown property "foobar">
+%! matlab.lang.makeValidName ("a", "foobar", 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+lang/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,15 @@
+FCN_FILE_DIRS += scripts/+matlab/+lang
+
+%canon_reldir%_FCN_FILES = \
+  %reldir%/makeUniqueStrings.m \
+  %reldir%/makeValidName.m
+
+%canon_reldir%dir = $(fcnfiledir)/+matlab/+lang
+
+%canon_reldir%_DATA = $(%canon_reldir%_FCN_FILES)
+
+FCN_FILES += $(%canon_reldir%_FCN_FILES)
+
+PKG_ADD_FILES += %reldir%/PKG_ADD
+
+DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
--- a/scripts/deprecated/bitmax.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-## Copyright (C) 2004-2018 John W. Eaton
-##
-## 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{r} =} bitmax (@var{precision})
-##
-## @code{bitmax} is deprecated and will be removed in Octave version 5.
-## Use @code{flintmax (precision) - 1} for the equivalent functionality.
-##
-## Return the largest integer @var{r} that can be represented within a
-## floating point value.
-##
-## The default class is @qcode{"double"}, but @qcode{"single"} is a valid
-## option.  On IEEE 754 compatible systems, @code{bitmax} is
-## @w{@math{2^{53} - 1}} for @qcode{"double"} and @w{@math{2^{24} - 1}} for
-## @qcode{"single"}.
-##
-## @seealso{flintmax, intmax, realmax, realmin}
-## @end deftypefn
-
-## Deprecated in version 4.2
-
-function r = bitmax (precision)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "bitmax is obsolete and will be removed from a future version of Octave, please use flintmax instead");
-  endif
-
-  if (nargin == 0)
-    precision = "double";
-  endif
-  r = flintmax (precision) - 1;
-
-endfunction
--- a/scripts/deprecated/chop.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/deprecated/chop.m	Thu Dec 20 17:18:56 2018 -0500
@@ -82,6 +82,11 @@
 endfunction
 
 
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! chop (0, 1);
+
 %!assert (chop (e, 3), 2.72)
 %!assert (chop (e, 4), 2.718)
 %!assert (chop (e, 4, 5), 2.72)
--- a/scripts/deprecated/isstr.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-## Copyright (C) 2003-2018 John W. Eaton
-##
-## 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 {} {} isstr (@var{a})
-## This function has been deprecated.  Use ischar instead.
-## @end deftypefn
-
-## Author: jwe
-
-## Deprecated in version 3.0
-## Matlab still has this function, so don't remove just yet.
-
-function retval = isstr (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "isstr is obsolete and will be removed from a future version of Octave, please use ischar instead");
-  endif
-
-  retval = ischar (varargin{:});
-
-endfunction
--- a/scripts/deprecated/mahalanobis.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-## Copyright (C) 1996-2018 John W. Eaton
-##
-## 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 {} {} mahalanobis (@var{x}, @var{y})
-##
-## @code{mahalanobis} is deprecated and will be removed in Octave version 5.
-## See the @code{mahal} function in the statistics package from Octave Forge
-## for equivalent functionality.
-##
-## Return the Mahalanobis' D-square distance between the multivariate
-## samples @var{x} and @var{y}.
-##
-## The data @var{x} and @var{y} must have the same number of components
-## (columns), but may have a different number of observations (rows).
-## @end deftypefn
-
-## Author: Friedrich Leisch <leisch@ci.tuwien.ac.at>
-## Created: July 1993
-## Adapted-By: jwe
-
-function retval = mahalanobis (x, y)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "mahalanobis is obsolete and will be removed from a future version of Octave, please use mahal from the statistics package in Octave Forge instead");
-  endif
-
-  if (nargin != 2)
-    print_usage ();
-  endif
-
-  if (   ! (isnumeric (x) || islogical (x))
-      || ! (isnumeric (y) || islogical (y)))
-    error ("mahalanobis: X and Y must be numeric matrices or vectors");
-  endif
-
-  if (ndims (x) != 2 || ndims (y) != 2)
-    error ("mahalanobis: X and Y must be 2-D matrices or vectors");
-  endif
-
-  [xr, xc] = size (x);
-  [yr, yc] = size (y);
-
-  if (xc != yc)
-    error ("mahalanobis: X and Y must have the same number of columns");
-  endif
-
-  if (isinteger (x))
-    x = double (x);
-  endif
-
-  xm = mean (x);
-  ym = mean (y);
-
-  ## Center data by subtracting means
-  x = bsxfun (@minus, x, xm);
-  y = bsxfun (@minus, y, ym);
-
-  w = (x' * x + y' * y) / (xr + yr - 2);
-
-  retval = sumsq ((xm - ym) / chol (w));
-
-endfunction
-
-## Test input validation
-%!error mahalanobis ()
-%!error mahalanobis (1, 2, 3)
-%!error mahalanobis ('A', 'B')
-%!error mahalanobis ([1, 2], ['A', 'B'])
-%!error mahalanobis (ones (2,2,2))
-%!error mahalanobis (ones (2,2), ones (2,2,2))
-%!error mahalanobis (ones (2,2), ones (2,3))
--- a/scripts/deprecated/md5sum.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-## Copyright (C) 2007-2018 David Bateman
-##
-## 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  {} {} md5sum (@var{file})
-## @deftypefnx {} {} md5sum (@var{str}, @var{opt})
-##
-## @code{md5sum} is deprecated and will be removed in Octave version 5.
-## For equivalent functionality replace calls like @code{md5sum (@var{file})}
-## with:
-##
-## @example
-## hash ("md5", fileread (@var{file}))
-## @end example
-##
-## And calls like @code{md5sum (@var{str}, true)} with:
-##
-## @example
-## hash ("md5", @var{str})
-## @end example
-##
-## Calculate the MD5 sum of the file @var{file}.
-##
-## If the second parameter @var{opt} exists and is true, then calculate the MD5
-## sum of the string @var{str}.
-##
-## @seealso{hash, fileread}
-## @end deftypefn
-
-function r = md5sum (str, opt)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "md5sum is obsolete and will be removed from a future version of Octave, please use hash instead");
-  endif
-
-  if (nargin == 1)
-    r = hash ("md5", fileread (str));
-  elseif ((nargin == 2) && isbool (opt) && isscalar (opt) && (opt == true))
-    r = hash ("md5", str);
-  else
-    print_usage ();
-  endif
-
-endfunction
-
-
-%!assert (md5sum ("abc\0", true), "147a664a2ca9410911e61986d3f0d52a")
-
-%!test
-%! tfile = tempname ();
-%! fid = fopen (tfile, "wb");
-%! fwrite (fid, "abc\0");
-%! fclose (fid);
-%! assert (md5sum (tfile), "147a664a2ca9410911e61986d3f0d52a");
-%! unlink (tfile);
-
-%!error md5sum ()
--- a/scripts/deprecated/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/deprecated/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -1,25 +1,14 @@
 FCN_FILE_DIRS += scripts/deprecated
 
 %canon_reldir%_FCN_FILES = \
-  %reldir%/bitmax.m \
   %reldir%/chop.m \
   %reldir%/comma.m \
   %reldir%/desktop.m \
-  %reldir%/isstr.m \
   %reldir%/java2mat.m \
-  %reldir%/mahalanobis.m \
-  %reldir%/md5sum.m \
-  %reldir%/octave_config_info.m \
-  %reldir%/onenormest.m \
   %reldir%/paren.m \
   %reldir%/semicolon.m \
-  %reldir%/setstr.m \
-  %reldir%/sleep.m \
   %reldir%/tmpnam.m \
-  %reldir%/toascii.m \
-  %reldir%/usleep.m \
-  %reldir%/wavread.m \
-  %reldir%/wavwrite.m
+  %reldir%/toascii.m
 
 %canon_reldir%dir = $(fcnfiledir)/deprecated
 
--- a/scripts/deprecated/octave_config_info.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-## Copyright (C) 2016-2018 John W. Eaton
-##
-## 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  {} {} octave_config_info ()
-## @deftypefnx {} {} octave_config_info (@var{option})
-##
-## @code{octave_config_info} is deprecated and will be removed in
-## Octave version 5.  Use @code{__have_feature__ (@var{option})} or
-## @code{__octave_config_info__} as a replacement.
-##
-## Return a structure containing configuration and installation
-## information for Octave.
-##
-## If @var{option} is a string, return the configuration information for
-## the specified option.
-##
-## @seealso{computer}
-## @end deftypefn
-
-## Deprecated in version 4.2
-
-function [retval, build_env_cell] = octave_config_info (option)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "octave_config_info is obsolete and will be removed from a future version of Octave, please use __have_feature__ or __octave_config_info__ instead.");
-  endif
-
-  if (nargin > 1)
-    print_usage ();
-  endif
-
-  if (nargin == 0)
-    info = __octave_config_info__ ();
-    ## Structure layout has changed.
-
-    dld = info.dld;
-    float_format = info.float_format;
-    words_big_endian = info.words_big_endian;
-    words_little_endian = info.words_little_endian;
-
-    features = info.build_features;
-
-    env = info.build_environment;
-    env_fields = fieldnames (env);
-    env_vals = struct2cell (env);
-    env_cell = [env_fields, env_vals]';
-
-    info = rmfield (info, {"dld", "float_format", "words_big_endian", ...
-                           "words_little_endian", "build_features", ...
-                           "build_environment"});
-
-    other_fields = fieldnames (info);
-    other_vals = struct2cell (info);
-    other_cell = [other_fields, other_vals]';
-
-    retval = struct ("dld", dld,
-                     "float_format", float_format,
-                     "words_big_endian", words_big_endian,
-                     "words_little_endian", words_little_endian,
-                     "features", features,
-                     env_cell{:}, other_cell{:});
-  else
-    if (strcmp (option, "features"))
-      option = "build_features";
-    endif
-    retval = __octave_config_info__ (option);
-  endif
-
-endfunction
--- a/scripts/deprecated/onenormest.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-## Copyright (C) 2007-2018 Regents of the University of California
-##
-## 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{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{A}, @var{t})
-## @deftypefnx {} {[@var{est}, @var{v}, @var{w}, @var{iter}] =} onenormest (@var{apply}, @var{apply_t}, @var{n}, @var{t})
-##
-## @code{onenormest} is deprecated and will be removed in Octave version 5.
-## Use @code{normest1} for the equivalent functionality.
-##
-## Apply @nospell{Higham and Tisseur's} randomized block 1-norm estimator to
-## matrix @var{A} using @var{t} test vectors.
-##
-## If @var{t} exceeds 5, then only 5 test vectors are used.
-##
-## If the matrix is not explicit, e.g., when estimating the norm of
-## @code{inv (@var{A})} given an LU@tie{}factorization, @code{onenormest}
-## applies @var{A} and its conjugate transpose through a pair of functions
-## @var{apply} and @var{apply_t}, respectively, to a dense matrix of size
-## @var{n} by @var{t}.  The implicit version requires an explicit dimension
-## @var{n}.
-##
-## Returns the norm estimate @var{est}, two vectors @var{v} and @var{w} related
-## by norm @code{(@var{w}, 1) = @var{est} * norm (@var{v}, 1)}, and the number
-## of iterations @var{iter}.  The number of iterations is limited to 10 and is
-## at least 2.
-##
-## References:
-##
-## @itemize
-## @item
-## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
-## for Matrix 1-Norm Estimation, with an Application to 1-Norm
-## Pseudospectra}. SIMAX vol 21, no 4, pp 1185-1201.
-## @url{http://dx.doi.org/10.1137/S0895479899356080}
-##
-## @item
-## @nospell{N.J. Higham and F. Tisseur}, @cite{A Block Algorithm
-## for Matrix 1-Norm Estimation, with an Application to 1-Norm
-## Pseudospectra}. @url{http://citeseer.ist.psu.edu/223007.html}
-## @end itemize
-##
-## @seealso{condest, norm, cond}
-## @end deftypefn
-
-## Code originally licensed under:
-##
-## Copyright (c) 2007, Regents of the University of California
-## All rights reserved.
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-##    * Redistributions of source code must retain the above copyright
-##      notice, this list of conditions and the following disclaimer.
-##
-##    * Redistributions in binary form must reproduce the above
-##      copyright notice, this list of conditions and the following
-##      disclaimer in the documentation and/or other materials provided
-##      with the distribution.
-##
-##    * Neither the name of the University of California, Berkeley nor
-##      the names of its contributors may be used to endorse or promote
-##      products derived from this software without specific prior
-##      written permission.
-##
-## THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS AND
-## 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.
-
-## Author: Jason Riedy <ejr@cs.berkeley.edu>
-## Keywords: linear-algebra norm estimation
-## Version: 0.2
-
-function [est, v, w, iter] = onenormest (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "onenormest is obsolete and will be removed from a future version of Octave, please use normest1 instead");
-  endif
-
-
-  if (nargin < 1 || nargin > 4)
-    print_usage ();
-  endif
-
-  default_t = 5;
-  itmax = 10;
-
-  if (isnumeric (varargin{1}))
-    [n, nc] = size (varargin{1});
-    if (n != nc)
-      error ("onenormest: matrix must be square");
-    endif
-    apply = @(x) varargin{1} * x;
-    apply_t = @(x) varargin{1}' * x;
-    if (nargin > 1)
-      t = varargin{2};
-    else
-      t = min (n, default_t);
-    endif
-    issing = isa (varargin{1}, "single");
-  else
-    if (nargin < 3)
-      print_usage ();
-    endif
-    apply = varargin{1};
-    apply_t = varargin{2};
-    n = varargin{3};
-    if (nargin > 3)
-      t = varargin{4};
-    else
-      t = default_t;
-    endif
-    issing = isa (n, "single");
-  endif
-
-  ## Initial test vectors X.
-  X = rand (n, t);
-  X ./= ones (n,1) * sum (abs (X), 1);
-
-  ## Track if a vertex has been visited.
-  been_there = zeros (n, 1);
-
-  ## To check if the estimate has increased.
-  est_old = 0;
-
-  ## Normalized vector of signs.
-  S = zeros (n, t);
-
-  if (issing)
-    myeps = eps ("single");
-    X = single (X);
-  else
-    myeps = eps;
-  endif
-
-  for iter = 1 : itmax + 1
-    Y = feval (apply, X);
-
-    ## Find the initial estimate as the largest A*x.
-    [est, ind_best] = max (sum (abs (Y), 1));
-    if (est > est_old || iter == 2)
-      w = Y(:,ind_best);
-    endif
-    if (iter >= 2 && est < est_old)
-      ## No improvement, so stop.
-      est = est_old;
-      break;
-    endif
-
-    est_old = est;
-    S_old = S;
-    if (iter > itmax),
-      ## Gone too far.  Stop.
-      break;
-    endif
-
-    S = sign (Y);
-
-    ## Test if any of S are approximately parallel to previous S
-    ## vectors or current S vectors.  If everything is parallel,
-    ## stop.  Otherwise, replace any parallel vectors with
-    ## rand{-1,+1}.
-    partest = any (abs (S_old' * S - n) < 4*eps*n);
-    if (all (partest))
-      ## All the current vectors are parallel to old vectors.
-      ## We've hit a cycle, so stop.
-      break;
-    endif
-    if (any (partest))
-      ## Some vectors are parallel to old ones and are cycling,
-      ## but not all of them.  Replace the parallel vectors with
-      ## rand{-1,+1}.
-      numpar = sum (partest);
-      replacements = 2*(rand (n,numpar) < 0.5) - 1;
-      S(:,partest) = replacements;
-    endif
-    ## Now test for parallel vectors within S.
-    partest = any ((S' * S - eye (t)) == n);
-    if (any (partest))
-      numpar = sum (partest);
-      replacements = 2*(rand (n,numpar) < 0.5) - 1;
-      S(:,partest) = replacements;
-    endif
-
-    Z = feval (apply_t, S);
-
-    ## Now find the largest non-previously-visted index per vector.
-    h = max (abs (Z),2);
-    [mh, mhi] = max (h);
-    if (iter >= 2 && mhi == ind_best)
-      ## Hit a cycle, stop.
-      break;
-    endif
-    [h, ind] = sort (h, 'descend');
-    if (t > 1)
-      firstind = ind(1:t);
-      if (all (been_there(firstind)))
-        ## Visited all these before, so stop.
-        break;
-      endif
-      ind = ind(! been_there(ind));
-      if (length (ind) < t)
-        ## There aren't enough new vectors, so we're practically
-        ## in a cycle.  Stop.
-        break;
-      endif
-    endif
-
-    ## Visit the new indices.
-    X = zeros (n, t);
-    for zz = 1 : t
-      X(ind(zz),zz) = 1;
-    endfor
-    been_there(ind(1 : t)) = 1;
-  endfor
-
-  ## The estimate est and vector w are set in the loop above.
-  ## The vector v selects the ind_best column of A.
-  v = zeros (n, 1);
-  v(ind_best) = 1;
-
-endfunction
-
-
-%!demo
-%! N = 100;
-%! A = randn (N) + eye (N);
-%! [L,U,P] = lu (A);
-%! nm1inv = onenormest (@(x) U\(L\(P*x)), @(x) P'*(L'\(U'\x)), N, 30)
-%! norm (inv (A), 1)
-
-%!test
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 10;
-%! A = ones (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, N, -2*eps);
-%! assert (nminf, N, -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-%!test
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 10;
-%! A = ones (N);
-%! [nm1, v1, w1] = onenormest (@(x) A*x, @(x) A'*x, N, 3);
-%! [nminf, vinf, winf] = onenormest (@(x) A'*x, @(x) A*x, N, 3);
-%! assert (nm1, N, -2*eps);
-%! assert (nminf, N, -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-%!test
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 5;
-%! A = hilb (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, norm (A, 1), -2*eps);
-%! assert (nminf, norm (A, inf), -2*eps);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
-
-## Only likely to be within a factor of 10.
-%!test
-%! warning ("off", "Octave:deprecated-function", "local");
-%! old_state = rand ("state");
-%! restore_state = onCleanup (@() rand ("state", old_state));
-%! rand ("state", 42);  # Initialize to guarantee reproducible results
-%! N = 100;
-%! A = rand (N);
-%! [nm1, v1, w1] = onenormest (A);
-%! [nminf, vinf, winf] = onenormest (A', 6);
-%! assert (nm1, norm (A, 1), -.1);
-%! assert (nminf, norm (A, inf), -.1);
-%! assert (norm (w1, 1), nm1 * norm (v1, 1), -2*eps);
-%! assert (norm (winf, 1), nminf * norm (vinf, 1), -2*eps);
--- a/scripts/deprecated/setstr.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-## Copyright (C) 2003-2018 John W. Eaton
-##
-## 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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {Function File} {} setstr (@var{s})
-## This function has been deprecated.  Use char instead.
-## @end deftypefn
-
-## Author: jwe
-
-## Deprecated in version 3.0
-## Matlab still has this function, so don't remove just yet.
-
-function retval = setstr (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "setstr is obsolete and will be removed from a future version of Octave; please use char instead");
-  endif
-
-  retval = char (varargin{:});
-
-endfunction
--- a/scripts/deprecated/sleep.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-## Copyright (C) 1993-2018 John W. Eaton
-##
-## 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 {} {} sleep (@var{seconds})
-##
-## @code{sleep} is deprecated and will be removed in Octave version 5.
-## Use @code{pause} instead.
-##
-## Suspend the execution of the program for the given number of seconds.
-##
-## @seealso{pause}
-## @end deftypefn
-
-function sleep (seconds)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "sleep is obsolete and will be removed from a future version of Octave, please use pause instead");
-  endif
-
-  if (nargin == 1)
-    pause (seconds);
-  else
-    print_usage ();
-  endif
-
-endfunction
-
-
-%!test
-%! sleep (1);
-
-%!error (sleep ())
-%!error (sleep (1, 2))
--- a/scripts/deprecated/toascii.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/deprecated/toascii.m	Thu Dec 20 17:18:56 2018 -0500
@@ -60,6 +60,11 @@
 endfunction
 
 
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:deprecated-function", "local");
+%! toascii ("");
+
 %!assert (toascii (char (0:127)), 0:127)
 %!assert (toascii (" ":"@"), 32:64)
 %!assert (toascii ("A":"Z"), 65:90)
--- a/scripts/deprecated/usleep.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-## Copyright (C) 1993-2018 John W. Eaton
-##
-## 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 {} {} usleep (@var{microseconds})
-##
-## @code{usleep} is deprecated and will be removed in Octave version 5.
-## Use @code{pause} instead.
-##
-## Suspend the execution of the program for the given number of
-## microseconds (1e-6 seconds).
-##
-## @seealso{pause}
-## @end deftypefn
-
-function usleep (microseconds)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "usleep is obsolete and will be removed from a future version of Octave, please use pause instead");
-  endif
-
-  if (nargin == 1)
-    pause (microseconds / 1e6);
-  else
-    print_usage ();
-  endif
-
-endfunction
-
-
-%!test
-%! usleep (1000);
-
-%!error (usleep ())
-%!error (usleep (1, 2))
--- a/scripts/deprecated/wavread.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-## Copyright (C) 2016-2018 Mike Miller
-## Copyright (C) 2005-2018 Michael Zeising
-##
-## 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} =} wavread (@var{filename})
-## @deftypefnx {} {[@var{y}, @var{fs}, @var{nbits}] =} wavread (@var{filename})
-## @deftypefnx {} {[@dots{}] =} wavread (@var{filename}, @var{n})
-## @deftypefnx {} {[@dots{}] =} wavread (@var{filename}, [@var{n1} @var{n2}])
-## @deftypefnx {} {[@dots{}] =} wavread (@dots{}, @var{datatype})
-## @deftypefnx {} {@var{sz} =} wavread (@var{filename}, "size")
-## @deftypefnx {} {[@var{n_samp}, @var{n_chan}] =} wavread (@var{filename}, "size")
-##
-## @code{wavread} is deprecated and will be removed in Octave version 5.
-## Use @code{audioread} for the equivalent functionality.
-##
-## Read the audio signal @var{y} from the RIFF/WAVE sound file @var{filename}.
-##
-## If the file contains multichannel data, then @var{y} is a matrix with the
-## channels represented as columns.
-##
-## If @var{n} is specified, only the first @var{n} samples of the file are
-## returned.  If [@var{n1} @var{n2}] is specified, only the range of samples
-## from @var{n1} to @var{n2} is returned.  A value of @code{Inf} can be used
-## to represent the total number of samples in the file.
-##
-## If the option @qcode{"size"} is given, then the size of the audio signal
-## is returned instead of the data.  The size is returned in a row vector of
-## the form [@var{samples} @var{channels}].  If there are two output arguments,
-## the number of samples is assigned to the first and the number of channels
-## is assigned to the second.
-##
-## The optional return value @var{fs} is the sample rate of the audio file in
-## Hz.  The optional return value @var{nbits} is the number of bits per sample
-## as encoded in the file.
-##
-## @seealso{audioread, audiowrite, wavwrite}
-## @end deftypefn
-
-## Deprecated in 4.2
-
-function [y, fs, nbits] = wavread (filename, varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "wavread is obsolete and will be removed from a future version of Octave, please use audioread instead");
-  endif
-
-  if (nargin < 1 || nargin > 3)
-    print_usage ();
-  endif
-
-  if (! ischar (filename))
-    error ("wavread: FILENAME must be a character string");
-  endif
-
-  datatype = "double";
-  samples = [1, Inf];
-  do_file_size = false;
-
-  if (nargin == 3)
-    samples = varargin{1};
-    datatype = varargin{2};
-  elseif (nargin == 2)
-    if (strcmp (varargin{1}, "size"))
-      do_file_size = true;
-    elseif (ischar (varargin{1}))
-      datatype = varargin{1};
-    else
-      samples = varargin{1};
-    endif
-  endif
-
-  if (isscalar (samples))
-    samples = [1, samples];
-  endif
-
-  if (! (isrow (samples) && numel (samples) == 2 && all (samples > 0)
-         && all (fix (samples) == samples)))
-    error ("wavread: SAMPLES must be a 1- or 2-element integer row vector");
-  endif
-
-  if (! (ischar (datatype) && any (strcmp (datatype, {"double", "native"}))))
-    error ('wavread: DATATYPE must be either "double" or "native"');
-  endif
-
-  info = audioinfo (filename);
-
-  if (do_file_size)
-    if (nargout > 1)
-      [y, fs] = deal (info.TotalSamples, info.NumChannels);
-    else
-      y = [info.TotalSamples, info.NumChannels];
-    endif
-  else
-    [y, fs] = audioread (filename, samples, datatype);
-    nbits = info.BitsPerSample;
-  endif
-
-endfunction
-
-
-## Functional tests for wavread/wavwrite pair are in wavwrite.m.
-
-## Test input validation
-%!error wavread ()
-%!error wavread (1)
-%!error wavread ("foo.wav", 2, 3, 4)
-%!error wavread ("foo.wav", "foo")
-%!error wavread ("foo.wav", -1)
-%!error wavread ("foo.wav", [1, Inf], "foo")
--- a/scripts/deprecated/wavwrite.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-## Copyright (C) 2016-2018 Mike Miller
-## Copyright (C) 2005-2018 Michael Zeising
-##
-## 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  {} {} wavwrite (@var{y}, @var{filename})
-## @deftypefnx {} {} wavwrite (@var{y}, @var{fs}, @var{filename})
-## @deftypefnx {} {} wavwrite (@var{y}, @var{fs}, @var{nbits}, @var{filename})
-##
-## @code{wavwrite} is deprecated and will be removed in Octave version 5.
-## Use @code{audiowrite} for the equivalent functionality.
-##
-## Write the audio signal @var{y} to the RIFF/WAVE sound file @var{filename}.
-##
-## If @var{y} is a matrix, the columns represent multiple audio channels.
-##
-## The optional argument @var{fs} specifies the sample rate of the audio signal
-## in Hz.
-##
-## The optional argument @var{nbits} specifies the number of bits per sample
-## to write to @var{filename}.
-##
-## The default sample rate is 8000 Hz and the default bit depth is 16 bits
-## per sample.
-##
-## @seealso{audiowrite, audioread, wavread}
-## @end deftypefn
-
-## Deprecated in 4.2
-
-function wavwrite (y, varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "wavwrite is obsolete and will be removed from a future version of Octave, please use audiowrite instead");
-  endif
-
-  if (nargin < 2 || nargin > 4)
-    print_usage ();
-  endif
-
-  ## Defaults.
-  fs = 8000;
-  nbits = 16;
-
-  filename = varargin{end};
-  if (nargin > 2)
-    fs = varargin{1};
-    if (nargin > 3)
-      nbits = varargin{2};
-    endif
-  endif
-
-  ## calculate filesize
-  [n, channels] = size (y);
-
-  ## allow y to be a row vector
-  if (n == 1)
-    y = y(:);
-    n = channels;
-    channels = 1;
-  endif
-
-  ## test arguments
-  if (channels < 1)
-    error ("wavwrite: Y must have at least one column");
-  endif
-
-  if (channels > 0x7FFF)
-    error ("wavwrite: Y must have no more than 32767 columns");
-  endif
-
-  if (! (isscalar (fs) && (fs > 0)))
-    error ("wavwrite: sample rate FS must be a positive number");
-  endif
-
-  if (! isscalar (nbits) || isempty (find (nbits == [8, 16, 24, 32])))
-    error ("wavwrite: bit depth NBITS must be 8, 16, 24, or 32");
-  endif
-
-  audiowrite (filename, y, fs, "BitsPerSample", nbits);
-
-endfunction
-
-
-%!shared fname
-%! fname = [tempname() ".wav"];
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1; -1:0.1:1]';
-%! unwind_protect
-%!   wavwrite (A, fname);
-%!   [B, samples_per_sec, bits_per_sample] = wavread (fname);
-%!   assert (B, A, 2^-14);
-%!   assert (samples_per_sec, 8000);
-%!   assert (bits_per_sample, 16);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1; -1:0.1:1]';
-%! unwind_protect
-%!   wavwrite (A, 4000, fname);
-%!   [B, samples_per_sec, bits_per_sample] = wavread (fname);
-%!   assert (B, A, 2^-14);
-%!   assert (samples_per_sec, 4000);
-%!   assert (bits_per_sample, 16);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1; -1:0.1:1]';
-%! unwind_protect
-%!   wavwrite (A, 4000, 8, fname);
-%!   [B, samples_per_sec, bits_per_sample] = wavread (fname);
-%!   assert (B, A, 2^-6);
-%!   assert (samples_per_sec, 4000);
-%!   assert (bits_per_sample, 8);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-2:2]';
-%! unwind_protect
-%!   wavwrite (A, fname);
-%!   B = wavread (fname);
-%!   B *= 32768;
-%!   assert (B, [-32767 -32767 0 32767 32767]');
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1];
-%! unwind_protect
-%!   wavwrite (A, fname);
-%!   [B, samples_per_sec, bits_per_sample] = wavread (fname);
-%!   assert (B, A', 2^-14);
-%!   assert (samples_per_sec, 8000);
-%!   assert (bits_per_sample, 16);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1; -1:0.1:1]';
-%! unwind_protect
-%!   wavwrite (A, fname);
-%!   B = wavread (fname, 15);
-%!   assert (B, A(1:15,:), 2^-14);
-%!   wavwrite (A, fname);
-%!   B = wavread (fname, [10, 20]);
-%!   assert (B, A(10:20,:), 2^-14);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-%!testif HAVE_SNDFILE
-%! A = [-1:0.1:1; -1:0.1:1]';
-%! unwind_protect
-%!   wavwrite (A, fname);
-%!   [nsamp, nchan] = wavread (fname, "size");
-%!   assert (nsamp, 21);
-%!   assert (nchan, 2);
-%! unwind_protect_cleanup
-%!   unlink (fname);
-%! end_unwind_protect
-
-## Test input validation
-%!error wavwrite ()
-%!error wavwrite (1)
-%!error wavwrite (1,2,3,4,5)
-%!error wavwrite ([], "foo.wav")
--- a/scripts/general/accumarray.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/accumarray.m	Thu Dec 20 17:18:56 2018 -0500
@@ -278,7 +278,7 @@
       ## Fast maximization.
 
       if (isinteger (vals))
-        zero = intmin (class (vals));
+        zero = intmin (vals);
       elseif (islogical (vals))
         zero = false;
       elseif (fillval == 0 && all (vals(:) >= 0))
@@ -305,7 +305,7 @@
       ## Fast minimization.
 
       if (isinteger (vals))
-        zero = intmax (class (vals));
+        zero = intmax (vals);
       elseif (islogical (vals))
         zero = true;
       elseif (fillval == 0 && all (vals(:) <= 0))
--- a/scripts/general/bitset.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/bitset.m	Thu Dec 20 17:18:56 2018 -0500
@@ -22,20 +22,41 @@
 ## @deftypefnx {} {@var{C} =} bitset (@var{A}, @var{n}, @var{val})
 ## Set or reset bit(s) @var{n} of the unsigned integers in @var{A}.
 ##
-## @var{val} = 0 resets and @var{val} = 1 sets the bits.
-## The least significant bit is @var{n} = 1.  All variables must be the same
-## size or scalars.
+## The least significant bit is @var{n} = 1.  @w{@var{val} = 0} resets bits and
+## @w{@var{val} = 1} sets bits.  If no @var{val} is specified it defaults to
+## 1 (set bit).  All inputs must be the same size or scalars.
+##
+## Example 1: Set multiple bits
 ##
 ## @example
 ## @group
-## dec2bin (bitset (10, 1))
-##   @result{} 1011
+## x = bitset (1, 3:5)
+## x =
+##
+##    5    9   17
+##
+## dec2bin (x)
+##   @result{}
+##      00101
+##      01001
+##      10001
+## @end group
+## @end example
+##
+## Example 2: Reset and set bits
+##
+## @example
+## @group
+## x = bitset ([15 14], 1, [0 1])
+## x =
+##
+##    14    15
 ## @end group
 ## @end example
 ## @seealso{bitand, bitor, bitxor, bitget, bitcmp, bitshift, intmax, flintmax}
 ## @end deftypefn
 
-function C = bitset (A, n, val)
+function C = bitset (A, n, val = true)
 
   if (nargin < 2 || nargin > 3)
     print_usage ();
@@ -45,12 +66,18 @@
     error ("bitset: A must be >= 0");
   endif
 
-  sz = size (A);
-
-  if (nargin == 2)
-    val = true (sz);
+  [size_err, A, n, val] = common_size (A, n, val);
+  if (size_err)
+    error ("bitset: A, N, and VAL must be the same size or scalar");
   endif
 
+  ## Special case of empty input
+  if (isempty (A))
+    C = [];
+    return;
+  endif
+
+  sz = size (A);
   cl = class (A);
 
   if (isfloat (A) && isreal (A))
@@ -76,9 +103,6 @@
     onmask = mask;
     offmask = mask;
   else
-    if (! size_equal (A, n))
-      error ("bitset: N must be scalar or the same size as A");
-    endif
     onmask = mask(on);
     offmask = mask(off);
   endif
@@ -101,12 +125,21 @@
 %!   endfor
 %! endfor
 
+%!assert (bitset ([], 1), [])
+
 %!assert <*36458> (bitset (uint8 ([1, 2;3 4]), 1, [0 1; 0 1]),
-%!                uint8 ([0, 3; 2 5]))
+%!                 uint8 ([0, 3; 2 5]))
+
+%!assert (bitset (1:5, 1), [1, 3, 3, 5, 5])
+%!assert (bitset (1:5, 1, [1, 1, 1, 1, 1]), [1, 3, 3, 5, 5])
+%!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)
 %!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])
 %!error <invalid class char> bitset ("1", 2)
 %!error <N must be in the range \[1,53\]> bitset (0, 0)
 %!error <N must be in the range \[1,53\]> bitset (0, 55)
@@ -121,5 +154,3 @@
 %!error <N must be in the range \[1,32\]> bitset (uint32 (0), 33)
 %!error <N must be in the range \[1,63\]> bitset (int64 (0), 65)
 %!error <N must be in the range \[1,64\]> bitset (uint64 (0), 65)
-%!error <N must be scalar or the same size as A> bitset (uint8 (1), [1 3])
-%!error <N must be scalar or the same size as A> bitset (uint8 (1:3), [1 3])
--- a/scripts/general/circshift.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/circshift.m	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,8 @@
 ## in @var{x}.  The values of @var{n} can be either positive or negative, which
 ## determines the direction in which the values of @var{x} are shifted.  If an
 ## element of @var{n} is zero, then the corresponding dimension of @var{x} will
-## not be shifted.
+## not be shifted.  If @var{n} is a scalar and no @var{dim} is specified then
+## the shift is applied to the first non-singular dimension.
 ##
 ## If a scalar @var{dim} is given then operate along the specified dimension.
 ## In this case @var{n} must be a scalar as well.
@@ -33,21 +34,25 @@
 ## Examples:
 ##
 ## @example
-## @group
-## x = [1, 2, 3; 4, 5, 6; 7, 8, 9];
-## circshift (x, 1)
-## @result{}  7, 8, 9
-##     1, 2, 3
-##     4, 5, 6
-## circshift (x, -2)
-## @result{}  7, 8, 9
-##     1, 2, 3
-##     4, 5, 6
-## circshift (x, [0,1])
-## @result{}  3, 1, 2
-##     6, 4, 5
-##     9, 7, 8
-## @end group
+## x = [1, 2, 3;
+##      4, 5, 6;
+##      7, 8, 9];
+## circshift (x, 1)      # positive shift on rows (1st non-singular dim)
+##  @result{}  7, 8, 9
+##      1, 2, 3
+##      4, 5, 6
+## circshift (x, -2)     # negative shift on rows (1st non-singular dim)
+##  @result{}  7, 8, 9
+##      1, 2, 3
+##      4, 5, 6
+## circshift (x, [0,1])  # no shift of rows, shift columns by 1 (2nd dimension)
+##  @result{}  3, 1, 2
+##      6, 4, 5
+##      9, 7, 8
+## circshift (x, 1, 2)   # shift columns (2nd dimension)
+##  @result{}  3, 1, 2
+##      6, 4, 5
+##      9, 7, 8
 ## @end example
 ## @seealso{permute, ipermute, shiftdim}
 ## @end deftypefn
@@ -63,16 +68,22 @@
     return;
   endif
 
-  if (nargin == 3)
-    if (! isscalar (n))
+  nd = ndims (x);
+  sz = size (x);
+
+  if (nargin == 2)
+    if (isscalar (n))
+      ## Find the first non-singleton dimension.
+      (dim = find (sz > 1, 1)) || (dim = 1);
+      n = [zeros(1, dim-1), n];
+    endif
+  elseif (nargin == 3)
+    if ( ! isscalar (n))
       error ("circshift: N must be a scalar when DIM is also specified");
     endif
     n = [zeros(1, dim-1), n];
   endif
 
-  nd = ndims (x);
-  sz = size (x);
-
   if (! isvector (n) || length (n) > nd)
     error ("circshift: N must be a vector, no longer than the number of dimensions in X");
   elseif (any (n != fix (n)))
@@ -80,7 +91,7 @@
   endif
 
   idx = repmat ({':'}, 1, nd);
-  for i = 1:length (n);
+  for i = 1:length (n)
     b = n(i);
     d = sz(i);
     if (b > 0)
@@ -111,6 +122,9 @@
 %!assert (circshift (x, -2, 1), [7, 8, 9; 1, 2, 3; 4, 5, 6])
 %!assert (circshift (x, 1, 2), [3, 1, 2; 6, 4, 5; 9, 7, 8])
 
+%!test <*53178> assert (circshift (1:4, 1), [4 1 2 3])
+%!test <*53178> assert (circshift (1:4, 1, 1), 1:4)
+
 ## Test input validation
 %!error circshift ()
 %!error circshift (1)
--- a/scripts/general/cumtrapz.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/cumtrapz.m	Thu Dec 20 17:18:56 2018 -0500
@@ -59,9 +59,9 @@
     have_xy = true;
     have_dim = true;
   elseif (nargin == 2)
-    if (! size_equal (x, y) && isscalar (y))
+    if (isscalar (y) && ! isscalar (x))
+      have_dim = true;
       dim = y;
-      have_dim = true;
     else
       have_xy = true;
     endif
@@ -86,28 +86,28 @@
   endif
 
   n = sz(dim);
-  idx1 = idx2 = repmat ({':'}, [nd, 1]);
+  idx1 = idx2 = {':'}(ones (nd, 1));  # repmat ({':'}, [nd, 1]), but faster
   idx1{dim} = 2 : n;
   idx2{dim} = 1 : (n - 1);
 
   if (! have_xy)
     z = 0.5 * cumsum (x(idx1{:}) + x(idx2{:}), dim);
-  else
-    if (isvector (x) && ! isvector (y))
-      if (length (x) != sz(dim))
-        error ("cumtrapz: length of X and length of Y along DIM must match");
-      endif
+  elseif (isscalar (x))
+    z = x * 0.5 * cumsum (y(idx1{:}) + y(idx2{:}), dim);
+  elseif (isvector (x))
+    if (length (x) != n)
+      error ("cumtrapz: length of X and length of Y along DIM must match");
+    endif
       ## Reshape vector to point along dimension DIM
       shape = ones (nd, 1);
-      shape(dim) = sz(dim);
+      shape(dim) = n;
       x = reshape (x, shape);
       z = 0.5 * cumsum (diff (x) .* (y(idx1{:}) + y(idx2{:})), dim);
-    else
-      if (! size_equal (x, y))
-        error ("cumtrapz: X and Y must have same shape");
-      endif
-      z = 0.5 * cumsum (diff (x, 1, dim) .* (y(idx1{:}) + y(idx2{:})), dim);
+  else
+    if (! size_equal (x, y))
+      error ("cumtrapz: X and Y must have same shape");
     endif
+    z = 0.5 * cumsum (diff (x, 1, dim) .* (y(idx1{:}) + y(idx2{:})), dim);
   endif
 
   sz(dim) = 1;
@@ -116,17 +116,34 @@
 endfunction
 
 
-%!shared x1,x2,y
+%!shared x1, x2, y
+%! x1 = [1:5];
+%! x2 = [2:2:10];
+%! y = [1:5];
+%!
+%!assert (cumtrapz (y), [0, 1.5, 4, 7.5, 12])
+%!assert (cumtrapz (y'), [0, 1.5, 4, 7.5, 12]')
+%!assert (cumtrapz (1, y), [0, 1.5, 4, 7.5, 12])
+%!assert (cumtrapz (2, y), [0, 3, 8, 15, 24])
+%!assert (cumtrapz (x1, y),[0, 1.5, 4, 7.5, 12])
+%!assert (cumtrapz (x2, y),[0, 3, 8, 15, 24])
+%!assert (cumtrapz (2, y, 2), [0, 3, 8, 15, 24])
+%!assert (cumtrapz (x2, y, 2), [0, 3, 8, 15, 24])
+%!assert (cumtrapz (y, 1), [0, 0, 0, 0, 0])
+%!assert (cumtrapz (2, y, 1), [0, 0, 0, 0, 0])
+%!assert (cumtrapz (y', 2), [0, 0, 0, 0, 0]')
+
+%!shared x1, x2, y
 %! x1 = [0,0,0;2,2,2];
 %! x2 = [0,2,4;0,2,4];
 %! y = [1,2,3;4,5,6];
 %!
 %!assert (cumtrapz (y), [0,0,0;2.5,3.5,4.5])
-%!assert (cumtrapz (x1,y), [0,0,0;5,7,9])
-%!assert (cumtrapz (y,1), [0,0,0;2.5,3.5,4.5])
-%!assert (cumtrapz (x1,y,1), [0,0,0;5,7,9])
-%!assert (cumtrapz (y,2), [0,1.5,4;0,4.5,10])
-%!assert (cumtrapz (x2,y,2), [0,3,8;0,9,20])
+%!assert (cumtrapz (x1, y), [0,0,0;5,7,9])
+%!assert (cumtrapz (y, 1), [0,0,0;2.5,3.5,4.5])
+%!assert (cumtrapz (x1, y, 1), [0,0,0;5,7,9])
+%!assert (cumtrapz (y, 2), [0,1.5,4;0,4.5,10])
+%!assert (cumtrapz (x2, y, 2), [0,3,8;0,9,20])
 
 ## Test ND-array implementation
 %!shared x1,x2,y
@@ -137,3 +154,13 @@
 %!assert (cumtrapz (y,3), reshape ([0,1.5,4;0,4.5,10],[1 2 3]))
 %!assert (cumtrapz (x1,y,3), reshape ([0,1.5,4;0,4.5,10],[1 2 3]))
 %!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 <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)
+%!error <length of X and length of Y.*must match> cumtrapz ([1 2], [1 2 3])
+%!error <X and Y must have same shape> cumtrapz (ones (2,3), ones (2,4))
+
--- a/scripts/general/flipdim.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-## Copyright (C) 2004-2018 David Bateman
-## Copyright (C) 2009 VZLU Prague
-##
-## 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  {} {} flipdim (@var{x})
-## @deftypefnx {} {} flipdim (@var{x}, @var{dim})
-## Flip array across dimension @var{dim}.
-##
-## This function is an alias for @code{flip} and exists for backwards and
-## @sc{matlab} compatibility.  See @code{flip} for complete usage information.
-##
-## @seealso{flip, fliplr, flipud, rot90, rotdim}
-## @end deftypefn
-
-## Author: David Bateman, Jaroslav Hajek
-
-function y = flipdim (varargin)
-  y = flip (varargin{:});
-endfunction
-
-
-## No tests needed for alias.  All tests for functionality are in flip.m
-%!assert (1)
--- a/scripts/general/gradient.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/gradient.m	Thu Dec 20 17:18:56 2018 -0500
@@ -72,7 +72,7 @@
   nargout_with_ans = max (1,nargout);
   if (isnumeric (m))
     [varargout{1:nargout_with_ans}] = matrix_gradient (m, varargin{:});
-  elseif (isa (m, "function_handle"))
+  elseif (is_function_handle (m))
     [varargout{1:nargout_with_ans}] = handle_gradient (m, varargin{:});
   elseif (ischar (m))
     [varargout{1:nargout_with_ans}] = handle_gradient (str2func (m), ...
--- a/scripts/general/interpft.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/interpft.m	Thu Dec 20 17:18:56 2018 -0500
@@ -118,21 +118,28 @@
 
 %!shared n,y
 %! x = [0:10]';  y = sin(x);  n = length (x);
-%!assert (interpft (y, n), y, 20*eps)
-%!assert (interpft (y', n), y', 20*eps)
-%!assert (interpft ([y,y],n), [y,y], 20*eps)
+%!testif HAVE_FFTW
+%! assert (interpft (y, n), y, 20*eps)
+%!testif HAVE_FFTW
+%! assert (interpft (y', n), y', 20*eps)
+%!testif HAVE_FFTW
+%! assert (interpft ([y,y],n), [y,y], 20*eps)
 
 ## Test case with complex input
-%!test <*39566>
+%!testif HAVE_FFTW <*39566>
 %! x = (1 + j) * [1:4]';
 %! y = ifft ([15 + 15*j; -6; -1.5 - 1.5*j; 0; -1.5 - 1.5*j; -6*j]);
 %! assert (interpft (x, 6), y, 10*eps);
 
 ## Test for correct spectral symmetry with even/odd lengths
-%!assert (max (abs (imag (interpft ([1:8], 20)))), 0, 20*eps)
-%!assert (max (abs (imag (interpft ([1:8], 21)))), 0, 21*eps)
-%!assert (max (abs (imag (interpft ([1:9], 20)))), 0, 20*eps)
-%!assert (max (abs (imag (interpft ([1:9], 21)))), 0, 21*eps)
+%!testif HAVE_FFTW
+%! 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)
+%!testif HAVE_FFTW
+%! 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)
 
 ## Test input validation
 %!error interpft ()
--- a/scripts/general/isequal.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/isequal.m	Thu Dec 20 17:18:56 2018 -0500
@@ -162,7 +162,7 @@
           idx += 1;
         endwhile
 
-      elseif (isa (x, "function_handle"))
+      elseif (is_function_handle (x))
         ## function type.  Use '==' operator which is overloaded.
         t = (x == y);
 
@@ -291,7 +291,7 @@
           idx += 1;
         endwhile
 
-      elseif (isa (x, "function_handle"))
+      elseif (is_function_handle (x))
         ## function type.  Use '==' operator which is overloaded.
         t = all (cellfun ("eq", {x}, varargin));
 
--- a/scripts/general/isequaln.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/isequaln.m	Thu Dec 20 17:18:56 2018 -0500
@@ -160,7 +160,7 @@
           idx += 1;
         endwhile
 
-      elseif (isa (x, "function_handle"))
+      elseif (is_function_handle (x))
         ## function type.  Use '==' operator which is overloaded.
         t = (x == y);
 
@@ -275,7 +275,7 @@
           idx += 1;
         endwhile
 
-      elseif (isa (x, "function_handle"))
+      elseif (is_function_handle (x))
         ## function type.  Use '==' operator which is overloaded.
         t = all (cellfun ("eq", {x}, varargin));
 
--- a/scripts/general/logspace.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/logspace.m	Thu Dec 20 17:18:56 2018 -0500
@@ -97,6 +97,16 @@
 %! assert (size (x2) == [1, 10] && abs (x2(1) - 10) < eps && abs (x2(10) - 100) < eps);
 %! assert (size (x3) == [1, 10] && abs (x3(1) - 10) < eps && abs (x3(10) - 0.01) < eps);
 %! assert (size (x4) == [1, 10] && abs (x4(1) - 10) < eps && abs (x4(10) - pi) < sqrt (eps));
+%!assert (logspace (Inf, Inf, 3), [Inf, Inf, Inf])
+%!assert (logspace (-Inf, -Inf, 3), [0, 0, 0])
+%!assert (logspace (-Inf, Inf, 3), [0, NaN, 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)])
+%!assert (logspace (0, Inf, 3), [1, Inf, Inf])
+%!assert (logspace (0, -Inf, 3), [1, 0, 0])
+%!assert (logspace (-Inf, 0, 3), [0, NaN, 1])
+%!assert (logspace (Inf, 0, 3), [Inf, NaN, 1])
+%!assert (logspace (Inf, -Inf, 3), [Inf, NaN, 0])
 
 ## Test input validation
 %!error logspace ()
--- a/scripts/general/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,6 @@
   %reldir%/del2.m \
   %reldir%/divergence.m \
   %reldir%/flip.m \
-  %reldir%/flipdim.m \
   %reldir%/fliplr.m \
   %reldir%/flipud.m \
   %reldir%/gradient.m \
--- a/scripts/general/nextpow2.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/nextpow2.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,7 +17,7 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {} nextpow2 (@var{x})
+## @deftypefn {} {@var{n} =} nextpow2 (@var{x})
 ## Compute the exponent for the smallest power of two larger than the input.
 ##
 ## For each element in the input array @var{x}, return the first integer
@@ -47,6 +47,8 @@
   endif
 
   [f, n] = log2 (abs (x));
+  idx = (n == 0);   # Find any failures of log2 function (n == 0)
+  n(idx) = f(idx);  # and copy over value.
   n(f == 0.5)--;
 
 endfunction
@@ -59,6 +61,15 @@
 %!assert (nextpow2 (-17), 5)
 %!assert (nextpow2 (-31), 5)
 %!assert (nextpow2 (1:17), [0 1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5])
+## Special cases
+%!assert (nextpow2 (0), 0)
+%!assert (nextpow2 (1), 0)
+%!assert (nextpow2 (Inf), Inf)
+%!assert (nextpow2 (-Inf), Inf)
+%!assert (nextpow2 (NaN), NaN)
+%!assert (nextpow2 ([1, Inf, 3, -Inf, 9, NaN]), [0, Inf, 2, Inf, 4, NaN])
 
+## Test input validation
 %!error nexpow2 ()
 %!error nexpow2 (1, 2)
+%!error <X must be numeric> nextpow2 ("t")
--- a/scripts/general/num2str.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/num2str.m	Thu Dec 20 17:18:56 2018 -0500
@@ -104,7 +104,7 @@
           ndgt = 0;  # All Inf or all zero array
         endif
 
-        if (any (x(valid) != fix (x(valid))))
+        if (ndgt > 15 || any (x(valid) != fix (x(valid))))
           ## Floating point input
           ndgt = max (ndgt + 5, 5);   # Keep at least 5 significant digits
           ndgt = min (ndgt, 16);      # Cap significant digits at 16
@@ -115,8 +115,6 @@
           if (any (! valid))
             ndgt = max (ndgt, 5);     # Allow space for Inf/NaN
           endif
-          ## FIXME: Integers must be masked to show only 16 significant digits
-          ##        See test case for bug #36133 below
           fmt = sprintf ("%%%d.0f", ndgt);
         endif
       else
@@ -190,6 +188,7 @@
 endfunction
 
 
+## Basic tests
 %!assert (num2str (123), "123")
 %!assert (num2str (1.23), "1.23")
 %!assert (num2str (123.456, 4), "123.5")
@@ -197,6 +196,7 @@
 %!assert (num2str (1.234 + 27.3i), "1.234+27.3i")
 %!assert (num2str ([true false true]), "1  0  1")
 
+## Exceptional values
 %!assert (num2str (19440606), "19440606")
 %!assert (num2str (2^33), "8589934592")
 %!assert (num2str (-2^33), "-8589934592")
@@ -222,7 +222,7 @@
 %! x = cat (3, m, -m);
 
 ## real case
-%!test
+%!test <*46770>
 %! y = num2str (x);
 %! assert (rows (y) == 3);
 %! assert (y, ["8  1  6 -8 -1 -6"
@@ -230,7 +230,7 @@
 %!             "4  9  2 -4 -9 -2"]);
 
 ## complex case
-%!test
+%!test <*46770>
 %! x(1,1,2) = -8+2i;
 %! y = num2str (x);
 %! assert (rows (y) == 3);
@@ -241,16 +241,26 @@
 ## Clear shared variables
 %!shared
 
-## FIXME: Integers greater than flintmax() - 1 should be masked to show just
-##        16 digits of precision.
-%!test <36133>
-%! assert (num2str (1e23), "100000000000000000000000");
+## Integers greater than 1e15 should switch to exponential notation
+%!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")
+## Mixed integer/floating point arrays
+%!assert <*36133> (num2str ([2.1, 1e23, pi]),
+%!                 "2.1  9.999999999999999e+22      3.141592653589793")
+
+## Large integers should not switch sign when printed due to overflow
+%!assert <*36121> (num2str (2.4e9, 15), "2400000000")
 
 ## Test for extra rows generated from newlines in format
 %!assert <*44864> (rows (num2str (magic (3), "%3d %3d %3d\n")), 3)
 
+## Test that string conversion of numeric objects results in characters
+## if the numbers are within range for ASCII.
 %!assert <*45174> (num2str ([65 66 67], "%s"), "ABC")
 
+## Test input validation
 %!error num2str ()
 %!error num2str (1, 2, 3)
 %!error <X must be a numeric> num2str ({1})
--- a/scripts/general/randi.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/randi.m	Thu Dec 20 17:18:56 2018 -0500
@@ -79,13 +79,6 @@
     endif
   endif
 
-  if (nargin > 1 && ischar (varargin{end}))
-    rclass = varargin{end};
-    varargin(end) = [];
-  else
-    rclass = "double";
-  endif
-
   ## Limit set by use of class double in rand(): Any consecutive integer in the
   ## range [-flintmax(), flintmax()] can be represented by a double.
   if ((abs (imax) >= flintmax ()) || (abs (imin) >= flintmax ()))
@@ -95,7 +88,35 @@
     error ("randi: integer range must be smaller than flintmax()-1");
   endif
 
-  ri = imin + floor ((imax - imin + 1) * rand (varargin{:}));
+  if (nargin > 1 && ischar (varargin{end}))
+    rclass = varargin{end};
+    varargin(end) = [];
+    nargin = nargin - 1;
+  else
+    rclass = "double";
+  endif
+
+  ## Expand dimension argument to at least 2-D for reshape
+  if (nargin == 1)
+    varargin = {1, 1};
+  elseif (nargin == 2 && isscalar (varargin{1}))
+    varargin(2) = varargin(1);
+  endif
+    
+  ## Rejection Algorithm to guarantee unbiased results.  See bug #54619.
+  rng = (imax - imin) + 1;              # requested range
+  N = prod ([varargin{:}]);             # number of requested elements
+  K = floor ((flintmax () + 1) / rng);  # number of primary integers ...
+                                        # mapped to single output
+  p = (K*rng) / (flintmax () + 1);      # expected proportion of used primaries
+  
+  do  
+    M = ceil (N/p + 10*sqrt (N/p - N)); # number of requested primary integers
+    r_prim = floor (rand (M,1) * (flintmax () + 1));
+    r_prim = r_prim(r_prim < K*rng);
+  until (numel (r_prim) >= N)           # should practically always be true
+  
+  ri = imin + floor (reshape (r_prim(1:N), varargin{:}) / K);
 
   if (! strcmp (rclass, "double"))
     if (strfind (rclass, "int"))
--- a/scripts/general/rat.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/rat.m	Thu Dec 20 17:18:56 2018 -0500
@@ -1,3 +1,4 @@
+## Copyright (C) 2018 Rik Wehbring
 ## Copyright (C) 2001-2018 Paul Kienzle
 ##
 ## This file is part of Octave.
@@ -17,41 +18,74 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{s} =} rat (@var{x}, @var{tol})
-## @deftypefnx {} {[@var{n}, @var{d}] =} rat (@var{x}, @var{tol})
+## @deftypefn  {} {@var{s} =} rat (@var{x})
+## @deftypefnx {} {@var{s} =} rat (@var{x}, @var{tol})
+## @deftypefnx {} {[@var{n}, @var{d}] =} rat (@dots{})
+##
+## Find a rational approximation of @var{x} to within the tolerance defined by
+## @var{tol}.
 ##
-## Find a rational approximation to @var{x} within the tolerance defined by
-## @var{tol} using a continued fraction expansion.
+## If unspecified, the default tolerance is @code{1e-6 * norm (@var{x}(:), 1)}.
+##
+## When called with one output argument, return a string containing a
+## continued fraction expansion (multiple terms).
+##
+## When called with two output arguments, return numeric matrices for the
+## numerator and denominator of a fractional representation of @var{x} such
+## that @code{@var{x} = @var{n} ./ @var{d}}.
 ##
 ## For example:
 ##
 ## @example
 ## @group
-## rat (pi) = 3 + 1/(7 + 1/16) = 355/113
-## rat (e) = 3 + 1/(-4 + 1/(2 + 1/(5 + 1/(-2 + 1/(-7)))))
-##         = 1457/536
+## @var{s} = rat (pi)
+## @result{} s = 3 + 1/(7 + 1/16)
+##
+## [@var{n}, @var{d}] = rat (pi)
+## @result{} @var{n} =  355
+## @result{} @var{d} =  113
+##
+## @var{n}/@var{d} - pi
+## @result{} 0.00000026676
 ## @end group
 ## @end example
 ##
-## When called with two output arguments return the numerator and denominator
-## separately as two matrices.
-## @seealso{rats}
+## Programming Note: With one output @code{rat} produces a string which is a
+## continued fraction expansion.  To produce a string which is a simple
+## fraction (one numerator, one denominator) use @code{rats}.
+##
+## @seealso{rats, format}
 ## @end deftypefn
 
-function [n,d] = rat (x,tol)
+function [n, d] = rat (x, tol)
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
 
-  if (nargin != [1,2] || nargout > 2)
-    print_usage ();
+  if (! isfloat (x))
+    error ("rat: X must be a single or double array");
+  endif
+
+  ## FIXME: This test should be removed when complex support is added.
+  ##        See bug #55198.
+  if (iscomplex (x))
+    error ("rat: X must be a real, not complex, array");
   endif
 
   y = x(:);
 
   ## Replace Inf with 0 while calculating ratios.
-  y(isinf(y)) = 0;
+  inf_idx = isinf (x);
+  y(inf_idx(:)) = 0;
 
-  ## default norm
-  if (nargin < 2)
-    tol = 1e-6 * norm (y,1);
+  if (nargin == 1)
+    ## default norm
+    tol = 1e-6 * norm (y, 1);
+  else
+    if (! (isscalar (tol) && isnumeric (tol) && tol > 0))
+      error ("rat: TOL must be a numeric scalar > 0");
+    endif
   endif
 
   ## First step in the approximation is the integer portion
@@ -59,18 +93,17 @@
   ## First element in the continued fraction.
   n = round (y);
   d = ones (size (y));
-  frac = y-n;
+  frac = y - n;
   lastn = ones (size (y));
   lastd = zeros (size (y));
 
-  nd = ndims (y);
   nsz = numel (y);
   steps = zeros ([nsz, 0]);
 
   ## Grab new factors until all continued fractions converge.
   while (1)
     ## Determine which fractions have not yet converged.
-    idx = find (abs (y-n./d) >= tol);
+    idx = find (y != 0 & abs (y - n./d) >= tol);
     if (isempty (idx))
       if (isempty (steps))
         steps = NaN (nsz, 1);
@@ -79,87 +112,115 @@
     endif
 
     ## Grab the next step in the continued fraction.
-    flip = 1./frac(idx);
+    flip = 1 ./ frac(idx);
     ## Next element in the continued fraction.
     step = round (flip);
 
     if (nargout < 2)
       tsteps = NaN (nsz, 1);
-      tsteps (idx) = step;
+      tsteps(idx) = step;
       steps = [steps, tsteps];
     endif
 
-    frac(idx) = flip-step;
+    frac(idx) = flip - step;
 
     ## Update the numerator/denominator.
-    nextn = n;
-    nextd = d;
+    savedn = n;
+    savedd = d;
     n(idx) = n(idx).*step + lastn(idx);
     d(idx) = d(idx).*step + lastd(idx);
-    lastn = nextn;
-    lastd = nextd;
+    lastn = savedn;
+    lastd = savedd;
   endwhile
 
-  if (nargout == 2)
-    ## Move the minus sign to the top.
+  if (nargout <= 1)
+    ## string output
+    n = "";
+    nsteps = columns (steps);
+    ## Loop over all values in array
+    for i = 1:nsz
+
+      if (inf_idx(i))
+        s = ifelse (x(i) > 0, "Inf", "-Inf");
+      elseif (y(i) == 0)
+        s = "0";
+      else
+        ## Create partial fraction expansion of one value
+        s = [int2str(y(i)), " "];
+        j = 1;
+
+        while (true)
+          step = steps(i, j++);
+          if (isnan (step))
+            break;
+          endif
+          if (j > nsteps || isnan (steps(i, j)))
+            if (step < 0)
+              s = [s(1:end-1), " + 1/(", int2str(step), ")"];
+            else
+              s = [s(1:end-1), " + 1/", int2str(step)];
+            endif
+            break;
+          else
+            s = [s(1:end-1), " + 1/(", int2str(step), ")"];
+          endif
+        endwhile
+        s = [s, repmat(")", 1, j-2)];
+      endif
+
+      ## Append result to output
+      n_nc = columns (n);
+      s_nc = columns (s);
+      if (n_nc > s_nc)
+        s(:, s_nc+1:n_nc) = " ";
+      elseif (s_nc > n_nc && n_nc != 0)
+        n(:, n_nc+1:s_nc) = " ";
+      endif
+      n = cat (1, n, s);
+    endfor
+  else
+    ## numerator, denominator output
+
+    ## Move the minus sign to the numerator.
     n .*= sign (d);
     d = abs (d);
 
-    ## Return the same shape as you receive.
+    ## Return the same shape as the input.
     n = reshape (n, size (x));
     d = reshape (d, size (x));
 
     ## Use 1/0 for Inf.
-    n(isinf (x)) = sign (x(isinf (x)));
-    d(isinf (x)) = 0;
-
-    ## Reshape the output.
-    n = reshape (n, size (x));
-    d = reshape (d, size (x));
-  else
-    n = "";
-    nsteps = columns (steps);
-    for i = 1: nsz
-      s = [int2str(y(i))," "];
-      j = 1;
-
-      while (true)
-        step = steps(i, j++);
-        if (isnan (step))
-          break;
-        endif
-        if (j > nsteps || isnan (steps(i, j)))
-          if (step < 0)
-            s = [s(1:end-1), " + 1/(", int2str(step), ")"];
-          else
-            s = [s(1:end-1), " + 1/", int2str(step)];
-          endif
-          break;
-        else
-          s = [s(1:end-1), " + 1/(", int2str(step), ")"];
-        endif
-      endwhile
-      s = [s, repmat(")", 1, j-2)];
-      n_nc = columns (n);
-      s_nc = columns (s);
-      if (n_nc > s_nc)
-        s(:,s_nc+1:n_nc) = " ";
-      elseif (s_nc > n_nc && n_nc != 0)
-        n(:,n_nc+1:s_nc) = " ";
-      endif
-      n = cat (1, n, s);
-    endfor
+    n(inf_idx) = sign (x(inf_idx));
+    d(inf_idx) = 0;
   endif
 
 endfunction
 
 
+%!assert (rat (pi), "3 + 1/(7 + 1/16)")
+%!assert (rat (pi, 1e-2), "3 + 1/7")
+## Test exceptional values
+%!assert (rat (0), "0")
+%!assert (rat (Inf), "Inf")
+%!assert (rat (-Inf), "-Inf")
+
 %!test
 %! [n, d] = rat ([0.5, 0.3, 1/3]);
 %! assert (n, [1, 3, 1]);
 %! assert (d, [2, 10, 3]);
+## Test exceptional values
+%!test
+%! [n, d] = rat ([Inf, 0, -Inf]);
+%! assert (n, [1, 0, -1]);
+%! assert (d, [0, 1, 0]);
 
 %!assert <*43374> (eval (rat (0.75)), [0.75])
 
+## Test input validation
 %!error rat ()
 %!error rat (1, 2, 3)
+%!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")
+%!error <TOL must be a numeric scalar> rat (1, [1 2])
+%!error <TOL must be a numeric scalar . 0> rat (1, -1)
--- a/scripts/general/sortrows.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/general/sortrows.m	Thu Dec 20 17:18:56 2018 -0500
@@ -65,7 +65,7 @@
   default_mode = "ascend";
   reverse_mode = "descend";
 
-  if (issparse (A))
+  if (issparse (A) || iscell (A))
     ## FIXME: Eliminate this case once __sort_rows_idx__ is fixed to
     ##        handle sparse matrices.
     if (nargin == 1)
@@ -97,7 +97,7 @@
     indices = [1:columns(m)]';
     mode(1:columns(m)) = {default_mode};
   else
-    for j = 1:length (c);
+    for j = 1:length (c)
       if (c(j) < 0)
         mode{j} = reverse_mode;
       else
@@ -114,8 +114,12 @@
   indices = flipud (indices);
   mode = flipud (mode');
   i = [1:rows(m)]';
-  for j = 1:length (indices);
-    [~, idx] = sort (m(i, indices(j)), mode{j});
+  for j = 1:length (indices)
+    M = m(i, indices(j));
+    if (iscell (M) && ! iscellstr (M))
+      M = cell2mat (M);
+    endif
+    [~, idx] = sort (M, mode{j});
     i = i(idx);
   endfor
 
@@ -144,6 +148,13 @@
 %! assert (x, full (sx));
 %! assert (idx, sidx);
 
+%!test <*42523>
+%! C = {1, 2, "filename1";
+%!      3, 4, "filename2";
+%!      5, 6, "filename3"};
+%! C2 = sortrows (C, -1);
+%! assert (C2, flipud (C));
+
 ## Test input validation
 %!error sortrows ()
 %!error sortrows (1, 2, 3)
--- a/scripts/geometry/convhull.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/geometry/convhull.m	Thu Dec 20 17:18:56 2018 -0500
@@ -18,12 +18,21 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{H} =} convhull (@var{x}, @var{y})
-## @deftypefnx {} {@var{H} =} convhull (@var{x}, @var{y}, @var{options})
-## Compute the convex hull of the set of points defined by the
-## arrays @var{x} and @var{y}.  The hull @var{H} is an index vector into
-## the set of points and specifies which points form the enclosing hull.
+## @deftypefnx {} {@var{H} =} convhull (@var{x}, @var{y}, @var{z})
+## @deftypefnx {} {@var{H} =} convhull (@var{x})
+## @deftypefnx {} {@var{H} =} convhull (@dots{}, @var{options})
+## @deftypefnx {} {[@var{H}, @var{V}] =} convhull (@dots{})
+## Compute the convex hull of a 2-D or 3-D set of points.
 ##
-## An optional third argument, which must be a string or cell array of strings,
+## The hull @var{H} is a linear index vector into the original set of points
+## that specifies which points form the enclosing hull.  For 2-D inputs only,
+## the output is ordered in a counter-clockwise manner around the hull.
+##
+## The input @var{x} may also be a matrix with two or three columns where the
+## first column contains x-data, the second y-data, and the optional third
+## column contains z-data.
+##
+## An optional final argument, which must be a string or cell array of strings,
 ## contains options passed to the underlying qhull command.
 ## See the documentation for the Qhull library for details
 ## @url{http://www.qhull.org/html/qh-quick.htm#options}.
@@ -34,55 +43,127 @@
 ## To append user options to the defaults it is necessary to repeat the
 ## default arguments in @var{options}.  Use a null string to pass no arguments.
 ##
+## If the second output @var{V} is requested the volume of the enclosing
+## convex hull is calculated.
+##
 ## @seealso{convhulln, delaunay, voronoi}
 ## @end deftypefn
 
-## Author: Kai Habel <kai.habel@gmx.de>
+function [H, V] = convhull (varargin)
 
-function H = convhull (x, y, options)
-
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 1 || nargin > 4)
     print_usage ();
   endif
 
-  ## convhulln expects column vectors
-  x = x(:);
-  y = y(:);
+  z = [];
+  options = [];
+
+  switch (nargin)
+
+    case 1
+      if (! ismatrix (varargin{1})
+          || (columns (varargin{1}) != 2 && columns (varargin{1}) != 3))
+          error ("convhull: X must be a matrix with 2 or 3 columns");
+      else
+        x = varargin{1}(:,1);
+        y = varargin{1}(:,2);
+        if (columns (varargin{1}) == 3)
+          z = varargin{1}(:,3);
+        endif
+      endif
+
+    case 2
+      if (isnumeric (varargin{2}))
+        x = varargin{1};
+        y = varargin{2};
+      elseif (! (ischar (varargin{2}) || iscellstr (varargin{2})))
+        error ("convhull: OPTIONS must be a string or cell array of strings");
+      else
+        options = varargin{2};
+        ncols = columns (varargin{1});
+
+        if (! ismatrix (varargin{1}) || (ncols != 2 && ncols != 3))
+          error ("convhull: X must be a matrix with 2 or 3 columns");
+        else
+          x = varargin{1}(:,1);
+          y = varargin{1}(:,2);
+          if (ncols == 3)
+            z = varargin{1}(:,3);
+          endif
+        endif
+      endif
 
-  if (length (x) != length (y))
-    error ("convhull: X and Y must have the same size");
-  elseif (nargin == 3 && ! (ischar (options) || iscellstr (options)))
-    error ("convhull: OPTIONS must be a string or cell array of strings");
-  endif
+    case 3
+      if (isnumeric (varargin{3}))
+        x = varargin{1};
+        y = varargin{2};
+        z = varargin{3};
+      elseif (! (ischar (varargin{3}) || iscellstr (varargin{3})))
+        error ("convhull: OPTIONS must be a string or cell array of strings");
+      else
+        x = varargin{1};
+        y = varargin{2};
+        options = varargin{3};
+      endif
+
+    case 4
+      x = varargin{1};
+      y = varargin{2};
+      z = varargin{3};
+      options = varargin{4};
+
+      if (! (ischar (options) || iscellstr (options)))
+        error ("convhull: OPTIONS must be a string or cell array of strings");
+      endif
 
-  if (nargin == 2)
-    i = convhulln ([x, y]);
+  endswitch
+
+  if (isempty (z))
+    x = x(:);  y = y(:);
+    if (! size_equal (x, y))
+      error ("convhull: X and Y must be the same size");
+    endif
+    if (nargout > 1)
+      [Htmp, V] = convhulln ([x, y], options);
+    else
+      Htmp = convhulln ([x, y], options);
+    endif
   else
-    i = convhulln ([x, y], options);
+    x = x(:);  y = y(:);  z = z(:);
+    if (! size_equal (x, y, z))
+      error ("convhull: X, Y, and Z must be the same size");
+    endif
+    if (nargout > 1)
+      [H, V] = convhulln ([x, y, z], options);
+    else
+      H = convhulln ([x, y, z], options);
+    endif
   endif
 
-  n = rows (i);
-  i = i'(:);
-  H = zeros (n + 1, 1);
-
-  H(1) = i(1);
-  next_i = i(2);
-  i(2) = 0;
-  for k = 2:n
-    next_idx = find (i == next_i);
+  if (isempty (z))
+    ## Order 2-D convex hull in a counter-clockwise manner.
+    n = rows (Htmp);
+    Htmp = Htmp.'(:);
+    H = zeros (n + 1, 1);
 
-    if (rem (next_idx, 2) == 0)
-      H(k) = i(next_idx);
-      next_i = i(next_idx - 1);
-      i(next_idx - 1) = 0;
-    else
-      H(k) = i(next_idx);
-      next_i = i(next_idx + 1);
-      i(next_idx + 1) = 0;
-    endif
-  endfor
+    H(1) = Htmp(1);
+    next_pt = Htmp(2);
+    Htmp(2) = 0;
+    for k = 2:n
+      next_idx = find (Htmp == next_pt);
+      H(k) = Htmp(next_idx);
 
-  H(n + 1) = H(1);
+      if (rem (next_idx, 2) == 0)
+        next_pt =  Htmp(next_idx - 1);
+         Htmp(next_idx - 1) = 0;
+      else
+        next_pt = Htmp(next_idx + 1);
+         Htmp(next_idx + 1) = 0;
+      endif
+    endfor
+
+    H(n + 1) = H(1);
+  endif
 
 endfunction
 
@@ -100,4 +181,17 @@
 %! y = abs (sin (x));
 %! assert (convhull (x, y), [1;7;13;12;11;10;4;3;2;1]);
 
-## FIXME: Need input validation tests
+%!testif HAVE_QHULL
+%! [~, V] = convhull ([0,2,2,0], [0,0,1,1]);
+%! assert (V == 2);
+
+## Input validation tests
+%!error convhull ()
+%!error 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 <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 <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	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/geometry/delaunay.m	Thu Dec 20 17:18:56 2018 -0500
@@ -44,7 +44,7 @@
 ## first column contains x-data, the second y-data, and the optional third
 ## column contains z-data.
 ##
-## The optional last argument, which must be a string or cell array of strings,
+## An optional final argument, which must be a string or cell array of strings,
 ## contains options passed to the underlying qhull command.
 ## See the documentation for the Qhull library for details
 ## @url{http://www.qhull.org/html/qh-quick.htm#options}.
@@ -69,8 +69,6 @@
 ## @seealso{delaunayn, convhull, voronoi, triplot, trimesh, tetramesh, trisurf}
 ## @end deftypefn
 
-## Author: Kai Habel <kai.habel@gmx.de>
-
 function tri = delaunay (varargin)
 
   if (nargin < 1 || nargin > 4)
@@ -141,15 +139,17 @@
   endswitch
 
   if (isempty (z))
+    x = x(:);  y = y(:);
     if (! size_equal (x, y))
       error ("delaunay: X and Y must be the same size");
     endif
-    tri = delaunayn ([x(:), y(:)], options);
+    tri = delaunayn ([x, y], options);
   else
+    x = x(:);  y = y(:);  z = z(:);
     if (! size_equal (x, y, z))
       error ("delaunay: X, Y, and Z must be the same size");
     endif
-    tri = delaunayn ([x(:), y(:), z(:)], options);
+    tri = delaunayn ([x, y, z], options);
   endif
 
 endfunction
@@ -176,7 +176,8 @@
 %!testif HAVE_QHULL
 %! x = [-1, 0, 1, 0];
 %! y = [0, 1, 0, -1];
-%! assert (sortrows (sort (delaunay ([x(:) y(:)]), 2)), [1,2,4;2,3,4]);
+%! mat = [x(:), y(:)];
+%! assert (sortrows (sort (delaunay (mat), 2)), [1,2,4;2,3,4]);
 
 %!testif HAVE_QHULL
 %! x = [-1, 0, 1, 0, 0];
--- a/scripts/geometry/delaunayn.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/geometry/delaunayn.m	Thu Dec 20 17:18:56 2018 -0500
@@ -66,23 +66,37 @@
   endif
 
   ## Try to remove the zero volume simplices.  The volume of the i-th simplex is
-  ## given by abs(det(pts(T(i,1:end-1),:)-pts(T(i,2:end),:)))/prod(1:n)
+  ## given by abs(det(pts(T(i,1:end-1),:)-pts(T(i,2:end),:)))/factorial(ndim+1)
   ## (reference http://en.wikipedia.org/wiki/Simplex).  Any simplex with a
   ## relative volume less than some arbitrary criteria is rejected.  The
   ## criteria we use is the volume of the simplex corresponding to an
   ## orthogonal simplex is equal edge length all equal to the edge length of
   ## the original simplex.  If the relative volume is 1e3*eps then the simplex
   ## is rejected.  Note division of the two volumes means that the factor
-  ## prod(1:n) is dropped.
-  idx = [];
-  [nt, n] = size (T);
-  ## FIXME: Vectorize this for loop or convert delaunayn to .oct function
-  for i = 1:nt
-    X = pts(T(i,1:end-1),:) - pts(T(i,2:end),:);
-    if (abs (det (X)) / sqrt (sumsq (X, 2)) < tol)
-      idx(end+1) = i;
-    endif
-  endfor
+  ## factorial(ndim+1) is dropped.
+  [nt, nd] = size (T);
+  if (nd == 3)
+    ## 2-D case
+    np = rows (pts);
+    ptsz = [pts, zeros(np, 1)];
+    p1 = ptsz(T(:,1), :);
+    p2 = ptsz(T(:,2), :);
+    p3 = ptsz(T(:,3), :);
+    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;
+  else
+    ## FIXME: Vectorize this for loop or convert delaunayn to .oct function
+    idx = [];
+    for i = 1:nt
+      X = pts(T(i,1:end-1),:) - pts(T(i,2:end),:);
+      if (abs (det (X)) / sqrt (sumsq (X, 2)) < tol)
+        idx(end+1) = i;
+      endif
+    endfor
+  endif
   T(idx,:) = [];
 
 endfunction
--- a/scripts/gui/errordlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/errordlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,24 +17,25 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{h} =} errordlg ()
-## @deftypefnx {} {@var{h} =} errordlg (@var{msg})
-## @deftypefnx {} {@var{h} =} errordlg (@var{msg}, @var{title})
-## @deftypefnx {} {@var{h} =} errordlg (@var{msg}, @var{title}, @var{createmode})
+## @deftypefn  {} {} errordlg ()
+## @deftypefnx {} {} errordlg (@var{msg})
+## @deftypefnx {} {} errordlg (@var{msg}, @var{title})
+## @deftypefnx {} {} errordlg (@var{msg}, @var{title}, @var{opt})
+## @deftypefnx {} {@var{h} =} errordlg (@dots{})
 ## Display an error dialog box with error message @var{msg} and caption
 ## @var{title}.
 ##
-## The default error message is @qcode{"This is the default error string."} and
-## the default caption is @qcode{"Error Dialog"}.
+## The default error message is @qcode{"This is the default error string.@:"}
+## and the default caption is @qcode{"Error Dialog"}.
 ##
 ## The error message may have multiple lines separated by newline characters
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
-## The return value @var{h} is always 1.
+## The third optional argument @var{opt} controls the behavior of the dialog.
+## See @code{msgbox} for details.
 ##
-## Compatibility Note: The optional argument @var{createmode} is accepted for
-## @sc{matlab} compatibility, but is not implemented.  See @code{msgbox} for
-## details.
+## The return value @var{h} is a handle to the figure object used for
+## building the dialog.
 ##
 ## Examples:
 ##
@@ -47,32 +48,37 @@
 ## @end group
 ## @end example
 ##
-## @seealso{helpdlg, inputdlg, listdlg, msgbox, questdlg, warndlg}
+## @seealso{helpdlg, warndlg, msgbox, inputdlg, listdlg, questdlg}
 ## @end deftypefn
 
-function retval = errordlg (varargin)
+function h = errordlg (varargin)
 
-  narginchk (0, 3);
+  msg = "This is the default error.";
+  tit = "Error Dialog";
+  opt = "non-modal";
+
+  nargs = numel (varargin);
 
-  msg = "This is the default error string.";
-  title = "Error Dialog";
-
-  if (nargin > 0)
+  if (nargs > 3)
+    print_usage ();
+  elseif (nargs == 1)
+    msg = varargin{1};
+  elseif (nargs == 2)
     msg = varargin{1};
-  endif
-  if (nargin > 1)
-    title = varargin{2};
+    tit = varargin{2};
+  elseif (nargs == 3)
+    msg = varargin{1};
+    tit = varargin{2};
+    opt = varargin{3};
   endif
 
-  if (nargin < 3)
-    retval = msgbox (msg, title, "error");
-  else
-    retval = msgbox (msg, title, "error", varargin{3});
+  htmp = msgbox (msg, tit, "error", opt);
+
+  if (nargout)
+    h = htmp;
   endif
 
 endfunction
 
-
-%!error errordlg (1, 2, 3, 4)
-%!error <MSG must be a character string> errordlg (1)
-%!error <TITLE must be a character string> errordlg ("msg", 1)
+## No BIST tests.  This function just dispatches to msgbox().
+%!assert (1)
--- a/scripts/gui/helpdlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/helpdlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,19 +17,21 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{h} =} helpdlg ()
-## @deftypefnx {} {@var{h} =} helpdlg (@var{msg})
-## @deftypefnx {} {@var{h} =} helpdlg (@var{msg}, @var{title})
+## @deftypefn  {} {} helpdlg ()
+## @deftypefnx {} {} helpdlg (@var{msg})
+## @deftypefnx {} {} helpdlg (@var{msg}, @var{title})
+## @deftypefnx {} {@var{h} =} helpdlg (@dots{})
 ## Display a help dialog box with help message @var{msg} and caption
 ## @var{title}.
 ##
-## The default help message is @qcode{"This is the default help string."} and
-## the default caption is @qcode{"Help Dialog"}.
+## The default help message is @qcode{"This is the default help string.@:"}
+## and the default caption is @qcode{"Help Dialog"}.
 ##
 ## The help message may have multiple lines separated by newline characters
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
-## The return value @var{h} is always 1.
+## The return value @var{h} is a handle to the figure object used for
+## building the dialog.
 ##
 ## Examples:
 ##
@@ -42,28 +44,33 @@
 ## @end group
 ## @end example
 ##
-## @seealso{errordlg, inputdlg, listdlg, msgbox, questdlg, warndlg}
+## @seealso{errordlg, warndlg, msgbox, inputdlg, listdlg, questdlg}
 ## @end deftypefn
 
-function retval = helpdlg (varargin)
+function h = helpdlg (varargin)
 
-  narginchk (0, 2);
+  msg = "This is the default help.";
+  tit = "Help Dialog";
+  opt = "non-modal";
+
+  nargs = numel (varargin);
 
-  msg = "This is the default help string.";
-  title = "Help Dialog";
-
-  if (nargin > 0)
+  if (nargs > 2)
+    print_usage ();
+  elseif (nargs == 1)
     msg = varargin{1};
-  endif
-  if (nargin > 1)
-    title = varargin{2};
+  elseif (nargs == 2)
+    msg = varargin{1};
+    tit = varargin{2};
   endif
 
-  retval = msgbox (msg, title, "help");
+  htmp = msgbox (msg, tit, "help", opt);
+
+  if (nargout)
+    h = htmp;
+  endif
 
 endfunction
 
-
-%!error helpdlg (1, 2, 3)
-%!error <MSG must be a character string> helpdlg (1)
-%!error <TITLE must be a character string> helpdlg ("msg", 1)
+## No BIST tests.  This function just dispatches to msgbox().
+%!assert (1)
--- a/scripts/gui/inputdlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/inputdlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -40,15 +40,20 @@
 ## Specifies the size of the text fields and can take three forms:
 ##
 ## @enumerate
-## @item a scalar value which defines the number of rows used for each text field.
+## @item a scalar value which defines the number of rows used for each text
+## field.
 ##
-## @item a vector which defines the individual number of rows used for each text field.
+## @item a vector which defines the individual number of rows used for each
+## text field.
 ##
-## @item a matrix which defines the individual number of rows and columns used for each text field.  In the matrix each row describes a single text field.  The first column specifies the number of input rows to use and the second column specifies the text field width.
+## @item a matrix which defines the individual number of rows and columns used
+## for each text field.  In the matrix each row describes a single text field.
+## The first column specifies the number of input rows to use and the second
+## column specifies the text field width.
 ## @end enumerate
 ##
 ## @item defaults
-## A list of default values to place in each text fields.  It must be a cell
+## A list of default values to place in each text field.  It must be a cell
 ## array of strings with the same size as @var{prompt}.
 ##
 ## @item options
@@ -229,11 +234,11 @@
 %! disp ('- test inputdlg with vector for a single item.');
 %! prompt = {'enter x value'};
 %! default = {1};
-%! answer = inputdlg (prompt,'Enter value', [1 10], default);
+%! answer = inputdlg (prompt, 'Enter value', [1 10], default);
 %! if (isempty (answer))
 %!   helpdlg ('Canceled by user', 'Information');
 %! else
-%!   helpdlg (sprintf ('answer = %d', str2num(answer{1})), 'answer');
+%!   helpdlg (sprintf ('answer = %d', str2num (answer{1})), 'answer');
 %! endif
 
 %!error inputdlg (1, 2, 3, 4, 5, 6)
--- a/scripts/gui/listdlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/listdlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -28,30 +28,32 @@
 ## otherwise it is 0 and @var{sel} is empty.
 ##
 ## Input arguments are specified in form of @var{key}, @var{value} pairs.
-## The @qcode{"ListString"} argument pair must be specified.
+## The @qcode{"ListString"} argument pair @strong{must} be specified.
 ##
 ## Valid @var{key} and @var{value} pairs are:
 ##
 ## @table @asis
 ## @item @qcode{"ListString"}
-## a cell array of strings with the contents of the list.
+## a cell array of strings specifying the items to list in the dialog.
 ##
 ## @item @qcode{"SelectionMode"}
-## can be either @qcode{"Single"} or @qcode{"Multiple"} (default).
+## can be either @qcode{"Single"} (only one item may be selected at a time) or
+## @qcode{"Multiple"} (default).
 ##
 ## @item @qcode{"ListSize"}
-## a vector with two elements @var{width} and @var{height} defining the size
-## of the list field in pixels.  Default is [160 300].
+## a two-element vector @code{[@var{width}, @var{height}]} specifying the size
+## of the list field in pixels.  The default is [160, 300].
 ##
 ## @item @qcode{"InitialValue"}
-## a vector containing 1-based indices of preselected elements.
-## Default is 1 (first item).
+## a vector containing 1-based indices of elements which will be pre-selected
+## when the list dialog is first displayed.
+## The default is 1 (first item).
 ##
 ## @item @qcode{"Name"}
 ## a string to be used as the dialog caption.  Default is "".
 ##
 ## @item @qcode{"PromptString"}
-## a cell array of strings to be displayed above the list field.
+## a cell array of strings to be displayed above the list of items.
 ## Default is @{@}.
 ##
 ## @item @qcode{"OKString"}
@@ -125,7 +127,7 @@
   endfor
 
   if (isempty (listcell))
-    error ("listdlg: ListString must not be empty");
+    error ('listdlg: "ListString" property must not be empty');
   endif
 
   ## make sure listcell strings are a cell array
@@ -142,51 +144,52 @@
 
   ## validate selection mode
   if (! strcmp (selmode, "multiple") && ! strcmp (selmode, "single"))
-    error ("listdlg: invalid SelectionMode");
+    error ('listdlg: "SelectionMode" must be "single" or "multiple"');
   endif
 
-  if (__octave_link_enabled__ ())
-    [sel, ok] = __octave_link_list_dialog__ (listcell, selmode, listsize,
-                                             initialvalue, name, prompt,
-                                             okstring, cancelstring);
-  else
+  if (! __octave_link_enabled__ ())
     error ("listdlg is not available in this version of Octave");
   endif
 
+  [sel, ok] = __octave_link_list_dialog__ (listcell, selmode, listsize,
+                                           initialvalue, name, prompt,
+                                           okstring, cancelstring);
+
 endfunction
 
 
 %!demo
-%! disp ("- test listdlg with selectionmode single. No caption, no prompt.");
-%! itemlist = {"An item \\alpha", "another", "yet another"};
+%! disp ('- test listdlg with "SelectionMode"="single".  No caption, no prompt.');
+%! itemlist = {"An item", "another", "yet another"};
 %! s = listdlg ("ListString", itemlist, "SelectionMode", "Single");
 %! imax = numel (s);
 %! for i=1:1:imax
-%!   disp (["Selected: ", num2str(i), ": ", itemlist{s(i)}]);
+%!   disp (["Selection #", num2str(i), ": ", itemlist{s(i)}]);
 %! endfor
 
 %!demo
-%! disp ("- test listdlg with selectionmode and preselection. Has caption and two lines prompt.");
-%! itemlist = {"An item \\alpha", "another", "yet another"};
+%! disp ('- test listdlg with "SelectionMode"="multiple" and pre-selection.  Has caption and two prompt lines.');
+%! itemlist = {"An item", "another", "yet another"};
 %! s = listdlg ("ListString", itemlist, ...
 %!              "SelectionMode", "Multiple", ...
 %!              "Name", "Selection Dialog", ...
-%!              "InitialValue", [1,2,3,4],
-%!              "PromptString", {"Select <b>an</b> item...", "...or <b>multiple</b> items"});
+%!              "InitialValue", [1,2,3],
+%!              "PromptString", {"Select <b>an</b> item...",
+%!                               "...or <b>multiple</b> items"});
 %! imax = numel (s);
 %! for i=1:1:imax
-%!   disp (["Selected: ", num2str(i), ": ", itemlist{s(i)}]);
+%!   disp (["Selection #", num2str(i), ": ", itemlist{s(i)}]);
 %! endfor
 
 %!demo
-%! disp ("- test listdlg with listsize.");
+%! disp ("- test listdlg with ListSize.");
 %! itemlist = {"Neutron", "Electron", "Quark", "Proton", "Neutrino"};
 %! s = listdlg ("ListString", itemlist,
 %!              "Name", "Bits and Pieces",
 %!              "ListSize", [200 75]);
 %! imax = numel (s);
 %! for i=1:1:imax
-%!   disp (["Selected: ", num2str(i), ": ", itemlist{s(i)}]);
+%!   disp (["Selection #", num2str(i), ": ", itemlist{s(i)}]);
 %! endfor
 
 ## Test input validation
@@ -194,6 +197,6 @@
 %!error listdlg ("SelectionMode")
 %!error <must occur in pairs> listdlg ("SelectionMode", "multiple", "Name")
 %!error <invalid KEY .FooBar.> listdlg ("FooBar", 1)
-%!error <ListString must not be empty> listdlg ("ListString", {})
-%!error <invalid SelectionMode>
+%!error <"ListString" property must not be empty> listdlg ("ListString", {})
+%!error <"SelectionMode" must be "single" or "multiple">
 %! listdlg ("ListString", {"A"}, "SelectionMode", "foobar");
--- a/scripts/gui/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -22,6 +22,7 @@
   %reldir%/inputdlg.m \
   %reldir%/isappdata.m \
   %reldir%/listdlg.m \
+  %reldir%/movegui.m \
   %reldir%/msgbox.m \
   %reldir%/questdlg.m \
   %reldir%/rmappdata.m \
@@ -36,6 +37,7 @@
   %reldir%/uipushtool.m \
   %reldir%/uiputfile.m \
   %reldir%/uiresume.m \
+  %reldir%/uitable.m \
   %reldir%/uitoggletool.m \
   %reldir%/uitoolbar.m \
   %reldir%/uiwait.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/movegui.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,238 @@
+## Copyright (C) 2018 Guillaume Flandin
+##
+## 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.
+## 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 filename COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} movegui
+## @deftypefnx {} {} movegui (@var{h})
+## @deftypefnx {} {} movegui (@var{pos})
+## @deftypefnx {} {} movegui (@var{h}, @var{pos})
+## @deftypefnx {} {} movegui (@var{h}, @var{event})
+## @deftypefnx {} {} movegui (@var{h}, @var{event}, @var{pos})
+## Move a figure specified by figure handle @var{h} to a position on the screen
+## defined by @var{pos}.
+##
+## @var{h} is a figure handle, or a handle to a graphics object.  In the latter
+## case, its parent figure will be used.  If unspecified, @var{h} will be
+## set to the handle of the relevant figure if a callback is being executed
+## (@code{gcbf}), otherwise it will be set to the handle of the current figure
+## (@code{gcf}).
+##
+## @var{pos} is either a two-value numeric vector or a string.  If @var{pos} is
+## numeric then it must be of the form @code{[h, v]} specifying the horizontal
+## and vertical offsets of the figure with respect to the screen.  A positive
+## value indicates the offset between the left (or bottom for the vertical
+## component) of the screen, and the left (or bottom) of the figure.  A
+## negative value indicates the offset between the right (or top) of the screen
+## and the right (or top) of the figure.
+##
+## Possible values for @var{pos} as a string are
+##
+## @table @code
+## @item north
+## Top center of the screen.
+##
+## @item south
+## Bottom center of the screen.
+##
+## @item east
+## Right center of the screen.
+##
+## @item west
+## Left center of the screen.
+##
+## @item northeast
+## Top right of the screen.
+##
+## @item northwest
+## Top left of the screen.
+##
+## @item southeast
+## Bottom right of the screen.
+##
+## @item southwest
+## Bottom left of the screen.
+##
+## @item center
+## Center of the screen.
+##
+## @item onscreen (default)
+## The figure will be minimally moved to be entirely visible on the screen,
+## with a 30 pixel extra padding from the sides of the screen.  This is the
+## default value if none is provided.
+## @end table
+##
+## @var{event} contains event data that will be ignored.  This construct
+## facilitates a call to movegui from a callback.
+##
+## @end deftypefn
+
+function movegui (varargin)
+
+  if (nargin > 3)
+    print_usage ();
+  endif
+
+  ## Default values for input arguments
+  h = [];
+  pos = "onscreen";
+
+  ## Get input arguments
+  if (nargin == 3)
+    h = varargin{1};
+    pos = varargin{3};
+  elseif (nargin == 2)
+    h = varargin{1};
+    pos = varargin{2};
+  elseif (nargin == 1)
+    if (ishghandle (varargin{1}) && isscalar (varargin{1}))
+      h = varargin{1};
+    else
+      pos = varargin{1};
+    endif
+  endif
+
+  ## Check figure handle
+  if (isempty (h))
+    h = gcbf ();
+    if (isempty (h))
+      h = gcf ();
+    endif
+  elseif (ishghandle (h))
+    h = ancestor (h, "figure");
+  else
+    error ("movegui: H must be a graphics handle");
+  endif
+
+  ## Get current position in pixels
+  units_fig = get (h, "units");
+  set (h, "units", "pixels");
+  fpos = get (h, "position");  # OuterPosition seems unreliable
+  set (h, "units", units_fig);
+
+  ## Get screen size in pixels
+  units_groot = get (groot (), "units");
+  set (groot (), "units", "pixels");
+  screen_size = get (groot (), "ScreenSize");
+  set (groot (), "units", units_groot);
+
+  ## Set default figure and screen border sizes [left, top, right, bottom]
+  f = [0, 90, 0, 30];
+  s = [0,  0, 0, 30];
+
+  ## Make sure figure is not larger than screen
+  fpos(1) = max (fpos(1), 1);
+  fpos(2) = max (fpos(2), 1);
+  fpos(3) = min (fpos(3), screen_size(3));
+  fpos(4) = min (fpos(4), screen_size(4));
+
+  ## Standard figure coordinates
+  ## left, middle, right
+  x = [s(1)+f(1), (screen_size(3)-fpos(3))/2, screen_size(3)-fpos(3)-s(3)-f(3)];
+  ## bottom, middle top
+  y = [s(4)+f(4), (screen_size(4)-fpos(4))/2, screen_size(4)-fpos(4)-s(2)-f(2)];
+
+  ## Compute new position
+  if (isnumeric (pos) && isreal (pos) && numel (pos) == 2)
+    fpos(1) = ifelse (pos(1) >= 0, pos(1), pos(1) + x(3));
+    fpos(2) = ifelse (pos(2) >= 0, pos(2), pos(2) + y(3));
+  elseif (ischar (pos))
+    switch (tolower (pos))
+      case "north"
+        fpos(1:2) = [x(2), y(3)];
+      case "south"
+        fpos(1:2) = [x(2), y(1)];
+      case "east"
+        fpos(1:2) = [x(3), y(2)];
+      case "west"
+        fpos(1:2) = [x(1), y(2)];
+      case "northeast"
+        fpos(1:2) = [x(3), y(3)];
+      case "northwest"
+        fpos(1:2) = [x(1), y(3)];
+      case "southeast"
+        fpos(1:2) = [x(3), y(1)];
+      case "southwest"
+        fpos(1:2) = [x(1), y(1)];
+      case "center"
+        fpos(1:2) = [x(2), y(2)];
+      case "onscreen"
+        if (fpos(1) > x(3))
+          fpos(1) = x(3) - 30;
+        endif
+        if (fpos(2) > y(3))
+          fpos(2) = y(3) - 30;
+        endif
+        fpos(1) = max(fpos(1), 30);
+        fpos(2) = max(fpos(2), 30);
+      otherwise
+        error ("movegui: invalid position");
+    endswitch
+  elseif (nargin == 2 && ! isempty (gcbo))
+    ## Ignore event data (from callback)
+    movegui (h);
+    return;
+  else
+    error ("movegui: invalid position");
+  endif
+
+  ## Move figure
+  set (h, "units", "pixels");
+  set (h, "position", fpos);
+  set (h, "units", units_fig);
+
+endfunction
+
+
+## FIXME: This test does not verify the results, only that the function
+##        can be invoked by different methods.
+%!test
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   pos = {[10 10], [10 -10], [-10 10], [-10 -10], [10 10]',...
+%!     "north", "east", "south", "west", ...
+%!     "northwest", "northeast", "southeast", "southwest", ...
+%!     "center", "onscreen"};
+%!   for i = 1:numel (pos)
+%!     movegui (h, pos{i});
+%!     movegui (pos{i});
+%!     movegui (h, struct ("evt", []), pos{i});
+%!   endfor
+%!   movegui ();
+%!   movegui (h);
+%! unwind_protect_cleanup
+%!   close (h);
+%! end_unwind_protect
+
+## Test input validation
+%!error movegui (1,2,3,4)
+%!error <H must be a graphics handle> movegui (-1, [1,1])
+%!error <invalid position>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   movegui (h, "foobar");
+%! unwind_protect_cleanup
+%!   close (h);
+%! end_unwind_protect
+%!error <invalid position>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   movegui (h, [1, 2, 3]);
+%! unwind_protect_cleanup
+%!   close (h);
+%! end_unwind_protect
--- a/scripts/gui/msgbox.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/msgbox.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,7 +20,9 @@
 ## @deftypefn  {} {@var{h} =} msgbox (@var{msg})
 ## @deftypefnx {} {@var{h} =} msgbox (@var{msg}, @var{title})
 ## @deftypefnx {} {@var{h} =} msgbox (@var{msg}, @var{title}, @var{icon})
-## @deftypefnx {} {@var{h} =} msgbox (@dots{}, @var{createmode})
+## @deftypefnx {} {@var{h} =} msgbox (@var{msg}, @var{title}, "custom", @var{cdata})
+## @deftypefnx {} {@var{h} =} msgbox (@var{msg}, @var{title}, "custom", @var{cdata}, @var{colormap})
+## @deftypefnx {} {@var{h} =} msgbox (@dots{}, @var{opt})
 ## Display @var{msg} using a message dialog box.
 ##
 ## The message may have multiple lines separated by newline characters ("\n"),
@@ -31,15 +33,41 @@
 ##
 ## The optional argument @var{icon} selects a dialog icon.
 ## It can be one of @qcode{"none"} (default), @qcode{"error"}, @qcode{"help"},
-## or @qcode{"warn"}.
+## @qcode{"warn"}, or @qcode{"custom"}.  The latter must be followed by an
+## image array @var{cdata}, and for indexed images the associated colormap.
+##
+## The final optional argument @var{opt} controls the behavior of the dialog.
+## If @var{opt} is a string, it may be one of
 ##
-## The return value is always 1.
+## @table @asis
+## @item @qcode{"non-modal"} (default)
+## The dialog is normal.
+##
+## @item @qcode{"modal"}
+## The dialog is displayed @qcode{"modal"} which means it prevents users from
+## interacting with any other GUI element until the dialog has been closed.
 ##
-## Compatibility Note: The optional argument @var{createmode} is accepted for
-## @sc{matlab} compatibility, but is not implemented.  A valid @var{createmode}
-## is either one of the character strings @qcode{"nonmodal"}, @qcode{"modal"},
-## or @qcode{"replace"}, or a structure containing a field
-## @qcode{"WindowStyle"} with one of the three character strings.
+## @item @qcode{"replace"}
+## If any dialogs already exist with the same title, the most recent is reused
+## and all others are closed.  The resulting dialog is set @qcode{"non-modal"}.
+## @end table
+##
+## If @var{opt} is a structure, it must contain fields @qcode{"WindowStyle"}
+## and @qcode{"Interpreter"}:
+##
+## @table @asis
+## @item @qcode{"WindowStyle"}
+## The value must be @qcode{"non-modal"}, @qcode{"modal"}, or
+## @qcode{"replace"}.  See above.
+##
+## @item @qcode{"Interpreter"}
+## Controls the @qcode{"interpreter"} property of the text object used for
+## displaying the message.  The value must be @qcode{"tex"} (default),
+## @qcode{"none"}, or @qcode{"latex"}.
+## @end table
+##
+## The return value @var{h} is a handle to the figure object used for building
+## the dialog.
 ##
 ## Examples:
 ##
@@ -50,7 +78,7 @@
 ## msgbox (@{"Some message", "with two lines."@});
 ## msgbox ("Some message for the user.", "Fancy caption");
 ##
-## % A message dialog box with error icon
+## ## A message dialog box with error icon
 ## msgbox ("Some message for the user.", "Fancy caption", "error");
 ## @end group
 ## @end example
@@ -58,70 +86,248 @@
 ## @seealso{errordlg, helpdlg, inputdlg, listdlg, questdlg, warndlg}
 ## @end deftypefn
 
-function retval = msgbox (msg, varargin)
-
-  narginchk (1, 4);
+function retval = msgbox (msg, tit = "", icon = "none", varargin)
 
-  if (! ischar (msg))
-    if (iscell (msg))
-      msg = sprintf ("%s\n", msg{:});
-      msg(end) = "";
+  ## Input checks
+  nargs = numel (varargin);
+  if (nargin < 1)
+    print_usage ();
+  elseif (! ischar (msg) && ! iscellstr (msg))
+    error ("msgbox: MSG must be a string or cell array of strings");
+  elseif (! ischar (tit))
+    error ("msgbox: TITLE must be a string");
+  elseif (isstruct (icon))
+    varargin{end+1} = icon;
+    nargs += 1;
+    icon = "none";
+  elseif (! any (strcmp (icon, {"help", "warn", "error", "none", "custom"})))
+    error ("msgbox: unhandled value for ICON data");
+  elseif (strcmp (icon, "custom"))
+    if (nargs < 1)
+      error ("msgbox: missing data for 'custom' icon");
+    endif
+    icon = struct ("cdata", varargin{1}, "colormap", []);
+    ## FIXME: This doesn't seem to be a robust test for RGB data.
+    if (! (ismatrix (icon.cdata) || size (icon.cdata, 3) == 3))
+      error ("msgbox: unhandled data for 'custom' icon");
+    elseif (size (icon.cdata, 3) == 1 && nargs > 1)
+      icon.colormap = varargin{2};
+      varargin(2) = [];
+      nargs--;
+    endif
+    varargin(1) = [];
+    nargs--;
+  endif
+
+  ## Window behavior and text interpreter
+  windowstyle = "normal";
+  interpreter = "tex";
+  if (nargs > 0)
+    if (isstruct (varargin{1}))
+      if (isfield (varargin{1}, "WindowStyle"))
+        windowstyle = varargin{1}.WindowStyle;
+      endif
+      if (isfield (varargin{1}, "Interpreter"))
+        interpreter = varargin{1}.Interpreter;
+      endif
     else
-      error ("MSG must be a character string or cellstr array");
+      windowstyle = varargin{1};
+    endif
+
+    if (! any (strcmp (windowstyle, {"non-modal", "modal", "replace"})))
+      error ("msgbox: unhandled value %s for OPT", windowstyle);
+    elseif (strcmp (windowstyle, "non-modal"))
+      windowstyle = "normal";
     endif
   endif
 
-  box_title = "";
-  box_icon = "none";
-
-  if (nargin > 1)
-    ## check last element to be a structure CREATEMODE
-    if (isstruct (varargin{end}) && isfield (varargin{end}, "WindowStyle"))
-      varargin{end} = varargin{end}.WindowStyle;
-    endif
-    ## print warning for unsupported CREATEMODE
-    if ((ischar (varargin{end}))
-        && (ismember (varargin{end}, {"nonmodal", "modal", "replace"})))
-      warning ("CREATEMODE %s is not yet supported", varargin{end});
-      nargin = nargin - 1;
-    elseif (nargin == 4)
-      error ("CREATEMODE is not a valid type");
+  ## Make a GUI element or print to console
+  if (__octave_link_enabled__ ())
+    retval = __msgbox__ (msg, tit, icon, windowstyle, interpreter);
+  else
+    if (iscellstr (msg))
+      msg = strjoin (msg, "\n");
     endif
-
-    if ((nargin > 1) && (! ischar (varargin{1})))
-      error ("TITLE must be a character string");
-    else
-      box_title = varargin{1};
+    if (isstruct (icon))
+      icon = "custom";
     endif
-
-    if (nargin > 2)
-      box_icon = varargin{2};
-      switch (box_icon)
-        case {"error", "help", "warn", "none"}
-          ## do nothing, all valid
-        case "custom"
-          warning ("custom icons are not yet supported");
-        otherwise
-          error ("ICON is not a valid type")
-      endswitch
-    endif
-  endif
-
-  ## make a GUI element or print to console
-  if (__octave_link_enabled__ ())
-    retval = __octave_link_message_dialog__ (box_icon, msg, box_title);
-  else
-    disp (sprintf ("\n%s:\t%s\n\t%s\n", upper (box_icon), box_title,
-      strrep (msg, "\n", "\n\t")));
+    disp (sprintf ("\n%s:\t%s\n\t%s\n",
+                   upper (icon), tit, strrep (msg, "\n", "\n\t")));
     retval = 1;
   endif
 
 endfunction
 
+function hf = __msgbox__ (msg, tit, icon, windowstyle, interpreter)
+
+  ## Prepare graphics objects
+  hf = [];
+  if (strcmp (windowstyle, "replace"))
+    windowstyle = "normal";
+    hf = findall (groot, "tag", "__dialog__", "-and", "name", tit);
+  endif
+
+  if (! isempty (hf))
+    if (numel (hf) > 1)
+      close (hf(2:end));
+    endif
+    hf = hf(1);
+    set (hf, "visible", "off", "windowstyle", "normal");
+  else
+    hf = dialog ("visible", "off", "name", tit, "tag", "__dialog__", ...
+                 "windowstyle", "normal");
+    if (! strcmp (graphics_toolkit (), "qt"))
+      graphics_toolkit (hf, "qt");
+    endif
+  endif
+
+  hp = uipanel (hf);
+
+  hax = axes ("parent", hp, "visible", "off", "units", "pixels", ...
+              "ydir", "reverse");
+
+  ht = text ("parent", hax, "string", msg, "units", "pixels", ...
+             "fontsize", 14, "interpreter", interpreter);
+
+  ## Hold default icons data in a persistent variable
+  persistent cdata = struct ("help", [], "warn", [], "error", []);
+
+  icon_name = "custom";
+  if (ischar (icon))
+    icon_name = icon;
+    icon = struct ("cdata", [], "colormap", []);
+    if (isfield (cdata, icon_name))
+      if (! isempty (cdata.(icon_name)))
+        icon.cdata = cdata.(icon_name);
+      else
+        if (strcmp (icon_name, "help"))
+          icon_name = "information";
+        elseif (strcmp (icon_name, "warn"))
+          icon_name = "warning";
+        endif
+        tmp = __octave_link_named_icon__ (["dialog-" icon_name]);
+        ## Fake transparency until the opengl renderer handles it:
+        ## RGB data from Qt are premultiplied, we only need to add the
+        ## background part
+        alpha = tmp(:,:,4);
+        tmp(:,:,4) = [];
+        backgnd = get (hp, "backgroundcolor");
+        tmp(:,:,1) += backgnd(1) * (255-alpha);
+        tmp(:,:,2) += backgnd(2) * (255-alpha);
+        tmp(:,:,3) += backgnd(3) * (255-alpha);
+        icon.cdata = tmp;
+        cdata.(icon_name) = tmp;
+
+      endif
+    endif
+  endif
+
+  ## Compute bbox in pixels
+  ax_sz = [200 60];
+  ax_margin = 12;
+  txt_margin = 20;
+  button_margin = 40;
+
+  extent = get (ht, "extent");
+  extent(3) += txt_margin;
+
+  im_sz = size (icon.cdata);
+
+  if (! isempty (icon.cdata))
+    extent(3) += im_sz(2);
+    extent(4) = max (extent(4), im_sz(1));
+  endif
+
+  ax_sz = max ([ax_sz; extent(3:4)+2*ax_margin]);
+
+  ## Align text left when there is an icon
+  text_offset = txt_margin;
+  if (! isempty (icon.cdata))
+    if (! isempty (icon.colormap))
+      set (hax, "colormap", icon.colormap)
+    endif
+    image ("parent", hax, "cdata", icon.cdata, "cdatamapping", "direct", ...
+           "xdata", [1 im_sz(2)], "ydata", [-(im_sz(1))/2+1 im_sz(1)/2]);
+    text_offset = im_sz(2) + txt_margin;
+  endif
+
+  ## Set objects position
+  wd = ax_sz(1);
+  hg = ax_sz(2) + button_margin;
+  center = get (0, "screensize")(3:4) / 2;
+
+  set (hf, "position", [center(1)-wd/2 center(2)-hg/2 wd hg]);
+
+  set (hax, "position", [0 button_margin ax_sz], ...
+       "xlim", [1 ax_sz(1)]-ax_margin, "ylim", [-ax_sz(2)/2 ax_sz(2)/2], ...
+       "units", "normalized");
+
+  set (ht, "units", "data", "position", [text_offset 0 0]);
+
+  hui = uicontrol ("string", "OK",
+                   "callback", @cb_callback,
+                   "keypressfcn", @cb_keypress,
+                   "position", [ax_sz(1)/2-40 ax_margin 80 28], "parent", hp);
+
+  uicontrol (hui);  # Set keyboard focus on the uicontrol
+
+  set (hf, "windowstyle", windowstyle, "visible", "on");
+
+endfunction
+
+## Callback when button clicked (close window)
+function cb_callback (~, ~)
+  close (gcbf ());
+endfunction
+
+## Callback when key typed (close window on activation of button)
+function cb_keypress (~, ev)
+  if (any (strcmp (ev.Key, {"enter", "return", "escape", "space"})))
+    close (gcbf ());
+  endif
+endfunction
+
+
+%!demo
+%! msgbox ("A bare dialog");
+
+%!demo
+%! msgbox ("An informative string", "Documentation", "help");
+
+%!demo
+%! msgbox ("Something the user should hear about before continuing", ...
+%!         "Take care!", "warn");
+
+%!demo
+%! msgbox ("A critical message for the user", "Error", "error");
+
+%!demo
+%! msgbox ({"The default interpreter is 'tex':", ...
+%!          '\Delta_{1-2} = r_2 - r_1'}, "Documentation", "help");
+
+%!demo
+%! msgbox ({"Help dialog with uninterpreted string:", ...
+%!          '\Delta_{1-2} = r_2 - r_1'}, "Documentation", "help", ...
+%!          struct ("Interpreter", "none", "WindowStyle", "non-modal"));
+
+%!demo
+%! msgbox ({"This dialog has replaced all the previously open dialogs", ...
+%!          "that had the same title ('Documentation')."}, "Documentation", ...
+%!         "warn", "replace");
+
+%!demo
+%! msgbox ("Custom dialog with a random 32-by-32-by-3 RGB icon.", ...
+%!         "Dialog Title", "custom", rand (32, 32, 3));
+
+%!demo
+%! cdata = get (0, "factoryimagecdata");
+%! msgbox ({"Custom dialog with the default Octave image.", ...
+%!          "The image is indexed into the 'copper' colormap"}, ...
+%!         "Dialog Title", "custom", cdata, copper (64));
 
 ## Test input validation
-%!error <narginchk> msgbox (1, 2, 3, 4, 5)
-%!error <MSG must be a character string> msgbox (1)
-%!error <TITLE must be a character string> msgbox ("msg", 1)
-%!error <ICON is not a valid type> msgbox ("msg", "title", 1)
-%!error <CREATEMODE is not a valid> msgbox ("msg", "title", "help", "wrong")
+%!error <MSG must be a string or cell array of strings> msgbox (1)
+%!error <TITLE must be a string> msgbox ("msg", 1)
+%!error <unhandled value for ICON data> msgbox ("msg", "title", 1)
+%!error <missing data for 'custom' icon> msgbox ("msg", "title", "custom")
+%!error <unhandled value 1 for OPT> msgbox ("msg", "title", "help", "1")
--- a/scripts/gui/private/__uiobject_split_args__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/private/__uiobject_split_args__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -33,25 +33,21 @@
     if (ishghandle (in_args{1}))
       parent = in_args{1};
       offset = 2;
-    elseif (! ischar (in_args{1}))
+    elseif (! ischar (in_args{1}) && ! isstruct (in_args{1}))
       error ("%s: invalid parent handle.", who);
     endif
 
     args = in_args(offset:end);
   endif
 
-  if (rem (length (args), 2))
-    error ("%s: PROPERTY/VALUE arguments must occur in pairs", who);
-  endif
-
   if (! isempty (args))
-    i = find (strcmpi (args(1:2:end), "parent"), 1, "first");
-    if (! isempty (i) && length (args) >= 2*i)
-      parent = args{2*i};
+    i = find (strcmpi (args, "parent"), 1, "first");
+    if (! isempty (i) && numel (args) > i)
+      parent = args{i+1};
       if (! ishghandle (parent))
         error ("%s: invalid parent handle.", who);
       endif
-      args([2*i-1, 2*i]) = [];
+      args(i:i+1) = [];
     endif
   endif
 
--- a/scripts/gui/questdlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/questdlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -137,13 +137,13 @@
 
 %!demo
 %! disp ('- test questdlg with message and title only.');
-%! a = 'No';
+%! a = 'Yes';
 %! c = 0;
-%! while (strcmp (a, 'No') || ! c)
+%! while (strcmp (a, 'Yes') && ! c)
 %!   a = questdlg ('Close this Question Dialog?', 'Reductio Ad Absurdum');
 %!   if (strcmp (a, 'Yes'))
 %!     q = 'Are you sure?';
-%!     while (strcmp (a, 'Yes') && ! c)
+%!     while (strcmp (a, 'Yes'))
 %!       a = questdlg (q, 'Reductio Ad Absurdum');
 %!       word = ' really';
 %!       i = strfind (q, word);
@@ -157,8 +157,7 @@
 %!     endwhile
 %!   endif
 %!   if (strcmp (a, 'Cancel'))
-%!     warndlg ('Answer "Yes" or "No".', 'Warning Dialog');
-%!     a = 'No';
+%!     uiwait (warndlg ('Answer "Yes" or "No".', 'Warning Dialog'));
 %!     c = 1;
 %!   endif
 %! endwhile
--- a/scripts/gui/setappdata.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/setappdata.m	Thu Dec 20 17:18:56 2018 -0500
@@ -59,9 +59,9 @@
     values = varargin{2};
     n_names = numel (names);
     n_value = numel (values);
-    if (n_value == 1 && n_names > 1);
+    if (n_value == 1 && n_names > 1)
       values = repmat (values, [1, n_names]);
-    elseif (n_names != n_value);
+    elseif (n_names != n_value)
       error ("setappdata: number of NAME and VALUE arguments must match");
     endif
     varargin = cell (1, 2*numel (names));
--- a/scripts/gui/uibuttongroup.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/uibuttongroup.m	Thu Dec 20 17:18:56 2018 -0500
@@ -23,7 +23,7 @@
 ##
 ## Create a uibuttongroup object and return a handle to it.
 ##
-## uibuttongroups are used to create group uicontrols.
+## A uibuttongroup is used to group uicontrol objects.
 ##
 ## If @var{parent} is omitted then a uibuttongroup for the current figure is
 ## created.  If no figure is available, a new figure is created first.
@@ -34,29 +34,34 @@
 ## Any provided property value pairs will override the default values of the
 ## created uibuttongroup object.
 ##
-## Uibuttongroup properties are documented at @ref{Uibuttongroup Properties}.
+## Properties of uibuttongroup objects are documented at
+## @ref{Uibuttongroup Properties}.
 ##
 ## Examples:
 ##
 ## @example
 ## @group
-## % create figure and panel on it
+## ## Create figure and panel on it
 ## f = figure;
-## % create a button group
+## ## Create a button group
 ## gp = uibuttongroup (f, "Position", [ 0 0.5 1 1])
-## % create a buttons in the group
+## ## Create a buttons in the group
 ## b1 = uicontrol (gp, "style", "radiobutton", ...
 ##                 "string", "Choice 1", ...
 ##                 "Position", [ 10 150 100 50 ]);
 ## b2 = uicontrol (gp, "style", "radiobutton", ...
 ##                 "string", "Choice 2", ...
 ##                 "Position", [ 10 50 100 30 ]);
-## % create a button not in the group
+## ## Create a button not in the group
 ## b3 = uicontrol (f, "style", "radiobutton", ...
 ##                 "string", "Not in the group", ...
 ##                 "Position", [ 10 50 100 50 ]);
 ## @end group
 ## @end example
+##
+## When called with a single argument @var{h} which is a handle to an existing
+## uibuttongroup object, switch the focus to the specified uibuttongroup.  This
+## functionality is not currently implemented.
 ## @seealso{figure, uipanel}
 ## @end deftypefn
 
@@ -65,7 +70,8 @@
 function hui = uibuttongroup (varargin)
 
   if (nargin == 1 && isgraphics (varargin{1}, "uibuttongroup"))
-    error ("uibuttongroup: focusing not implemented yet");
+    warning ("uibuttongroup: focusing not implemented yet");
+    return;
   endif
 
   [h, args] = __uiobject_split_args__ ("uibuttongroup", varargin,
@@ -74,6 +80,7 @@
 
 endfunction
 
+
 %!demo
 %! f = figure;
 %! gp = uibuttongroup (f, "Position", [ 0 0.5 1 1], ...
--- a/scripts/gui/uicontrol.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/uicontrol.m	Thu Dec 20 17:18:56 2018 -0500
@@ -23,8 +23,8 @@
 ##
 ## Create a uicontrol object and return a handle to it.
 ##
-## uicontrols are used to create simple interactive controls such as push
-## buttons, checkboxes, edit and list controls.
+## A uicontrol object is used to create simple interactive controls such as
+## push buttons, checkboxes, edit and list controls.
 ##
 ## If @var{parent} is omitted then a uicontrol for the current figure is
 ## created.  If no figure is available, a new figure is created first.
@@ -35,11 +35,11 @@
 ## Any provided property value pairs will override the default values of the
 ## created uicontrol object.
 ##
-## Uicontrol properties are documented at @ref{Uicontrol Properties}.
+## Properties of uicontrol objects are documented at
+## @ref{Uicontrol Properties}.
 ##
-## Control of the type of uicontrol created is through the use of the
-## @var{style} property.  If no style property is provided, a push button will
-## be created.
+## The type of uicontrol created is specified by the @var{style} property.  If
+## no style property is provided, a push button will be created.
 ##
 ## Valid styles for uicontrol are:
 ##
@@ -83,16 +83,23 @@
 ##
 ## @example
 ## @group
-## % create figure and panel on it
+## ## Create figure and panel on it
 ## f = figure;
-## % create a button (default style)
-## b1 = uicontrol (f, "string", "A Button", "position",[10 10 150 40]);
-## % create an edit control
-## e1 = uicontrol (f, "style", "edit", "string", "editable text", "position",[10 60 300 40]);
-## % create a checkbox
-## c1 = uicontrol (f, "style", "checkbox", "string", "a checkbox", "position",[10 120 150 40]);
+## ## Create a button (default style)
+## b1 = uicontrol (f, "string", "A Button", "position", [10 10 150 40]);
+## ## Create an edit control
+## e1 = uicontrol (f, "style", "edit", "string", "editable text", ...
+##                    "position", [10 60 300 40]);
+## ## Create a checkbox
+## c1 = uicontrol (f, "style", "checkbox", "string", "a checkbox", ...
+##                    "position", [10 120 150 40]);
 ## @end group
 ## @end example
+##
+## When called with a single argument @var{h} which is a handle to an existing
+## uicontrol object, switch the keyboard focus to the specified
+## uicontrol.  As a result, the uicontrol object will receive keyboard
+## events that can be processed using the @qcode{"keypressfcn"} callback.
 ## @seealso{figure, uipanel}
 ## @end deftypefn
 
@@ -101,7 +108,8 @@
 function hui = uicontrol (varargin)
 
   if (nargin == 1 && isgraphics (varargin{1}, "uicontrol"))
-    error ("uicontrol: focusing not implemented yet");
+    set (varargin{1}, "__focus__", "on");
+    return;
   endif
 
   [h, args] = __uiobject_split_args__ ("uicontrol", varargin,
--- a/scripts/gui/uigetdir.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/uigetdir.m	Thu Dec 20 17:18:56 2018 -0500
@@ -40,7 +40,7 @@
     error ("uigetdir: INIT_PATH and DIALOG_NAME must be string arguments");
   endif
 
-  if (! isdir (init_path))
+  if (! isfolder (init_path))
     init_path = fileparts (init_path);
   endif
 
--- a/scripts/gui/uigetfile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/uigetfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -126,7 +126,7 @@
 
   if (len > 2)
     if (ischar (args{3}))
-      if (isdir (args{3}))
+      if (isfolder (args{3}))
         fdir = args{3};
         fname = fext = "";
       else
--- a/scripts/gui/uiputfile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/uiputfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -90,7 +90,7 @@
 
   if (nargin > 2)
     if (ischar (varargin{3}))
-      if (isdir (varargin{3}))
+      if (isfolder (varargin{3}))
         fdir = varargin{3};
         fname = fext = "";
       else
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/uitable.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,302 @@
+## Copyright (C) 2016-2018 Andrew Thornton
+##
+## 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{hui} =} uitable (@var{property}, @var{value}, @dots{})
+## @deftypefnx {} {@var{hui} =} uitable (@var{parent}, @var{property}, @var{value}, @dots{})
+## Create a uitable object and return a handle to it.
+##
+## A uitable object is used to show tables of data in a figure window.
+##
+## If @var{parent} is omitted then a uitable for the current figure is
+## created.  If no figure is available, a new figure is created first.
+##
+## If @var{parent} is given then a uitable relative to @var{parent} is
+## created.
+##
+## Any provided property value pairs will override the default values of the
+## created uitable object.
+##
+## Properties of uitable objects are documented at
+## @ref{Uitable Properties}.
+##
+## Examples:
+##
+## @example
+## @group
+## ## Create figure and place a table on it
+## f = figure ();
+## m = magic (8);
+## t = uitable (f, "Data", m, "ColumnWidth", @{ 40 @});
+## @end group
+##
+## @group
+## ## Create a table with labeled rows and columns
+## f = figure ();
+## d = reshape (1:9, [3, 3]);
+## row_names = @{ "Row1", "Row2", "Row3" @};
+## col_names = @{ "Col1", "Col2", "Col3" @};
+## t = uitable (f, "Data", d, ...
+##              "RowName", row_names, "ColumnName", col_names);
+##
+## p = get (t, "Position");
+## e = get (t, "Extent");
+## p(3:4) = e(3:4);
+## set (t, "Position", p);
+## @end group
+##
+## ## Long demo with callbacks
+## function uitable_demo ()
+##   f = figure ("Name", "uitable Demo", "Menu", "none", ...
+##               "Position", [10 10 1000 680]);
+##
+##   ## A basic example
+##   d = @{ "char"   , "A string";
+##         "double" , 12.3456789;
+##         "complex", 1+2i;
+##         "bool"   , true;
+##         "single" , single (12.3456789);
+##         "int8"   , int8 (-128);
+##         "uint8"  , uint8 (128);
+##         "int16"  , int16 (-32768);
+##         "uint16" , uint16 (32768);
+##         "int32"  , int32 (-2147483648);
+##         "uint32" , uint32 (2147483648);
+##         "int64"  , int64 (-2147483649);
+##         "uint64" , uint64 (2147843649)@};
+##
+##   popup_options = @{"A", "B", "C", "D", "E"@};
+##
+##   columnformat_options = @{ "[]", "char", "pop-up", "numeric", "short", "short e", ...
+##                   "short eng", "short g", "long", "long e", "long eng", ...
+##                   "long g", "bank", "+", "rat", "logical"@};
+##   columnformat_values = columnformat_options;
+##   columnformat_values@{1@} = "";
+##   columnformat_values@{3@} = popup_options;
+##
+##   default_data = repmat (d(:,2), 1, columns (columnformat_options));
+##   b_add = uicontrol (f, "Position", [285 630 600 50], ...
+##             "UserData", [rows(d), 1], ...
+##             "Style", "pushbutton", ...
+##             "String", "Set data at selected point to selected datatype");
+##
+##   l_type_table = uicontrol (f, "Position", [ 0 603 120 25 ], ...
+##       "String", "Datatype Table:", ...
+##       "Style", "text");
+##   t_type_table = uitable (f, "Position", [ 0 530 1000 70 ], ...
+##       "Data", transpose (d(:, 2)), ...
+##       "ColumnName", transpose (d(:, 1)), ...
+##       "RowName", "Value", ...
+##       "CellSelectionCallback", ...
+##            @@(x, y) set (b_add, "UserData", y.Indices ));
+##
+##   l_point_table = uicontrol (f, "Position", [ 0 640 60 25 ], ...
+##       "String", "Point:", ...
+##       "Style", "text");
+##   t_point_table = uitable (f, "Position", [ 80 630 160 42 ], ...
+##       "RowName", [], ...
+##       "ColumnName", @{"x", "y"@}, ...
+##       "Data", [ 1, 1 ], ...
+##       "ColumnEditable", true);
+##
+##   l_editable_table = uicontrol (f, "Position", [ 0 502 200 25 ], ...
+##       "Style", "text", ...
+##       "String", "Set Data Columns Editable:");
+##   t_editable_table = uitable (f, "Position", [ 0 434 1000 65 ], ...
+##                              "Data", repmat (false, 1, columns (default_data)), ...
+##                              "ColumnEditable", true);
+##
+##   l_format_table = uicontrol (f, "Position", [ 0 406 200 25 ], ...
+##       "Style", "text", ...
+##       "String", "Set Data Column Format:");
+##   t_format_table = uitable (f, "Position", [ 0 338 1000 65 ], ...
+##       "Data", columnformat_options, ...
+##       "ColumnEditable", true, ...
+##       "ColumnFormat", arrayfun (@@(x) @{columnformat_options@}, 1:columns (columnformat_options)));
+##
+##   l_data_table = uicontrol (f, "Style", "text", "String", "Data:", "Position", [ 0 310 60 25 ]);
+##   t_data_table = uitable (f, "Position", [ 0 15 1000 290 ], ...
+##       "Data", default_data, ...
+##       "ColumnFormat", columnformat_values);
+##
+##   set (t_format_table, "CellEditCallback", ...
+##       @@(x, y) update_column_format (y.NewData, y.Indices, t_data_table, popup_options));
+##   set (t_point_table, "CellEditCallback", ...
+##      @@(x, y) validate_point_table (x, y, t_data_table));
+##   set (t_editable_table, "CellEditCallback", @@(x,y) set (t_data_table, ...
+##           "ColumnEditable", get (t_editable_table, "Data")));
+##   set (b_add, "Callback", @@(x, y) ...
+##           update_data (b_add, t_point_table, t_type_table, t_data_table));
+##   set (t_data_table, "cellselectioncallback", @@(x, y) update_point_table (y.Indices, t_point_table));
+## endfunction
+##
+## function validate_point_table (h, dat, t_data_table)
+##   if (! (dat.NewData > 0 && ...
+##     dat.NewData < size (get (t_data_table, "Data"), dat.Indices(1, 1)) + 1))
+##
+##     d = get (h, "Data");
+##     d(dat.Indices) = 1;
+##     set (h, "Data", d);
+##   endif
+## endfunction
+##
+## function update_column_format (format, indices, t_data_table, popup_options)
+##   cf = get (t_data_table, "ColumnFormat");
+##   if (strcmp (format, "[]"))
+##     format = "";
+##   elseif (strcmp (format, "pop-up"))
+##     format = popup_options;
+##   endif
+##   cf@{indices(1,2)@} = format;
+##   set (t_data_table, "ColumnFormat", cf);
+## endfunction
+##
+## function update_point_table (indices, t_point_table)
+##   if (isempty (indices))
+##     indices = [1, 1];
+##   endif
+##   set (t_point_table, "Data", indices(1,:));
+## endfunction
+##
+## function update_data (b_add, t_point_table, t_type_table, t_data_table)
+##   indices = get (b_add, "UserData");
+##   if (isempty (indices))
+##     indices = [1, 1];
+##   endif
+##   d = get (t_data_table, "Data");
+##   t_type_table_data = get (t_type_table, "Data");
+##   p = get (t_point_table, "Data");
+##   d(p(1,2), p(1,1)) = t_type_table_data(indices(1,2));
+##   set (t_data_table, "Data", d);
+## endfunction
+## @end example
+##
+## @seealso{figure, uicontrol}
+## @end deftypefn
+
+function hui = uitable (varargin)
+
+  [h, args] = __uiobject_split_args__ ("uitable", varargin, ...
+                                       {"figure", "uipanel", "uibuttongroup"});
+  htmp = __go_uitable__ (h, args{:});
+
+  if (nargout > 0)
+    hui = htmp;
+  endif
+
+endfunction
+
+
+%!demo
+%! ## Create figure and place a table on it
+%! f = clf ();
+%! m = magic (8);
+%! t = uitable (f, "Data", m, "ColumnWidth", {50}, ...
+%!              "Units", "normalized", "Position", [0.1 0.1 0.8 0.8]);
+
+%!demo
+%! ## Create figure and place an editable table on it
+%! f = clf ();
+%! m = magic (8);
+%! t = uitable (f, "Data", m, "ColumnWidth", {50}, "ColumnEditable", true, ...
+%!              "Units", "normalized", "Position", [0.1 0.1 0.8 0.8]);
+
+%!demo
+%! ## Create figure and table, but change the format to rational_approx
+%! f = clf ();
+%! m = magic (8) / 64;
+%! t = uitable (f, "Data", m, "ColumnWidth", {50}, ...
+%!              "ColumnFormat", repmat ({"rat"}, 1, 8), ...
+%!              "Units", "normalized", "Position", [0.1 0.1 0.8 0.8]);
+
+%!demo
+%! cf = {"char", "char", {"A", "B", "C"}, "numeric", "short", "short e", ...
+%!      "short eng", "short g", "long", "long e", "long eng", "long g", ...
+%!      "bank", "+", "rat", "logical"};
+%! cn = cf;
+%! cn{1} = "type";
+%! cn{3} = "pop-up";
+%!
+%! d = {"double", 0.0000123456789;
+%!      "double", 0.000123456789;
+%!      "double", 0.00123456789;
+%!      "double", 0.0123456789;
+%!      "double", 0.123456789;
+%!      "double", 12;
+%!      "double", 1.23456789;
+%!      "double", 12.3456789;
+%!      "double", 123.456789;
+%!      "double", 1234.56789;
+%!      "complex", 0.0000123456789 + 12.3456789i;
+%!      "complex", 0.000123456789 + 12.3456789i;
+%!      "complex", 0.00123456789 + 12.3456789i;
+%!      "complex", 0.0123456789 + 12.3456789i;
+%!      "complex", 0.123456789 + 12.3456789i;
+%!      "complex", 1.23456789 + 12.3456789i;
+%!      "complex", 12.3456789 + 12.3456789i;
+%!      "complex", 123.456789 + 12.3456789i;
+%!      "complex", 1234.56789 + 12.3456789i;
+%!      "bool", true;
+%!      "bool", false;
+%!      "single", single(0.0000123456789);
+%!      "single", single(1.23456789);
+%!      "single", single(1234.56789);
+%!      "int8", int8(127);
+%!      "int8", int8(0);
+%!      "int8", int8(-126);
+%!      "int16", int16(32767);
+%!      "int16", int16(0);
+%!      "int16", int16(-32768);
+%!      "int32", int32(2147483647);
+%!      "int32", int32(0);
+%!      "int32", int32(-2147483647);
+%!      "int64", int64(9223372036854775807);
+%!      "int64", int64(0);
+%!      "int64", int64(-9223372036854775807);
+%!      "uint8", uint8(127);
+%!      "uint8", uint8(0);
+%!      "uint8", uint8(255);
+%!      "uint16", uint16(32767);
+%!      "uint16", uint16(0);
+%!      "uint16", uint16(65535);
+%!      "uint32", uint32(2147483647);
+%!      "uint32", uint32(0);
+%!      "uint32", uint32(4294967295);
+%!      "uint64", uint64(9223372036854775807);
+%!      "uint64", uint64(0);
+%!      "uint64", uint64(18446744073709551615);
+%!      "char", "a string"};
+%!
+%! ws = {"auto", 140};
+%! widths = cell (1, columns (cf));
+%! widths(1,1) = ws(1,1);
+%! widths(1,2:end) = repmat (ws(:,2), [1, columns(cf) - 1]);
+%!
+%! data = cell (rows (d), columns (cf));
+%!
+%! data(:,1) = d(:,1);
+%!
+%! data(:, 2:end) = repmat (d(:,2), [1, columns(cf) - 1]);
+%!
+%! t = uitable ("Data", data,
+%!              "ColumnFormat", cf,
+%!              "ColumnWidth", widths,
+%!              "ColumnName", cn,
+%!              "ColumnEditable", true,
+%!              "Units", "Normalized",
+%!              "Position", [0 0 1 1]);
--- a/scripts/gui/waitbar.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/waitbar.m	Thu Dec 20 17:18:56 2018 -0500
@@ -210,6 +210,9 @@
 %! h = waitbar (0, '0.00%');
 %! for i = 0:0.01:1
 %!   waitbar (i, h, sprintf ('%.2f%%', 100*i));
+%!   if (strcmp (graphics_toolkit (), "qt"))
+%!     pause (0.01);
+%!   endif
 %! endfor
 %! close (h);
 
@@ -217,20 +220,32 @@
 %! h = waitbar (0, 'please wait...');
 %! for i = 0:0.01:0.6
 %!   waitbar (i);
+%!   if (strcmp (graphics_toolkit (), "qt"))
+%!     pause (0.01);
+%!   endif
 %! endfor
 %! i = 0.3;
 %! waitbar (i, h, 'don''t you hate taking a step backward?');
 %! pause (0.5);
 %! for i = i:0.005:0.7
 %!   waitbar (i, h);
+%!   if (strcmp (graphics_toolkit (), "qt"))
+%!     pause (0.01);
+%!   endif
 %! endfor
 %! waitbar (i, h, 'or stalling?');
 %! pause (1);
-%! for i = i:0.003:0.8
+%! for i = i:0.003:0.85
 %!   waitbar (i, h, 'just a little longer now');
+%!   if (strcmp (graphics_toolkit (), "qt"))
+%!     pause (0.01);
+%!   endif
 %! endfor
 %! for i = i:0.001:1
 %!   waitbar (i, h, 'please don''t be impatient');
+%!   if (strcmp (graphics_toolkit (), "qt"))
+%!     pause (0.01);
+%!   endif
 %! endfor
 %! close (h);
 
@@ -253,15 +268,20 @@
 
 %!demo
 %! clf ();
-%! niter = 9;
+%! niter = 7;
 %! l = 1;
 %! xx = [0 l];
 %! yy = [0 0];
 %! hli = plot (xx, yy);
+%! pos1 = get (gcf, "position");
 %!
-%! disp ("Push the cancel to stop the process.");
-%! hf = waitbar(0,"0","Name","Building Koch curve ...",...
-%!              "createcancelbtn", "setappdata (gcbf,'interrupt', true)");
+%! disp ("Push the <cancel> button to stop the process.");
+%! hf = waitbar (0,"0","Name","Building Koch curve ...",...
+%!               "createcancelbtn", "setappdata (gcbf,'interrupt', true)");
+%! 
+%! pos2 = get (hf, "position");
+%! set (hf, "position", [pos1(1)+(pos1(3)-pos2(3))/2, pos1(2)+pos1(4), pos2(3:4)]);
+%! 
 %! for ii = 1:niter
 %!   ## Check cancel request
 %!   if (! ishghandle (hf))
@@ -282,14 +302,14 @@
 %!                                              0 0 l*(3)^.5/2 0;
 %!                                              1 1 1          1];
 %!   tmp = arrayfun (xy, theta, xx(1:end-1), yy(1:end-1),
-%!                  "uniformoutput", false);
+%!                   "uniformoutput", false);
 %!
 %!   tmp = cell2mat (tmp);
 %!   xx = [tmp(1,:) xx(end)];
 %!   yy = [tmp(2,:) yy(end)];
 %!   set (hli, "xdata", xx, "ydata", yy);
 %!   drawnow ();
-%!   pause (0.5);
+%!   pause (0.75);
 %! endfor
 %!
 %! if (ishghandle (hf))
--- a/scripts/gui/warndlg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/gui/warndlg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,24 +17,26 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{h} =} warndlg ()
-## @deftypefnx {} {@var{h} =} warndlg (@var{msg})
-## @deftypefnx {} {@var{h} =} warndlg (@var{msg}, @var{title})
-## @deftypefnx {} {@var{h} =} warndlg (@var{msg}, @var{title}, @var{createmode})
+## @deftypefn  {} {} warndlg ()
+## @deftypefnx {} {} warndlg (@var{msg})
+## @deftypefnx {} {} warndlg (@var{msg}, @var{title})
+## @deftypefnx {} {} warndlg (@var{msg}, @var{title}, @var{opt})
+## @deftypefnx {} {@var{h} =} warndlg (@dots{})
 ## Display a warning dialog box with warning message @var{msg} and caption
 ## @var{title}.
 ##
-## The default warning message is @qcode{"This is the default warning string."}
-## and the default caption is @qcode{"Warning Dialog"}.
+## The default warning message is
+## @qcode{"This is the default warning string.@:"} and the default caption is
+## @qcode{"Warning Dialog"}.
 ##
 ## The warning message may have multiple lines separated by newline characters
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
-## The return value @var{h} is always 1.
+## The third optional argument @var{opt} controls the behavior of the dialog.
+## See @code{msgbox} for details.
 ##
-## Compatibility Note: The optional argument @var{createmode} is accepted for
-## @sc{matlab} compatibility, but is not implemented.  See @code{msgbox} for
-## details.
+## The return value @var{h} is a handle to the figure object used for
+## building the dialog.
 ##
 ## Examples:
 ##
@@ -47,32 +49,37 @@
 ## @end group
 ## @end example
 ##
-## @seealso{errordlg, helpdlg, inputdlg, listdlg, msgbox, questdlg}
+## @seealso{errordlg, helpdlg, msgbox, inputdlg, listdlg, questdlg}
 ## @end deftypefn
 
-function retval = warndlg (varargin)
+function h = warndlg (varargin)
 
-  narginchk (0, 3);
+  msg = "This is the default warning.";
+  tit = "Warning Dialog";
+  opt = "non-modal";
+
+  nargs = numel (varargin);
 
-  msg = "This is the default warning string.";
-  title = "Warning Dialog";
-
-  if (nargin > 0)
+  if (nargs > 3)
+    print_usage ();
+  elseif (nargs == 1)
+    msg = varargin{1};
+  elseif (nargs == 2)
     msg = varargin{1};
-  endif
-  if (nargin > 1)
-    title = varargin{2};
+    tit = varargin{2};
+  elseif (nargs == 3)
+    msg = varargin{1};
+    tit = varargin{2};
+    opt = varargin{3};
   endif
 
-  if (nargin < 3)
-    retval = msgbox (msg, title, "warn");
-  else
-    retval = msgbox (msg, title, "warn", varargin{3});
+  htmp = msgbox (msg, tit, "warn", opt);
+
+  if (nargout)
+    h = htmp;
   endif
 
 endfunction
 
-
-%!error warndlg (1, 2, 3, 4)
-%!error <MSG must be a character string> warndlg (1)
-%!error <TITLE must be a character string> warndlg ("msg", 1)
+## No BIST tests.  This function just dispatches to msgbox().
+%!assert (1)
--- a/scripts/help/__makeinfo__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/help/__makeinfo__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -83,7 +83,7 @@
     endif
   endif
 
-  if (! isa (fsee_also, "function_handle"))
+  if (! is_function_handle (fsee_also))
     error ("__makeinfo__: third input argument must be a function handle");
   endif
 
--- a/scripts/help/__unimplemented__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/help/__unimplemented__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -587,7 +587,6 @@
   "boundary",
   "boundaryFacets",
   "boundingbox",
-  "bounds",
   "brush",
   "builddocsearchdb",
   "bvp4c",
@@ -632,7 +631,6 @@
   "clearAllMemoizedCaches",
   "clearCache",
   "clearpoints",
-  "clearvars",
   "clipboard",
   "clone",
   "cmopts",
@@ -645,7 +643,6 @@
   "condensation",
   "coneplot",
   "conncomp",
-  "containers.Map",
   "contains",
   "contourslice",
   "convertCharsToStrings",
@@ -905,8 +902,6 @@
   "isEdge",
   "isenum",
   "isevent",
-  "isfile",
-  "isfolder",
   "ishole",
   "isIllConditioned",
   "isinterface",
@@ -995,21 +990,9 @@
   "morebins",
   "movAbsHDU",
   "move",
-  "movegui",
-  "movie",
   "movie2avi",
-  "movmad",
-  "movmax",
-  "movmean",
-  "movmedian",
-  "movmin",
   "movNamHDU",
-  "movprod",
   "movRelHDU",
-  "movstd"
-  "movstd",
-  "movsum",
-  "movvar",
   "mput",
   "multibandread",
   "multibandwrite",
@@ -1062,10 +1045,8 @@
   "ode23t",
   "ode23tb",
   "odextend",
-  "openfig",
   "openFile",
   "opengl",
-  "ordeig",
   "ordqz",
   "outdegree",
   "outerjoin",
@@ -1161,7 +1142,6 @@
   "rticklabels",
   "ruler2num",
   "runperf",
-  "savefig",
   "scale",
   "scatteredInterpolant",
   "scroll",
@@ -1309,7 +1289,6 @@
   "uiswitch",
   "uitab",
   "uitabgroup",
-  "uitable",
   "uitextarea",
   "uitogglebutton",
   "uitree",
--- a/scripts/help/get_first_help_sentence.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/help/get_first_help_sentence.m	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,9 @@
 ## The first sentence is defined as the text after the function declaration
 ## until either the first period (".") or the first appearance of two
 ## consecutive newlines ("\n\n").  The text is truncated to a maximum length of
-## @var{max_len}, which defaults to 80.
+## @var{max_len}, which defaults to 80.  If the text must be truncated the last
+## three characters of the text are replaced with @qcode{"..."} to indicate
+## that more text was available.
 ##
 ## The optional output argument @var{status} returns the status reported by
 ## @code{makeinfo}.  If only one output argument is requested, and @var{status}
@@ -82,13 +84,24 @@
 
 ## This function extracts the first sentence from a plain text help text
 function [text, status] = first_sentence_plain_text (help_text, max_len)
-  ## Extract first line by searching for a period followed by a space class
-  ## character (to support periods in numbers or words) ...
-  period_idx = regexp (help_text, '\.\s', "once");
+  ## Extract first line by searching for a period followed by whitespace
+  ## followed by a capital letter (Nearly the same rule as Texinfo).
+  period_idx = regexp (help_text, '\.\s+(?:[A-Z]|\n)', "once");
   ## ... or a double end-of-line (we subtract 1 because we are not interested
   ## in capturing the first newline).
   line_end_idx = regexp (help_text, "\n\n", "once") - 1;
-  text = help_text (1:min ([period_idx; line_end_idx; max_len; length(help_text)]));
+  help_len = length (help_text);
+  min_idx = min ([period_idx, line_end_idx, help_len]);
+  if (min_idx < max_len)
+    text = help_text(1:min_idx);
+  else
+    if (max_len > 3)
+      text = help_text(1:(max_len-3));
+      text = [text, "..."];
+    else
+      text = help_text(1:max_len);
+    endif
+  endif
   status = 0;
 endfunction
 
@@ -158,6 +171,9 @@
 %!assert (get_first_help_sentence ('get_first_help_sentence'), ...
 %!        "Return the first sentence of a function's help text.")
 
+%!assert (get_first_help_sentence ('get_first_help_sentence', 28), ...
+%!        "Return the first sentence...")
+
 ## Test input validation
 %!error get_first_help_sentence ()
 %!error get_first_help_sentence (1, 2, 3)
--- a/scripts/help/warning_ids.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/help/warning_ids.m	Thu Dec 20 17:18:56 2018 -0500
@@ -212,6 +212,15 @@
 ## The @option{--traditional} or @option{--braindead} startup options for
 ## Octave may also be of use, @pxref{Command Line Options}.
 ##
+## @item Octave:legacy-function
+## If the @code{Octave:legacy-function} warning is enabled, a
+## warning is issued when Octave encounters a function that @sc{matlab} has
+## suggested should be avoided.  The function may become obsolete at some
+## point in the future and removed, in which case the warning will change to
+## @code{Octave:deprecated-function}, and the function will continue to exist
+## for two further versions of Octave before being removed.
+## By default, the @code{Octave:legacy-function} warning is enabled.
+##
 ## @item Octave:logical-conversion
 ## By default, the @code{Octave:logical-conversion} warning is enabled.
 ##
--- a/scripts/help/which.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/help/which.m	Thu Dec 20 17:18:56 2018 -0500
@@ -54,7 +54,7 @@
         endif
       else
         if (isempty (m(i).type))
-          if (isdir (m(i).file))
+          if (isfolder (m(i).file))
             printf ("'%s' is the directory %s\n",
                     m(i).name, m(i).file);
           else
--- a/scripts/image/getframe.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/getframe.m	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,7 @@
 ## the figure to be captured.  Regardless of the figure @qcode{"units"}
 ## property, @var{rect} must be defined in @strong{pixels}.
 ##
-## @seealso{im2frame, frame2im}
+## @seealso{im2frame, frame2im, movie}
 ## @end deftypefn
 
 function frame = getframe (h = [], rect = [])
@@ -99,14 +99,18 @@
       || (strcmp (get (hf, "__graphics_toolkit__"), "qt")
           && (strcmp (get (hf, "__gl_window__"), "on")
               || __have_feature__ ("QT_OFFSCREEN"))))
-    cdata = __get_frame__ (hf);
+
+    ## __get_frame__ requires that the figure "units" is "pixels"
+    unwind_protect
+      units = get (hf, "units");
+      set (hf, "units", "pixels");
+      cdata = __get_frame__ (hf);
+    unwind_protect_cleanup
+      set (hf, "units", units)
+    end_unwind_protect
+
   else
-    ## Use OpenGL offscreen rendering with OSMesa for non-visible figures
-    try
-      cdata = __osmesa_print__ (hf);
-    catch
-      error ("getframe: couldn't render invisible figure. %s", lasterr ());
-    end_try_catch
+    error ("getframe: figure must be visible or qt toolkit must be used with __gl_window__ property 'on' or QT_OFFSCREEN feature available");
   endif
 
   i1 = max (floor (pos(1)), 1);
--- a/scripts/image/image.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/image.m	Thu Dec 20 17:18:56 2018 -0500
@@ -105,6 +105,10 @@
     chararg = 4;
   endif
 
+  if (iscomplex (img))
+    error ("image: IMG data can not be complex");
+  endif
+
   oldfig = [];
   if (! isempty (hax))
     oldfig = get (0, "currentfigure");
@@ -186,9 +190,8 @@
 
       if (ndims (img) == 3)
         if (isinteger (img))
-          cls = class (img);
-          mn = intmin (cls);
-          mx = intmax (cls);
+          mn = intmin (img);
+          mx = intmax (img);
           set (hax, "clim", double ([mn, mx]));
         endif
       endif
@@ -259,3 +262,5 @@
 %! end_unwind_protect
 
 ## FIXME: Need %!tests for linear
+
+%!error <IMG data can not be complex> image ([1, i])
--- a/scripts/image/imagesc.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/imagesc.m	Thu Dec 20 17:18:56 2018 -0500
@@ -35,8 +35,8 @@
 ## If a range is specified as @w{@code{[max, min]}} then the image will be
 ## reversed along that axis.  For convenience, @var{x} and @var{y} may be
 ## specified as N-element vectors matching the length of the data in @var{img}.
-## However, only the first and last elements will be used to determine the axis
-## limits.
+## However, only the first and last elements will be used to determine
+## the image limits.
 ##
 ## The optional return value @var{h} is a graphics handle to the image.
 ##
--- a/scripts/image/imshow.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/imshow.m	Thu Dec 20 17:18:56 2018 -0500
@@ -49,16 +49,16 @@
 ##
 ## @item @qcode{"xdata"}
 ## If @var{value1} is a 2-element vector, it must contain horizontal image
-## limits in the form [xmin, xmax], where xmin and xmax are the abscissa of
-## the centers of the corner pixels.  Otherwise @var{value1} must be a vector
-## and only the first and last elements will be used for xmin and xmax
-## respectively.
+## limits in the form [xfirst, xlast], where xfirst and xlast are the
+## abscissa of the centers of the corner pixels.  Otherwise @var{value1}
+##  must be a vector and only the first and last elements will be used
+## for xfirst and xlast respectively.
 ##
 ## @item @qcode{"ydata"}
 ## If @var{value1} is a 2-element vector, it must contain vertical image
-## limits in the form [ymin, ymax], where ymin and ymax are the ordinates of
-## the center of the corner pixels.  Otherwise @var{value1} must be a vector
-## and only the first and last elements will be used for ymin and ymax
+## limits in the form [yfirst, ylast], where yfirst and ylast are the ordinates
+## of the center of the corner pixels.  Otherwise @var{value1} must be a vector
+## and only the first and last elements will be used for yfirst and ylast
 ## respectively.
 ##
 ## @end table
--- a/scripts/image/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -46,6 +46,7 @@
   %reldir%/iscolormap.m \
   %reldir%/jet.m \
   %reldir%/lines.m \
+  %reldir%/movie.m \
   %reldir%/ocean.m \
   %reldir%/pink.m \
   %reldir%/prism.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/movie.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,269 @@
+## Copyright (C) 2017 Pantxo Diribarne
+##
+## 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  {} {} movie (@var{mov})
+## @deftypefnx {} {} movie (@var{mov}, @var{n})
+## @deftypefnx {} {} movie (@var{mov}, @var{n}, @var{fps})
+## @deftypefnx {} {} movie (@var{h}, @dots{})
+## Play a movie defined by an array of frame structures.
+##
+## The movie @var{mov} must be a struct array of frames with fields
+## @qcode{"cdata"} and @qcode{"colormap"}, as returned by the @code{getframe}
+## function.  By default all images are displayed once, at 12 fps, in the
+## current axes.
+##
+## The optional argument @var{n} is a scalar or vector of integers that
+## controls the number of times the movie is displayed and which particular
+## frames are shown:
+##
+## @table @asis
+## @item First element:
+##
+## @table @asis
+## @item @var{n}(1) > 0
+## Play the movie @var{n}(1) times.
+##
+## @item @var{n}(1) < 0
+## Play the movie @code{abs (@var{n}(1)} times alternatively in forward and
+## backward order.
+## @end table
+##
+## @item Other elements (if any):
+## Indices of the frames in @var{mov} that will be displayed.
+## @end table
+##
+## If the first argument is a handle to a figure or axes @var{h}, the movie is
+## played in that figure or axes instead of the current axes.
+##
+## @seealso{getframe, im2frame, frame2im}
+## @end deftypefn
+
+function movie (varargin)
+
+  if (nargin == 0 || nargin > 4)
+    print_usage ();
+  endif
+
+  ## Extract possible handle argument
+  hax = [];
+  if (ishghandle (varargin{1}))
+    typ = get (varargin{1}, "type");
+    if (strcmp (typ, "axes"))
+      hax = varargin{1};
+    elseif (strcmp (typ, "figure"))
+      figure (varargin{1});
+      hax = gca ();
+    else
+      error ("movie: H must be a handle to an axes or figure");
+    endif
+    varargin(1) = [];
+    nargin = nargin - 1;
+    if (nargin == 0)
+      print_usage ();
+    endif
+  endif
+
+  ## Extract other arguments
+  n = 1;
+  fps = 12;
+  idx = [];
+
+  mov = varargin{1};
+  if (! isfield (mov, "cdata") || ! isfield (mov, "colormap"))
+    error ("movie: MOV must be a frame struct array");
+  elseif (numel (mov) < 2)
+    error ("movie: MOV must contain at least two frames");
+  endif
+
+  if (nargin > 1)
+    n = varargin{2};
+    if (! isindex (abs (n(1))))
+      error ("movie: N must be a non-zero integer");
+    endif
+
+    if (! isscalar (n))
+      idx = n(2:end)(:)';
+      n = n(1);
+      if (! isindex (idx, numel (mov)))
+        error (["movie: All elements N(2:end) must be valid indices ", ...
+                "into the MOV struct array"]);
+      endif
+    endif
+
+    if (nargin > 2)
+      fps = varargin{3};
+      if (! (isnumeric (fps) && isscalar (fps) && fps > 0))
+        error ("movie: FPS must be a numeric scalar > 0");
+      endif
+    endif
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  ## Build the list of frames to be displayed
+  if (isempty (idx))
+    idx = (1:numel (mov));
+  endif
+
+  if (n > 0)
+    idx = repmat (idx, 1, n);
+  else
+    n = -n;
+    tmp = repmat ([idx fliplr(idx)], 1, fix (n/2));
+    if (fix (n/2) != n/2)
+      idx = [tmp, idx];
+    else
+      idx = tmp;
+    endif
+  endif
+
+  ## Initialize graphics objects
+  if (isempty (mov(1).cdata))
+    error ("movie: empty image data at frame 1");
+  endif
+
+  him = findobj (hax, "-depth", 1, "tag", "__movie_frame__");
+  if (isempty (him))
+    him = image ("parent", hax, "cdata", mov(1).cdata,
+                 "tag", "__movie_frame__");
+  else
+    set (him, "cdata", mov(1).cdata);
+  endif
+
+  set (hax, "ydir", "reverse", "visible", "off");
+
+  ## Initialize the timer
+  t = tau = 1/fps;
+  timerid = tic ();
+
+  for ii = idx
+    cdata = mov(ii).cdata;
+    if (isempty (cdata))
+      error ("movie: empty image data at frame %d", ii);
+    endif
+    set (him, "cdata", cdata);
+
+    if (! isempty (mov(ii).colormap))
+      set (hax, "colormap", mov(ii).colormap)
+    endif
+
+    pause (t - toc (timerid));
+    t += tau;
+  endfor
+
+endfunction
+
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title ("Play movie forward 2 times");
+%! movie (mov, 2);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title ("Play movie forward and backward 5 times at 25 fps");
+%! movie (mov, -5, 25);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title ("Play downsampled movie 5 times");
+%! movie (mov, [5 1:3:nframes]);
+
+%!demo
+%! clf ();
+%! z = sombrero ();
+%! hs = surf (z);
+%! axis manual
+%! nframes = 50;
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   set (hs, "zdata", z * sin (2*pi*ii/nframes));
+%!   mov(ii) = getframe ();
+%! endfor
+%! clf ();
+%! movie (mov, 3, 25);
+
+## Test input validation
+%!error movie ()
+%!error <MOV must be a frame struct array> movie ({2})
+%!error <MOV must contain at least two frames>
+%! movie (struct ("cdata", [], "colormap", []));
+%!error <N must be a non-zero integer>
+%! movie (struct ("cdata", {[], []}, "colormap", []), 2.3);
+%!error <N must be a non-zero integer>
+%! movie (struct ("cdata", {[], []}, "colormap", []), [2.3 -6]);
+%!error <All elements N\(2:end\) must be valid indices into the MOV struct>
+%! movie (struct ("cdata", {[], []}, "colormap", []), [1 -1])
+%!error <All elements N\(2:end\) must be valid indices into the MOV struct>
+%! movie (struct ("cdata", {[], []}, "colormap", []), [1 5])
+%!error <FPS must be a numeric scalar . 0>
+%! movie (struct ("cdata", {[], []}, "colormap", []), 1, "a")
+%!error <FPS must be a numeric scalar . 0>
+%! movie (struct ("cdata", {[], []}, "colormap", []), 1, [1 1])
+%!error <FPS must be a numeric scalar . 0>
+%! movie (struct ("cdata", {[], []}, "colormap", []), 1, -1/12)
+%!error <empty image data at frame 1>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   movie (hf, struct ("cdata", {[], []}, "colormap", []));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+%!error <empty image data at frame 2>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   movie (struct ("cdata", {ones(2), []}, "colormap", []))
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
--- a/scripts/image/private/ind2x.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/private/ind2x.m	Thu Dec 20 17:18:56 2018 -0500
@@ -28,7 +28,7 @@
   if (all (ndims (x) != [2 4]) || size (x, 3) != 1
       || iscomplex (x) || issparse (x)
       || ! (isfloat (x) && all (x(:) == fix (x(:)))
-            || (isinteger (x) && intmin (class (x)) == 0)))
+            || (isinteger (x) && intmin (x) == 0)))
     error ("%s: X must be an indexed image", caller);
   endif
 
@@ -53,7 +53,7 @@
   ## to make the switch, in which case we convert the data to single.
   maxidx = max (x(:));
   if (isinteger (x))
-    if (maxidx == intmax (class (x)))
+    if (maxidx == intmax (x))
       x = single (x);
     endif
     x      += 1;
--- a/scripts/image/rgb2ind.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/image/rgb2ind.m	Thu Dec 20 17:18:56 2018 -0500
@@ -78,7 +78,7 @@
     case {"single", "double", "logical"}
       ## do nothing, return the same
     case {"uint8", "uint16"}
-      map = double (map) / double (intmax (class (R)));
+      map = double (map) / double (intmax (R));
     case "int16"
       map = (double (im) + 32768) / 65535;
     otherwise
--- a/scripts/io/csvread.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/io/csvread.m	Thu Dec 20 17:18:56 2018 -0500
@@ -32,7 +32,7 @@
 ##
 ## Any optional arguments are passed directly to @code{dlmread}
 ## (@pxref{XREFdlmread,,dlmread}).
-## @seealso{dlmread, textread, textscan, csvwrite, dlmwrite}
+## @seealso{dlmread, textscan, csvwrite, dlmwrite}
 ## @end deftypefn
 
 function x = csvread (filename, varargin)
--- a/scripts/io/fileread.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/io/fileread.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,7 +19,7 @@
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{str} =} fileread (@var{filename})
 ## Read the contents of @var{filename} and return it as a string.
-## @seealso{fread, textread, sscanf}
+## @seealso{fread, fscanf, importdata, textscan, type}
 ## @end deftypefn
 
 function str = fileread (filename)
--- a/scripts/io/importdata.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/io/importdata.m	Thu Dec 20 17:18:56 2018 -0500
@@ -257,7 +257,7 @@
   endif
   if (any (na_idx(:)))
 
-    file_content = ostrsplit (fileread (fname), "\n");
+    file_content = ostrsplit (fileread (fname), "\r\n", true);
 
     na_rows = find (any (na_idx, 2));
     for ridx = na_rows(:)'
--- a/scripts/io/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/io/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -7,9 +7,7 @@
   %reldir%/dlmwrite.m \
   %reldir%/fileread.m \
   %reldir%/importdata.m \
-  %reldir%/is_valid_file_id.m \
-  %reldir%/strread.m \
-  %reldir%/textread.m
+  %reldir%/is_valid_file_id.m
 
 %canon_reldir%dir = $(fcnfiledir)/io
 
--- a/scripts/io/strread.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1122 +0,0 @@
-## Copyright (C) 2009-2018 Eric Chassande-Mottin, CNRS (France)
-## Parts Copyright (C) 2012-2018 Philip Nienhuis
-##
-## 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{a}, @dots{}] =} strread (@var{str})
-## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format})
-## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat})
-## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{prop1}, @var{value1}, @dots{})
-## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat}, @var{prop1}, @var{value1}, @dots{})
-## Read data from a string.
-##
-## The string @var{str} is split into words that are repeatedly matched to the
-## specifiers in @var{format}.  The first word is matched to the first
-## specifier, the second to the second specifier and so forth.  If there are
-## more words than specifiers, the process is repeated until all words have
-## been processed.
-##
-## The string @var{format} describes how the words in @var{str} should be
-## parsed.  It may contain any combination of the following specifiers:
-##
-## @table @code
-## @item %s
-## The word is parsed as a string.
-##
-## @item  %f
-## @itemx %n
-## The word is parsed as a number and converted to double.
-##
-## @item  %d
-## @itemx %u
-## The word is parsed as a number and converted to int32.
-##
-## @item  %*
-## @itemx %*f
-## @itemx %*s
-## The word is skipped.
-##
-## For %s and %d, %f, %n, %u and the associated %*s @dots{} specifiers an
-## optional width can be specified as %Ns, etc.@: where N is an integer > 1.
-## For %f, format specifiers like %N.Mf are allowed.
-##
-## @item literals
-## In addition the format may contain literal character strings; these will be
-## skipped during reading.
-## @end table
-##
-## Parsed word corresponding to the first specifier are returned in the first
-## output argument and likewise for the rest of the specifiers.
-##
-## By default, @var{format} is @t{"%f"}, meaning that numbers are read from
-## @var{str}.  This will do if @var{str} contains only numeric fields.
-##
-## For example, the string
-##
-## @example
-## @group
-## @var{str} = "\
-## Bunny Bugs   5.5\n\
-## Duck Daffy  -7.5e-5\n\
-## Penguin Tux   6"
-## @end group
-## @end example
-##
-## @noindent
-## can be read using
-##
-## @example
-## [@var{a}, @var{b}, @var{c}] = strread (@var{str}, "%s %s %f");
-## @end example
-##
-## Optional numeric argument @var{format_repeat} can be used for limiting the
-## number of items read:
-##
-## @table @asis
-## @item -1
-## (default) read all of the string until the end.
-##
-## @item N
-## Read N times @var{nargout} items.  0 (zero) is an acceptable value for
-## @var{format_repeat}.
-## @end table
-##
-## The behavior of @code{strread} can be changed via property-value pairs.  The
-## following properties are recognized:
-##
-## @table @asis
-## @item @qcode{"commentstyle"}
-## Parts of @var{str} are considered comments and will be skipped.
-## @var{value} is the comment style and can be any of the following.
-##
-## @itemize
-## @item @qcode{"shell"}
-## Everything from @code{#} characters to the nearest end-of-line is skipped.
-##
-## @item @qcode{"c"}
-## Everything between @code{/*} and @code{*/} is skipped.
-##
-## @item @qcode{"c++"}
-## Everything from @code{//} characters to the nearest end-of-line is skipped.
-##
-## @item @qcode{"matlab"}
-## Everything from @code{%} characters to the nearest end-of-line is skipped.
-##
-## @item user-supplied.  Two options:
-## (1) One string, or 1x1 cell string: Skip everything to the right of it;
-## (2) 2x1 cell string array: Everything between the left and right strings
-## is skipped.
-## @end itemize
-##
-## @item @qcode{"delimiter"}
-## Any character in @var{value} will be used to split @var{str} into words
-## (default value = any whitespace).  Note that whitespace is implicitly added
-## to the set of delimiter characters unless a @qcode{"%s"} format conversion
-## specifier is supplied; see @qcode{"whitespace"} parameter below.  The set
-## of delimiter characters cannot be empty; if needed Octave substitutes a
-## space as delimiter.
-##
-## @item @qcode{"emptyvalue"}
-## Value to return for empty numeric values in non-whitespace delimited data.
-## The default is NaN@.  When the data type does not support NaN (int32 for
-## example), then default is zero.
-##
-## @item @qcode{"multipledelimsasone"}
-## Treat a series of consecutive delimiters, without whitespace in between,
-## as a single delimiter.  Consecutive delimiter series need not be vertically
-## @qcode{"aligned"}.
-##
-## @item @qcode{"treatasempty"}
-## Treat single occurrences (surrounded by delimiters or whitespace) of the
-## string(s) in @var{value} as missing values.
-##
-## @item @qcode{"returnonerror"}
-## If @var{value} true (1, default), ignore read errors and return normally.
-## If false (0), return an error.
-##
-## @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
-## 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"}
-## (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
-## @qcode{"delimiter"} is retained as delimiter and removed from the set of
-## whitespace characters.  If whitespace characters are to be kept as-is (in
-## e.g., strings), specify an empty value (i.e., @qcode{""}) for
-## @qcode{"whitespace"}; obviously, whitespace cannot be a delimiter then.
-##
-## @end table
-##
-## When the number of words in @var{str} doesn't match an exact multiple of
-## the number of format conversion specifiers, strread's behavior depends on
-## the last character of @var{str}:
-##
-## @table @asis
-## @item last character = @qcode{"@xbackslashchar{}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"}
-## Data columns are not padded; strread returns columns of unequal length
-##
-## @end table
-##
-## @seealso{textscan, textread, load, dlmread, fscanf}
-## @end deftypefn
-
-function varargout = strread (str, format = "%f", varargin)
-
-  ## Check input
-  if (nargin < 1)
-    print_usage ();
-  endif
-
-  if (isempty (str))
-    ## Return empty args (no match), rather than raising an error
-    varargout = cell (1, nargout);
-    return;
-  endif
-
-  if (isempty (format))
-    format = "%f";
-  endif
-
-  if (! ischar (str) || ! ischar (format))
-    error ("strread: STR and FORMAT arguments must be strings");
-  endif
-
-  if (strcmp (typeinfo (format), "sq_string"))
-    format = do_string_escapes (format);
-  endif
-
-  ## Parse format string to compare number of conversion fields and nargout
-  nfields = numel (regexp (format, '(%(\d*|\d*\.\d*)?[nfduscq]|%\[)', "match"));
-  ## If str only has numeric fields, a (default) format ("%f") will do.
-  ## Otherwise:
-  if (! nfields)
-    error ("strread.m: no valid format conversion specifiers found\n");
-  elseif ((max (nargout, 1) != nfields) && ! strcmp (format, "%f"))
-    error ("strread: the number of output variables must match that specified by FORMAT");
-  endif
-
-  ## Check for format string repeat count
-  format_repeat_count = -1;
-  if (nargin > 2 && isnumeric (varargin{1}))
-    if (varargin{1} >= 0)
-      format_repeat_count = varargin{1};
-    endif
-    if (nargin > 3)
-      varargin = varargin(2:end);
-    else
-      varargin = {};
-    endif
-  endif
-
-  ## Parse options.  First initialize defaults
-  comment_flag = false;
-  open_comment = false;
-  cmt_eol = "\n";
-  delimiter_str = "";
-  empty_str = "";
-  eol_char = "";
-  err_action = 0;
-  mult_dlms_s1 = false;
-  numeric_fill_value = NaN;
-  white_spaces = " \b\r\n\t";
-  for n = 1:2:length (varargin)
-    switch (lower (varargin{n}))
-      case "bufsize"
-        ## We could synthesize this, but that just seems weird...
-        warning ("strread: property 'bufsize' is not implemented");
-      case "commentstyle"
-        comment_flag = true;
-        switch (lower (varargin{n+1}))
-          case "c"
-            [comment_start, comment_end] = deal ("/*", "*/");
-          case "c++"
-            [comment_start, comment_end] = deal ("//", "cmt_eol");
-            open_comment = true;
-          case "shell"
-            [comment_start, comment_end] = deal ("#" , "cmt_eol");
-            open_comment = true;
-          case "matlab"
-            [comment_start, comment_end] = deal ("%" , "cmt_eol");
-            open_comment = true;
-          otherwise
-            if (ischar (varargin{n+1})
-                || (numel (varargin{n+1}) == 1 && iscellstr (varargin{n+1})))
-              [comment_start, comment_end] = deal (char (varargin{n+1}), "cmt_eol");
-            open_comment = true;
-            elseif (iscellstr (varargin{n+1}) && numel (varargin{n+1}) == 2)
-              [comment_start, comment_end] = deal (varargin{n+1}{:});
-            else
-              ## FIXME: A user may have numeric values specified: {'//', 7}
-              ##        this will lead to an error in the warning message
-              error ("strread: unknown or unrecognized comment style '%s'",
-                      varargin{n+1});
-            endif
-        endswitch
-      case "delimiter"
-        delimiter_str = varargin{n+1};
-        if (strcmp (typeinfo (delimiter_str), "sq_string"))
-          delimiter_str = do_string_escapes (delimiter_str);
-        endif
-      case "emptyvalue"
-        numeric_fill_value = varargin{n+1};
-      case "expchars"
-        warning ("strread: property 'expchars' is not implemented");
-      case "whitespace"
-        white_spaces = varargin{n+1};
-        if (strcmp (typeinfo (white_spaces), "sq_string"))
-          white_spaces = do_string_escapes (white_spaces);
-        endif
-      ## The following parameters are specific to textscan and textread
-      case "endofline"
-        eol_char = varargin{n+1};
-        if (strcmp (typeinfo (eol_char), "sq_string"))
-          eol_char = do_string_escapes (eol_char);
-        endif
-        cmt_eol = eol_char;
-        open_comment = false;
-      case "returnonerror"
-        err_action = varargin{n+1};
-      case "multipledelimsasone"
-        mult_dlms_s1 = varargin{n+1};
-      case "treatasempty"
-        if (iscellstr (varargin{n+1}))
-          empty_str = varargin{n+1};
-        elseif (ischar (varargin{n+1}))
-          empty_str = varargin(n+1);
-        else
-          error ("strread: 'treatasempty' value must be string or cellstr");
-        endif
-      otherwise
-        warning ("strread: unknown property '%s'", varargin{n});
-    endswitch
-  endfor
-
-  ## First parse of FORMAT
-  if (strcmpi (strtrim (format), "%f"))
-    ## Default format specified.  Expand it (to desired nargout)
-    fmt_words = cell (max (nargout, 1), 1);
-    fmt_words (1:max (nargout, 1)) = format;
-  else
-    ## Determine the number of words per line as a first guess.  Forms
-    ## like %f<literal>) (w/o delimiter in between) are fixed further on
-    format = strrep (format, "%", " %");
-    fmt_words = regexp (format, '[^ ]+', "match");
-
-    ## Find position of conversion specifiers (they start with %)
-    fcs_ptrn = '(%\*?(\d*|\d*\.\d*)?[nfduscq]|%\*?\[)';
-    idy2 = find (! cellfun ("isempty", regexp (fmt_words, fcs_ptrn)));
-
-    ## 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.");
-    endif
-
-    ## Format conversion specifiers following literals w/o space/delim
-    ## in between are separate now.  Separate those w trailing literals
-    a = strfind (fmt_words(idy2), "%");
-    b = regexp (fmt_words(idy2), '[nfdus]', "end");
-    for jj = 1:numel (a)
-      ## From right to left to avoid losing track
-      ii = numel (a) - jj + 1;
-      ## Check for illegal format specifiers
-      if (isempty (b{ii}))
-        error ("strread: unknown format specifier #%d ('%s')\n",
-              ii, fmt_words{idy2(ii)});
-      endif
-      if (! (length (fmt_words{idy2(ii)}) == b{ii}(1)))
-        ## Split fmt_words(ii) into % conv specifier and trailing literal
-        fmt_words(idy2(ii)+1 : end+1) = fmt_words(idy2(ii) : end);
-        fmt_words{idy2(ii)} = fmt_words{idy2(ii)}(a{ii} : b{ii}(1));
-        fmt_words{idy2(ii)+1} = fmt_words{idy2(ii)+1}(b{ii}+1:end);
-      endif
-    endfor
-  endif
-  num_words_per_line = numel (fmt_words);
-
-  ## Special handling for CRLF EOL character in str
-  if (! isempty (eol_char) && strcmp (eol_char, "\r\n"))
-    ## Strip CR from CRLF sequences
-    str = strrep (str, "\r\n", "\n");
-    ## CR serves no further purpose in function
-    eol_char = "\n";
-  endif
-
-  ## Remove comments in str
-  if (comment_flag)
-    ## Expand 'cmt_eol' here, after option processing which may have set value
-    comment_end = strrep (comment_end, "cmt_eol", cmt_eol);
-    cstart = strfind (str, comment_start);
-    cstop  = strfind (str, comment_end);
-    if (open_comment)
-      cstop -= 1;
-    endif
-    ## Treat end of string as additional comment stop
-    if (isempty (cstop) || cstop(end) != length (str))
-      cstop(end+1) = length (str);
-    endif
-    if (! isempty (cstart))
-      ## Ignore nested openers.
-      [idx, cidx] = unique (lookup (cstop, cstart), "first");
-      if (idx(end) == length (cstop))
-        cidx(end) = []; # Drop the last one if orphaned.
-      endif
-      cstart = cstart(cidx);
-    endif
-    if (! isempty (cstop))
-      ## Ignore nested closers.
-      [idx, cidx] = unique (lookup (cstart, cstop), "first");
-      if (idx(1) == 0)
-        cidx(1) = []; # Drop the first one if orphaned.
-      endif
-      cstop = cstop(cidx);
-    endif
-    len = length (str);
-    c2len = length (comment_end);
-    if (cstop + c2len == len)
-      ## Ignore last char of to-the-end-of-line comments
-      c2len += 1;
-    endif
-    str = cellslices (str, [1, cstop + c2len], [cstart - 1, len]);
-    str = [str{:}];
-  endif
-
-  if (! isempty (white_spaces))
-    ## For numeric fields, whitespace is always a delimiter, but not for text
-    ## fields
-    if (isempty (regexp (format, '%\*?\d*s')))
-      ## Add whitespace to delimiter set
-      delimiter_str = unique ([white_spaces delimiter_str]);
-    else
-      ## Remove any delimiter chars from white_spaces list
-      white_spaces = setdiff (white_spaces, delimiter_str);
-    endif
-  endif
-  if (isempty (delimiter_str))
-    delimiter_str = " ";
-  endif
-  if (! isempty (eol_char))
-    ## Add eol_char to delimiter collection
-    delimiter_str = unique ([delimiter_str eol_char]);
-    ## and remove it from whitespace collection
-    white_spaces = strrep (white_spaces, eol_char, '');
-  endif
-
-  ii = numel (fmt_words);
-  while (ii > 0)
-    if (ismember (fmt_words{ii}, delimiter_str)(1))
-      fmt_words(ii) = [];
-      --num_words_per_line;
-    endif
-    --ii;
-  endwhile
-
-  pad_out = 0;
-  ## Trim whitespace if needed
-  if (! isempty (white_spaces))
-    ## Check if trailing "\n" might signal padding output arrays to equal size
-    ## before it is trimmed away below
-    if (str(end) == "\n" && nargout > 1)
-      pad_out = 1;
-    endif
-    ## Condense all repeated whitespace into one single space
-    ## FIXME: this will also fold repeated whitespace in a char field
-    rxp_wsp = sprintf ("[%s]+", white_spaces);
-    str = regexprep (str, rxp_wsp, ' ');
-    ## Remove possible leading space at string
-    if (str(1) == " ")
-       str = str(2:end);
-    endif
-    ## Check for single delimiter followed/preceded by whitespace
-    if (! isempty (delimiter_str))
-      dlmstr = setdiff (delimiter_str, " ");
-      if (! isempty (dlmstr))
-        rxp_dlmwsp = sprintf ('( [%s] | [%s]|[%s] )', dlmstr, dlmstr, dlmstr);
-        str = regexprep (str, rxp_dlmwsp, delimiter_str(1));
-      endif
-    endif
-    ## Wipe leading and trailing whitespace on each line (it may be
-    ## delimiter too)
-    ## FIXME: Double strrep on str is enormously expensive in CPU time.
-    ## Can this be eliminated?
-    if (! isempty (eol_char))
-      str = strrep (str, [eol_char " "], eol_char);
-      str = strrep (str, [" " eol_char], eol_char);
-    endif
-  endif
-
-  ## Split 'str' into words
-  words = split_by (str, delimiter_str, mult_dlms_s1, eol_char);
-  if (! isempty (white_spaces))
-    ## Trim leading and trailing 'white_spaces'.
-    ## All whitespace has been converted to space above
-    words = strtrim (words);
-  endif
-  num_words = numel (words);
-  ## First guess at nr. of lines in file (ignoring leading/trailing literals)
-  num_lines = ceil (num_words / num_words_per_line);
-
-  ## Replace TreatAsEmpty char sequences by empty strings
-  if (! isempty (empty_str))
-    for ii = 1:numel (empty_str)
-      idz = strncmp (empty_str{ii}, words, length (empty_str{ii}));
-      words(idz) = {""};
-    endfor
-  endif
-
-  ## fmt_words has been split properly now, but words{} has only been split on
-  ## delimiter positions.  As numeric fields can also be separated by
-  ## whitespace, more splits may be needed.
-  ## We also don't know the number of lines (as EndOfLine may have been set to
-  ## "" (empty) by the caller).
-  ##
-  ## We also may have to cope with 3 cases as far as literals go:
-  ## A: Trailing literals (%f<literal>) w/o delimiter in between.
-  ## B: Leading literals (<literal>%f) w/o delimiter in between.
-  ## C. Skipping leftover parts of specified skip fields (%*N )
-  ## Some words columns may have to be split further to fix these.
-  ## To find out, we'll match fmt_words to the words array to see what
-  ## needs to be done.  fwptr tracks which {fmt_words} starts in what {words}
-
-  ## Find indices and pointers to possible literals in fmt_words
-  idf = cellfun ("isempty", strfind (fmt_words, "%"));
-  ## Find indices and pointers to conversion specifiers with fixed width
-  idg = ! cellfun ("isempty", regexp (fmt_words, '%\*?\d'));
-  idy = find (idf | idg);
-  ## Find indices to numeric conversion specifiers
-  idn = ! cellfun ("isempty", regexp (fmt_words, '%[dnfu]'));
-
-  ## If needed, split up columns in three steps:
-  if (! isempty (idy))
-    ## Try-catch because complexity of strings to read can be infinite
-    try
-
-      ## 1. Assess "period" in the split-up words array ( < num_words_per_line).
-      ## Could be done using EndOfLine but that prohibits EndOfLine = "" option.
-      ## Alternative below goes by simply parsing a first grab of words and
-      ## matching fmt_words to words until the fmt_words array is exhausted.
-      ## iwrd: ptr to current analyzed word.
-      ## iwrdp: ptr to pos before analyzed char.
-      iwrd = 1; iwrdp = 0; iwrdl = length (words{1});
-      fwptr = zeros (1, numel (fmt_words));
-      ii = 1;
-      while (ii <= numel (fmt_words))
-
-        nxt_wrd = 0;
-        ## Keep track of which words nr. every fmt_words{} is (starts) in.
-        fwptr(ii) = iwrd;
-
-        if (idf(ii))
-          ## Literal expected
-          if (isempty (strfind (fmt_words{ii}, words(iwrd))))
-            ## Not found in current word; supposed to be in next word
-            nxt_wrd = 1;
-          else
-            ## Found it in current word.  Subtract literal length
-            iwrdp += length (fmt_words{ii});
-            if (iwrdp > iwrdl)
-              ## Parse error.  Literal extends beyond delimiter (word boundary)
-              warning ("strread: literal '%s' (fmt spec # %d) does not match data", ...
-                fmt_words{ii}, ii);
-              ## Word assumed to be completely "used up".  Next word
-              nxt_wrd = 1;
-            elseif (iwrdp == iwrdl)
-              ## Word completely "used up".  Next word
-              nxt_wrd = 1;
-            endif
-          endif
-
-        elseif (idg(ii))
-          ## Fixed width specifier (%N or %*N): read just a part of word
-          sw = regexp (fmt_words{ii}, '\d', "once");
-          ew = regexp (fmt_words{ii}, '[nfuds]') - 1;
-          iwrdp += floor (str2double (fmt_words{ii}(sw:ew)));
-          if (iwrdp > iwrdl)
-            ## Match error.  Field extends beyond word boundary.
-            warning  ...
-            ("strread: field width '%s' (fmt spec # %d) extends beyond actual word limit", ...
-               fmt_words{ii}, ii);
-            ## Assume word to be completely "used up".  Next word
-            nxt_wrd = 1;
-          elseif (iwrdp == iwrdl)
-            ## Word completely "used up".  Next word
-            nxt_wrd = 1;
-          endif
-
-        else
-          ## A simple format conv. specifier.  Either (1) uses rest of word, or
-          ## (2) is squeezed between current iwrdp and next literal, or (3) uses
-          ## next word. (3) is already taken care of.  So just check (1) & (2)
-          if (ii < numel (fmt_words) && idf(ii+1))
-            ## Next fmt_word is a literal...
-            if (! index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1}))
-              ## ...but not found in current word => field uses rest of word
-              nxt_wrd = 1;
-            else
-              ## ..or it IS found.  Add inferred width of current conversion field
-              iwrdp += index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1}) - 1;
-            endif
-          elseif (iwrdp <= iwrdl)
-            ## No bordering literal to the right => field occupies (rest of) word
-            nxt_wrd = 1;
-          endif
-
-        endif
-
-        if (nxt_wrd)
-          ++iwrd; iwrdp = 0;
-          if (iwrd > numel (words))
-            ## Apparently EOF; assume incomplete row already at L.1 of data
-            ii = numel (fmt_words);
-          elseif (ii < numel (fmt_words) && iwrd <= numel (words))
-            iwrdl = length (words{iwrd});
-          endif
-        endif
-
-        ++ii;
-
-      endwhile
-      ## Done
-      words_period = max (iwrd - 1, 1);
-      num_lines = ceil (num_words / words_period);
-
-      ## 2. Pad words array so that it can be reshaped
-      num_words_padded = num_lines * words_period - num_words;
-      if (num_words_padded)
-        words = [words'; cell(num_words_padded, 1)];
-      endif
-      words = reshape (words, words_period, num_lines);
-
-      ## 3. Do the column splitting on rectangular words array
-      icol = 1; ii = 1;    # icol = current column, ii = current fmt_word
-      while (ii <= num_words_per_line)
-
-        ## Check if fmt_words(ii) contains a literal or fixed-width
-        if ((idf(ii) || idg(ii)) && (rows (words) < num_words_per_line))
-          if (idf(ii))
-            s = strfind (words(icol, 1), fmt_words{ii});
-            if (isempty (s{:}))
-              error ("strread: Literal '%s' not found in column %d", fmt_words{ii}, icol);
-            endif
-            s = s{:}(1);
-            e = s(1) + length (fmt_words{ii}) - 1;
-          endif
-          if (! strcmp (fmt_words{ii}, words{icol, 1}))
-            ## Column doesn't exactly match literal => split needed.
-            ## Insert a column
-            words(icol+1:end+1, :) = words(icol:end, :);
-            ## Watch out for empty cells
-            jptr = find (! cellfun ("isempty", words(icol, :)));
-
-            ## Distinguish leading or trailing literals
-            if (! idg(ii) && ! isempty (s) && s(1) == 1)
-              ## Leading literal.
-              ## Assign literal to icol, paste rest in icol + 1
-              ## Apply only to those cells that do have something beyond literal
-              jptr = find (cellfun ("length", words(icol+1, jptr), ...
-                                    "UniformOutput", false) > e(1));
-              words(icol+1, :) = {""};
-              words(icol+1, jptr) = cellfun (
-                @(x) substr (x, e(1)+1, length (x) - e(1)), words(icol, jptr),
-                "UniformOutput", false);
-              words(icol, jptr) = fmt_words{ii};
-              fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
-
-            else
-              if (idg(ii))
-                ## Current field = fixed width.
-                ## Strip into icol, rest in icol+1
-                sw = regexp (fmt_words{ii}, '\d', "once");
-                ew = regexp (fmt_words{ii}, '[nfuds]') - 1;
-                wdth = floor (str2double (fmt_words{ii}(sw:ew)));
-                words(icol+1, jptr) = cellfun (@(x) x(wdth+1:end),
-                     words(icol,jptr), "UniformOutput", false);
-                if (isempty ([words(icol+1, :){:}]))
-                  ## Apparently split wasn't needed as turns out to cover
-                  ## entire column. So delete column again
-                  words(icol+1, :) = [];
-                else
-                  words(icol, jptr) = strtrunc (words(icol, jptr), wdth);
-                  fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
-                endif
-              else
-                if (! isempty (strfind (fmt_words{ii-1}, "%s")))
-                  ## Trailing literal.
-                  ## Could be ambiguous if preceding format == '%s'
-                  warning ("strread.m:\n  Ambiguous '%%s' specifier immediately before literal in column %d", icol);
-                endif
-                ## FIXME: this assumes char(254)/char(255) won't occur in input!
-                clear wrds;
-                wrds(1:2:2*numel (words(icol, jptr))) = ...
-                     strrep (words(icol, jptr), fmt_words{ii}, ...
-                     [char(255) char(254)]);
-                wrds(2:2:2*numel (words(icol, jptr))-1) = char (255);
-                wrds = ostrsplit ([wrds{:}], char (255));
-                words(icol, jptr) = ...
-                  wrds(find (cellfun ("isempty", strfind (wrds, char (254)))));
-                wrds(find (cellfun ("isempty", strfind (wrds, char (254))))) ...
-                   = char (255);
-                words(icol+1, jptr) = ostrsplit (strrep ([wrds{2:end}], ...
-                   char (254), fmt_words{ii}), char (255));
-                ## Former trailing literal may now be leading for next specifier
-                --ii;
-                fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
-              endif
-            endif
-          endif
-
-        else
-          ## Conversion specifier.
-          ## Peek if next fmt_word needs split from current column.
-          if (ii < num_words_per_line)
-            if (fwptr(ii) == fwptr(ii+1))
-              --icol;
-            endif
-          endif
-        endif
-        ## Next fmt_word, next column
-        ++ii; ++icol;
-      endwhile
-
-      ## Done.
-      ## Reshape words back into one long vector and strip padded empty words
-      words = reshape (words, 1, numel (words))(1 : end-num_words_padded);
-
-    catch
-      warning ("strread: unable to parse text or file with given format string");
-      return;
-
-    end_try_catch
-  endif
-
-  ## For each specifier, process corresponding column
-  k = 1;
-  for m = 1:num_words_per_line
-    try
-      if (format_repeat_count < 0)
-        data = words(m:num_words_per_line:end);
-      elseif (format_repeat_count == 0)
-        data = {};
-      else
-        lastline = ...
-          min (num_words_per_line * format_repeat_count + m - 1, numel (words));
-        data = words(m:num_words_per_line:lastline);
-        if (num_lines > format_repeat_count)
-          num_lines = format_repeat_count;
-        endif
-      endif
-
-      ## Map to format
-      ## FIXME: Add support for formats like "<%s>", "%[a-zA-Z]"
-      ##        Someone with regexp experience is needed.
-      switch (fmt_words{m}(1:min (2, length (fmt_words{m}))))
-        case "%s"
-          if (pad_out)
-            data(end+1:num_lines) = {""};
-          endif
-          varargout{k} = data';
-          k += 1;
-        case {"%d", "%u", "%f", "%n"}
-          n = cellfun ("isempty", data);
-          ### FIXME: Erroneously formatted data lead to NaN, not an error
-          data = str2double (data);
-          if (! isempty (regexp (fmt_words{m}, "%[du]")))
-            ## Cast to integer
-            ## FIXME: NaNs will be transformed into zeros
-            data = int32 (data);
-          endif
-          data(n) = numeric_fill_value;
-          if (pad_out)
-            data(end+1:num_lines) = numeric_fill_value;
-          endif
-          varargout{k} = data.';
-          k += 1;
-        case {"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%8", "%9"}
-          sw = regexp (fmt_words{m}, '\d', "once");
-          ew = regexp (fmt_words{m}, '[nfudsq]') - 1;
-          nfmt = ostrsplit (fmt_words{m}(2:ew), ".");
-          swidth = str2double (nfmt{1});
-          switch (fmt_words{m}(ew+1))
-            case {"d", "u", "f", "n"}
-              n = cellfun ("isempty", data);
-              ### FIXME: Erroneously formatted data lead to NaN, not an error
-              ###        => ReturnOnError can't be implemented for numeric data
-              data = str2double (strtrunc (data, swidth));
-              data(n) = numeric_fill_value;
-              if (pad_out)
-                data(end+1:num_lines) = numeric_fill_value;
-              endif
-              if (numel (nfmt) > 1)
-                sprec = str2double (nfmt{2});
-                data = 10^-sprec * round (10^sprec * data);
-              elseif (! isempty (regexp (fmt_words{m}, "[du]")))
-                ## Cast to integer
-                ## FIXME: NaNs will be transformed into zeros
-                data = int32 (data);
-              endif
-              varargout{k} = data.';
-              k += 1;
-            case "s"
-              if (pad_out)
-                data(end+1:num_lines) = {""};
-              endif
-              varargout{k} = strtrunc (data, swidth)';
-              k += 1;
-            otherwise
-          endswitch
-        case {"%*", "%*s"}
-          ## skip the word
-        otherwise
-          ## Ensure descriptive content is consistent.
-          ## Test made a bit lax to accomodate for incomplete last lines
-          n = find (! cellfun ("isempty", data));
-          if (numel (unique (data(n))) > 1
-              || ! strcmpi (unique (data), fmt_words{m}))
-            error ("strread: FORMAT does not match data");
-          endif
-      endswitch
-    catch
-      ## As strread processes columnwise, ML-compatible error processing
-      ## (row after row) is not feasible.  In addition Octave sets
-      ## unrecognizable numbers to NaN w/o error.  But maybe Octave is better
-      ## in this respect.
-      if (err_action)
-        ## Just try the next column where ML bails out
-      else
-        rethrow (lasterror);
-      endif
-    end_try_catch
-  endfor
-
-endfunction
-
-function out = split_by (text, sep, mult_dlms_s1, eol_char)
-
-  ## Check & if needed, process MultipleDelimsAsOne parameter
-  if (mult_dlms_s1)
-    mult_dlms_s1 = true;
-    ## FIXME: Should re-implement strsplit() function here in order
-    ## to avoid strrep on megabytes of data.
-    ## If \n is in sep collection we need to enclose it in text
-    ## to avoid it being included in consecutive delim series
-    enchr = ' ';
-    ## However watch out if eol_char is also in delimiters
-    if (index (sep, eol_char)); enchr = char (255); endif
-    text = strrep (text, eol_char, [enchr eol_char enchr]);
-  else
-    mult_dlms_s1 = false;
-  endif
-
-  ## Split text string along delimiters
-  out = ostrsplit (text, sep, mult_dlms_s1);
-  if (index (sep, eol_char)); out = strrep (out, char (255), ''); endif
-  ## In case of trailing delimiter, strip stray last empty word
-  if (! isempty (out) && any (sep == text(end)) && ! mult_dlms_s1)
-    out(end) = [];
-  endif
-
-  ## Empty cells converted to empty cellstrings.
-  out(cellfun ("isempty", out)) = {""};
-
-endfunction
-
-
-%!test
-%! [a, b] = strread ("1 2", "%f%f");
-%! assert (a, 1);
-%! assert (b, 2);
-
-%!test
-%! str = "";
-%! a = rand (10, 1);
-%! b = char (randi ([65, 85], 10, 1));
-%! for k = 1:10
-%!   str = sprintf ("%s %.6f %s\n", str, a(k), b(k));
-%! endfor
-%! [aa, bb] = strread (str, "%f %s");
-%! assert (aa, a, 1e-6);
-%! assert (bb, cellstr (b));
-
-%!test
-%! str = "";
-%! a = rand (10, 1);
-%! b = char (randi ([65, 85], 10, 1));
-%! for k = 1:10
-%!   str = sprintf ("%s %.6f %s\n", str, a(k), b(k));
-%! endfor
-%! aa = strread (str, "%f %*s");
-%! assert (aa, a, 1e-6);
-
-%!test
-%! str = sprintf ("/* this is\nacomment*/ 1 2 3");
-%! a = strread (str, "%f", "commentstyle", "c");
-%! assert (a, [1; 2; 3]);
-
-%!test
-%! str = "# comment\n# comment\n1 2 3";
-%! [a, b] = strread (str, "%n %s", "commentstyle", "shell", "endofline", "\n");
-%! assert (a, [1; 3]);
-%! assert (b, {"2"});
-
-%!test
-%! assert (strread ("Hello World! // this is comment", "%s",
-%!                  "commentstyle", "c++"),
-%!         {"Hello"; "World!"});
-%! assert (strread ("Hello World! % this is comment", "%s",...
-%!                  "commentstyle", "matlab"), ...
-%!         {"Hello"; "World!"});
-%! assert (strread ("Hello World! # this is comment", "%s",...
-%!                  "commentstyle", "shell"), ...
-%!         {"Hello"; "World!"});
-
-%!test <*49454>
-%! assert (strread ("hello%foo\nworld, another%bar\r\nday", "%s", ...
-%!                  "commentstyle", "matlab", "delimiter", " ,"),...
-%!         {"hello"; "world"; "another"; "day"});
-
-%!test
-%! str = sprintf ("Tom 100 miles/hr\nDick 90 miles/hr\nHarry 80 miles/hr");
-%! fmt = "%s %f miles/hr";
-%! c = cell (1, 2);
-%! [c{:}] = strread (str, fmt);
-%! assert (c{1}, {"Tom"; "Dick"; "Harry"});
-%! assert (c{2}, [100; 90; 80]);
-
-%!test
-%! a = strread ("a b c, d e, , f", "%s", "delimiter", ",");
-%! assert (a, {"a b c"; "d e"; ""; "f"});
-
-%! ## Format repeat counters w & w/o trailing EOL even within partly read files
-%!test
-%! [a, b] = strread ("10 a 20 b\n 30 c 40", "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"});
-%! [a, b] = strread ("10 a 20 b\n 30 c 40\n", "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; ""});
-%! [a, b] = strread ("10 a 20 b\n 30 c 40", "%d %s", 1);
-%! assert (a, int32 (10));
-%! assert (b, {"a"});
-
-%!test <*33536>
-%! [a, b, c] = strread ("1,,2", "%s%s%s", "delimiter", ",");
-%! assert (a{1}, "1");
-%! assert (b{1}, "");
-%! assert (c{1}, "2");
-
-%!test <*33536>
-%!test
-%! a = strread ("[SomeText]", "[%s", "delimiter", "]");
-%! assert (a{1}, "SomeText");
-
-%!test
-%! dat = "Data file.\r\n=  =  =  =  =\r\nCOMPANY    : <Company name>\r\n";
-%! a = strread (dat, "%s", "delimiter", "\n", "whitespace", "", "endofline", "\r\n");
-%! assert (a{2}, "=  =  =  =  =");
-%! assert (double (a{3}(end-5:end)), [32 110 97 109 101 62]);
-
-%!test
-%! [a, b, c, d] = strread ("1,2,3,,5,6", "%d%f%d%f", "delimiter", ",");
-%! assert (c, int32 (3));
-%! assert (d, NaN);
-
-%!test
-%! [a, b, c, d] = strread ("1,2,3,,5,6\n", "%d%d%f%d", "delimiter", ",");
-%! assert (c, [3; NaN]);
-%! assert (d, int32 ([0; 0]));
-
-## Default format (= %f)
-%!test
-%! [a, b, c] = strread ("0.12 0.234 0.3567");
-%! assert (a, 0.12);
-%! assert (b, 0.234);
-%! assert (c, 0.3567);
-
-%!test
-%! [a, b] = strread ("0.41 8.24 3.57 6.24 9.27", "%f%f", 2, "delimiter", " ");
-%! assert (a, [0.41; 3.57]);
-
-## TreatAsEmpty
-%!test
-%! [a, b, c, d] = strread ("1,2,3,NN,5,6\n", "%d%d%d%f", "delimiter", ",", "TreatAsEmpty", "NN");
-%! assert (c, int32 ([3; 0]));
-%! assert (d, [NaN; NaN]);
-
-## No delimiters at all besides EOL.  Plain reading numbers & strings
-%!test
-%! str = "Text1Text2Text\nText398Text4Text\nText57Text";
-%! [a, b] = strread (str, "Text%dText%1sText");
-%! assert (a, int32 ([1; 398; 57]));
-%! assert (b(1:2), {"2"; "4"});
-%! assert (isempty (b{3}), true);
-
-## MultipleDelimsAsOne
-%!test
-%! str = "11, 12, 13,, 15\n21,, 23, 24, 25\n,, 33, 34, 35";
-%! [a b c d] = strread (str, "%f %f %f %f", "delimiter", ",", "multipledelimsasone", 1, "endofline", "\n");
-%! assert (a', [11, 21, NaN]);
-%! assert (b', [12, 23, 33]);
-%! assert (c', [13, 24, 34]);
-%! assert (d', [15, 25, 35]);
-
-%!assert <*44750> (strread ('/home/foo/','%s','delimiter','/','MultipleDelimsAsOne',1),
-%!                {"home"; "foo"})
-
-## delimiter as sq_string and dq_string
-%!assert (strread ("1\n2\n3", "%d", "delimiter", "\n"),
-%!        strread ("1\n2\n3", "%d", "delimiter", '\n'))
-
-## whitespace as sq_string and dq_string
-%!assert (strread ("1\b2\r3\b4\t5", "%d", "whitespace", "\b\r\n\t"),
-%!        strread ("1\b2\r3\b4\t5", "%d", "whitespace", '\b\r\n\t'))
-
-%!test
-%! str =  "0.31 0.86 0.94\n 0.60 0.72 0.87";
-%! fmt = "%f %f %f";
-%! args = {"delimiter", " ", "endofline", "\n", "whitespace", " "};
-%! [a, b, c] = strread (str, fmt, args{:});
-%! assert (a, [0.31; 0.60], 0.01);
-%! assert (b, [0.86; 0.72], 0.01);
-%! assert (c, [0.94; 0.87], 0.01);
-
-%!test
-%! str =  "0.31,0.86,0.94\n0.60,0.72,0.87";
-%! fmt = "%f %f %f";
-%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
-%! [a, b, c] = strread (str, fmt, args{:});
-%! assert (a, [0.31; 0.60], 0.01);
-%! assert (b, [0.86; 0.72], 0.01);
-%! assert (c, [0.94; 0.87], 0.01);
-
-%!test
-%! str =  "0.31 0.86 0.94\n 0.60 0.72 0.87";
-%! fmt = "%f %f %f";
-%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
-%! [a, b, c] = strread (str, fmt, args{:});
-%! assert (a, [0.31; 0.60], 0.01);
-%! assert (b, [0.86; 0.72], 0.01);
-%! assert (c, [0.94; 0.87], 0.01);
-
-%!test
-%! str =  "0.31, 0.86, 0.94\n 0.60, 0.72, 0.87";
-%! fmt = "%f %f %f";
-%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
-%! [a, b, c] = strread (str, fmt, args{:});
-%! assert (a, [0.31; 0.60], 0.01);
-%! assert (b, [0.86; 0.72], 0.01);
-%! assert (c, [0.94; 0.87], 0.01);
-
-%!test
-%! [a, b] = strread (["Empty 1" char(10)], "Empty%s %f");
-%! assert (a{1}, '1');
-%! assert (b, NaN);
-
-%!test
-%! [a, b] = strread (["Empty" char(10)], "Empty%f %f");
-%! assert (a, NaN);
-%! assert (b, NaN);
-
-%!test <*35999>
-%! [a, b, c] = strread ("", "%f");
-%! assert (isempty (a));
-%! assert (isempty (b));
-%! assert (isempty (c));
-
-%!test <*37023>
-%! [a, b] = strread (" 1. 1 \n  2 3 \n", "%f %f", "endofline", "\n");
-%! assert (a, [1; 2], 1e-15);
-%! assert (b, [1; 3], 1e-15);
-
-## Test for no output arg (interactive use)
-%!assert (strread (",2,,4\n5,,7,", "", "delimiter", ","),
-%!        [NaN; 2; NaN; 4; 5; NaN; 7])
-
-## Test #1 bug #42609
-%!test <*42609>
-%! [a, b, c] = strread ("1 2 3\n4 5 6\n7 8 9\n", "%f %f %f\n");
-%! assert (a, [1; 4; 7]);
-%! assert (b, [2; 5; 8]);
-%! assert (c, [3; 6; 9]);
-
-## Test #2 bug #42609
-%!test <*42609>
-%! [a, b, c] = strread ("1 2\n3\n4 5\n6\n7 8\n9\n", "%f %f\n%f");
-%! assert (a, [1;4;7]);
-%! assert (b, [2; 5; 8]);
-%! assert (c, [3; 6; 9]);
-
-## Test #3 bug #42609
-%!test <*42609>
-%! [a, b, c] = strread ("1 2 3\n4 5 6\n7 8 9\n", '%f %f %f\n');
-%! assert (a, [1; 4; 7]);
-%! assert (b, [2; 5; 8]);
-%! assert (c, [3; 6; 9]);
-
-## Test #4 bug #42609
-%!test <*42609>
-%! [a, b, c] = strread ("1 2\n3\n4 5\n6\n7 8\n9\n", '%f %f\n%f');
-%! assert (a, [1;4;7]);
-%! assert (b, [2; 5; 8]);
-%! assert (c, [3; 6; 9]);
-
-## Unsupported format specifiers
-%!error <format specifiers are not supported> strread ("a", "%c")
-%!error <format specifiers are not supported> strread ("a", "%*c %d")
-%!error <format specifiers are not supported> strread ("a", "%q")
-%!error <format specifiers are not supported> strread ("a", "%*q %d")
-%!error <format specifiers are not supported> strread ("a", "%[a]")
-%!error <format specifiers are not supported> strread ("a", "%*[a] %d")
-%!error <format specifiers are not supported> strread ("a", "%[^a]")
-%!error <format specifiers are not supported> strread ("a", "%*[^a] %d")
-%!error <format specifiers are not supported> strread ("a", "%d8")
-%!error <format specifiers are not supported> strread ("a", "%*d8 %s")
-%!error <format specifiers are not supported> strread ("a", "%f64")
-%!error <format specifiers are not supported> strread ("a", "%*f64 %s")
-%!error <format specifiers are not supported> strread ("a", "%u32")
-%!error <format specifiers are not supported> strread ("a", "%*u32 %d")
-
-## Illegal format specifiers
-%!error <no valid format conversion specifiers> strread ("1.0", "%z")
-
-## Test for false positives in check for non-supported format specifiers
-%!assert (strread ("Total: 32.5 % (of cm values)","Total: %f % (of cm values)"), 32.5, 1e-5)
-
-## Test various forms of string format specifiers
-%!test <*45712>
-%! str = "14 :1 z:2 z:3 z:5 z:11";
-%! [a, b, c, d] = strread (str, "%f %s %*s %3s %*3s %f", "delimiter", ":");
-%! assert ({a, b, c, d}, {14, {"1 z"}, {"3 z"}, 11});
-
-## Allow cuddling %sliteral but warn that it is ambiguous
-%!warning <Ambiguous '%s' specifier immediately before literal in column 1>
-%! [a, b] = strread ("abcxyz51\nxyz83\n##xyz101", "%s xyz %d");
-%! assert (a([1 3]), {"abc"; "##"});
-%! assert (isempty (a{2}), true);
-%! assert (b, int32([51; 83; 101]));
--- a/scripts/io/textread.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,509 +0,0 @@
-## Copyright (C) 2009-2018 Eric Chassande-Mottin, CNRS (France)
-##
-## 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{a}, @dots{}] =} textread (@var{filename})
-## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format})
-## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n})
-## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{prop1}, @var{value1}, @dots{})
-## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n}, @var{prop1}, @var{value1}, @dots{})
-## Read data from a text file.
-##
-## The file @var{filename} is read and parsed according to @var{format}.  The
-## function behaves like @code{strread} except it works by parsing a file
-## instead of a string.  See the documentation of @code{strread} for details.
-##
-## In addition to the options supported by @code{strread}, this function
-## supports two more:
-##
-## @itemize
-## @item @qcode{"headerlines"}:
-## The first @var{value} number of lines of @var{filename} are skipped.
-##
-## @item @qcode{"endofline"}:
-## Specify a single character or
-## @qcode{"@xbackslashchar{}r@xbackslashchar{}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
-##
-## The optional input @var{n} (format repeat count) specifies the number of
-## times the format string is to be used or the number of lines to be read,
-## whichever happens first while reading.  The former is equivalent to
-## requesting that the data output vectors should be of length @var{N}.
-## Note that when reading files with format strings referring to multiple
-## lines, @var{n} should rather be the number of lines to be read than the
-## number of format string uses.
-##
-## If the format string is empty (not just omitted) and the file contains only
-## numeric data (excluding headerlines), textread will return a rectangular
-## matrix with the number of columns matching the number of numeric fields on
-## the first data line of the file.  Empty fields are returned as zero values.
-##
-## Examples:
-##
-## @example
-## @group
-##   Assume a data file like:
-##   1 a 2 b
-##   3 c 4 d
-##   5 e
-## @end group
-## @end example
-##
-## @example
-## @group
-##   [a, b] = textread (f, "%f %s")
-##   returns two columns of data, one with doubles, the other a
-##   cellstr array:
-##   a = [1; 2; 3; 4; 5]
-##   b = @{"a"; "b"; "c"; "d"; "e"@}
-## @end group
-## @end example
-##
-## @example
-## @group
-##   [a, b] = textread (f, "%f %s", 3)
-##   (read data into two culumns, try to use the format string
-##   three times)
-##   returns
-##   a = [1; 2; 3]
-##   b = @{"a"; "b"; "c"@}
-##
-## @end group
-## @end example
-##
-## @example
-## @group
-##   With a data file like:
-##   1
-##   a
-##   2
-##   b
-##
-##   [a, b] = textread (f, "%f %s", 2)
-##   returns a = 1 and b = @{"a"@}; i.e., the format string is used
-##   only once because the format string refers to 2 lines of the
-##   data file.  To obtain 2x1 data output columns, specify N = 4
-##   (number of data lines containing all requested data) rather
-##   than 2.
-## @end group
-## @end example
-##
-## @seealso{strread, load, dlmread, fscanf, textscan}
-## @end deftypefn
-
-function varargout = textread (filename, format = "%f", varargin)
-
-  BUFLENGTH = 4096;       # Read buffer to speed up processing @var{n}
-
-  ## Check input
-  if (nargin < 1)
-    print_usage ();
-  endif
-
-  if (! ischar (filename) || ! ischar (format))
-    error ("textread: FILENAME and FORMAT arguments must be strings");
-  endif
-
-  if (! isempty (varargin) && isnumeric (varargin{1}))
-    nlines = varargin{1};
-  else
-    nlines = Inf;
-  endif
-  if (nlines < 1)
-    printf ("textread: N = 0, no data read\n");
-    varargout = cell (1, nargout);
-    return;
-  endif
-
-  ## Read file
-  fid = fopen (filename, "r");
-  if (fid == -1)
-    error ("textread: could not open '%s' for reading", filename);
-  endif
-
-  ## Skip header lines if requested
-  headerlines = find (strcmpi (varargin, "headerlines"), 1);
-  if (! isempty (headerlines))
-    ## Beware of missing or wrong headerline value
-    if (headerlines == numel (varargin)
-       || ! isnumeric (varargin{headerlines + 1}))
-      error ("textread: missing or invalid value for 'headerlines'" );
-    endif
-    ## Avoid conveying floats to fskipl
-    varargin{headerlines + 1} = round (varargin{headerlines + 1});
-    ## Beware of zero valued headerline, fskipl would skip to EOF
-    if (varargin{headerlines + 1} > 0)
-      fskipl (fid, varargin{headerlines + 1});
-    elseif (varargin{headerlines + 1} < 0)
-      warning ("textread: negative headerline value ignored");
-    endif
-    varargin(headerlines:headerlines+1) = [];
-  endif
-  st_pos = ftell (fid);
-
-  ## Read a first file chunk.  Rest follows after endofline processing
-  [str, count] = fscanf (fid, "%c", BUFLENGTH);
-  if (isempty (str) || count < 1)
-    warning ("textread: empty file");
-    varargout = cell (1, nargout);
-    return;
-  endif
-
-  endofline = find (strcmpi (varargin, "endofline"), 1);
-  if (! isempty (endofline))
-    ## 'endofline' option set by user.
-    if (ischar (varargin{endofline + 1}))
-      eol_char = varargin{endofline + 1};
-      if (strcmp (typeinfo (eol_char), "sq_string"))
-        eol_char = do_string_escapes (eol_char);
-      endif
-      if (! any (strcmp (eol_char, {"", "\n", "\r", "\r\n"})))
-        error ("textread: invalid EndOfLine character value specified");
-      endif
-    else
-      error ("textread: character value required for EndOfLine");
-    endif
-  else
-    ## Determine EOL from file.
-    ## Search for EOL candidates in the first BUFLENGTH chars
-    ## FIXME: Ignore risk of 2-byte EOL (\r\n) being split at exactly BUFLENGTH
-    eol_srch_len = min (length (str), BUFLENGTH);
-    ## First try DOS (CRLF)
-    if (! isempty (strfind (str(1 : eol_srch_len), "\r\n")))
-      eol_char = "\r\n";
-    ## Perhaps old Macintosh? (CR)
-    elseif (! isempty (strfind (str(1 : eol_srch_len), "\r")))
-      eol_char = "\r";
-    ## Otherwise, use plain *nix (LF)
-    else
-      eol_char = "\n";
-    endif
-    ## Set up default endofline param value
-    varargin(end+1:end+2) = {"endofline", eol_char};
-  endif
-
-  ## Now that we know what EOL looks like, we can process format_repeat_count.
-  ## FIXME: The below isn't ML-compatible: counts lines, not format string uses
-  if (isfinite (nlines) && (nlines > 0))
-    l_eol_char = length (eol_char);
-    eoi = findstr (str, eol_char);
-    n_eoi = length (eoi);
-    nblks = 0;
-    ## Avoid slow repeated str concatenation, first seek requested end of data
-    while (n_eoi < nlines && count == BUFLENGTH)
-      [nstr, count] = fscanf (fid, "%c", BUFLENGTH);
-      if (count > 0)
-        ## Watch out for multichar EOL being missed across buffer boundaries
-        if (l_eol_char > 1)
-          str = [str(end - length (eol_char) + 2 : end) nstr];
-        else
-          str = nstr;
-        endif
-        eoi = findstr (str, eol_char);
-        n_eoi += numel (eoi);
-        ++nblks;
-      endif
-    endwhile
-    ## Handle case of missing or incomplete trailing EOL
-    if (! strcmp (str(end - length (eol_char) + 1 : end), eol_char))
-      eoi = [ eoi (length (str)) ];
-      ++n_eoi;
-    endif
-    ## Found EOL delimiting last requested line.  Compute ptr (incl. EOL)
-    if (isempty (eoi))
-      eoi_pos = nblks * BUFLENGTH + count;
-    else
-      eoi_pos = (nblks * BUFLENGTH) + eoi(end + min (nlines, n_eoi) - n_eoi);
-    endif
-    fseek (fid, st_pos, "bof");
-    str = fscanf (fid, "%c", eoi_pos);
-  else
-    fseek (fid, st_pos, "bof");
-    str = fread (fid, "char=>char").';
-  endif
-  fclose (fid);
-
-  ## Set up default whitespace param value if needed
-  if (isempty (find (strcmpi ("whitespace", varargin))))
-    varargin(end+1:end+2) = {"whitespace", " \b\t"};
-  endif
-
-  ## Call strread to make it do the real work
-  [varargout{1:max (nargout, 1)}] = strread (str, format, varargin{:});
-
-  ## Hack to concatenate/reshape numeric output into 2D array (undocumented ML)
-  ## In ML this only works in case of an empty format string
-  if (isempty (format))
-    ## Get number of fields per line.
-    ## 1. Get eol_char position
-    iwhsp = find (strcmpi ("whitespace", varargin));
-    whsp = varargin{iwhsp + 1};
-    idx = regexp (str, eol_char, "once");
-    ## 2. Get first data line til EOL. Avoid corner case of just one line
-    if (! isempty (idx))
-      str = str(1:idx-1);
-    endif
-    idelimiter = find (strcmpi (varargin, "delimiter"), 1);
-    if (isempty (idelimiter))
-      ## Assume delimiter = whitespace
-      ## 3A. whitespace incl. consecutive whitespace => single space
-      str = regexprep (str, sprintf ("[%s]+", whsp), ' ');
-      ## 4A. Remove possible leading & trailing spaces
-      str = strtrim (str);
-      ## 5A. Count spaces, add one to get nr of data fields per line
-      ncols = numel (strfind (str, " ")) + 1;
-    else
-      ## 3B. Just count delimiters. FIXME: delimiters could occur in literals
-      delimiter = varargin{idelimiter+1};
-      ncols = numel (regexp (str, sprintf ("[%s]", delimiter))) + 1;
-    endif
-    ## 6. Reshape; watch out, we need a transpose
-    nrows = ceil (numel (varargout{1}) / ncols);
-    pad = mod (numel (varargout{1}), ncols);
-    if (pad > 0)
-      pad = ncols - pad;
-      varargout{1}(end+1 : end+pad) = NaN;
-    endif
-    varargout{1} = reshape (varargout{1}, ncols, nrows)';
-    ## ML replaces empty values with NaNs
-    varargout{1}(find (isnan (varargout{1}))) = 0;
-  endif
-
-endfunction
-
-
-%!test
-%! f = tempname ();
-%! d = rand (5, 3);
-%! dlmwrite (f, d, "precision", "%5.2f");
-%! [a, b, c] = textread (f, "%f %f %f", "delimiter", ",", "headerlines", 3);
-%! unlink (f);
-%! assert (a, d(4:5, 1), 1e-2);
-%! assert (b, d(4:5, 2), 1e-2);
-%! assert (c, d(4:5, 3), 1e-2);
-
-%!test
-%! f = tempname ();
-%! d = rand (7, 2);
-%! dlmwrite (f, d, "precision", "%5.2f");
-%! [a, b] = textread (f, "%f, %f", "headerlines", 1);
-%! unlink (f);
-%! assert (a, d(2:7, 1), 1e-2);
-
-## Test reading 2D matrix with empty format
-%!test
-%! f = tempname ();
-%! d = rand (5, 2);
-%! dlmwrite (f, d, "precision", "%5.2f");
-%! A = textread (f, "", "headerlines", 3);
-%! unlink (f);
-%! assert (A, d(4:5, :), 1e-2);
-
-## Read multiple lines using empty format string
-%!test
-%! f = tempname ();
-%! unlink (f);
-%! fid = fopen (f, "w");
-%! d = rand (1, 4);
-%! fprintf (fid, "  %f %f   %f  %f ", d);
-%! fclose (fid);
-%! A = textread (f, "");
-%! unlink (f);
-%! assert (A, d, 1e-6);
-
-## Empty format, corner case = one line w/o EOL
-%!test
-%! f = tempname ();
-%! unlink (f);
-%! fid = fopen (f, "w");
-%! d = rand (1, 4);
-%! fprintf (fid, "  %f %f   %f  %f ", d);
-%! fclose (fid);
-%! A = textread (f, "");
-%! unlink (f);
-%! assert (A, d, 1e-6);
-
-## Tests with format repeat count #1
-%!test
-%! f = tempname ();
-%! fid = fopen (f, "w");
-%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d %s \n", ...
-%!                10, "a", 20, "b", 30, "c", 40, "d");
-%! fclose (fid);
-%! [a, b] = textread (f, "%d %s", 1);
-%! assert (a, int32 (10));
-%! assert (b, {"a"});
-%! [a, b] = textread (f, "%d %s", 2);
-%! assert (a, int32 ([10; 20]));
-%! assert (b, {"a"; "b"});
-%! [a, b] = textread (f, "%d %s", 3);
-%! assert (a, int32 ([10; 20; 30]));
-%! assert (b, {"a"; "b"; "c"});
-%! [a, b] = textread (f, "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; "d"});
-%! [a, b] = textread (f, "%d %s", 5);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; "d"});
-%! unlink (f);
-
-## Tests with format repeat count #2, missing last EOL
-%!test
-%! f = tempname ();
-%! fid = fopen (f, "w");
-%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d %s", ...
-%!                10, "a", 20, "b", 30, "c", 40, "d");
-%! fclose (fid);
-%! [a, b] = textread (f, "%d %s", 1);
-%! assert (a, int32 (10));
-%! assert (b, {"a"});
-%! [a, b] = textread (f, "%d %s", 2);
-%! assert (a, int32 ([10; 20]));
-%! assert (b, {"a"; "b"});
-%! [a, b] = textread (f, "%d %s", 3);
-%! assert (a, int32 ([10; 20; 30]));
-%! assert (b, {"a"; "b"; "c"});
-%! [a, b] = textread (f, "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; "d"});
-%! [a, b] = textread (f, "%d %s", 5);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; "d"});
-%! unlink (f);
-
-## Tests with format repeat count #3, incomplete last line
-%!test
-%! f = tempname ();
-%! fid = fopen (f, "w");
-%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d", ...
-%!                10, "a", 20, "b", 30, "c", 40);
-%! fclose (fid);
-%! [a, b] = textread (f, "%d %s", 1);
-%! assert (a, int32 (10));
-%! assert (b, {"a"});
-%! [a, b] = textread (f, "%d %s", 2);
-%! assert (a, int32 ([10; 20]));
-%! assert (b, {"a"; "b"});
-%! [a, b] = textread (f, "%d %s", 3);
-%! assert (a, int32 ([10; 20; 30]));
-%! assert (b, {"a"; "b"; "c"});
-%! [a, b] = textread (f, "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"});
-%! [a, b] = textread (f, "%d %s", 5);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"});
-%! unlink (f);
-
-## Tests with format repeat count #4, incomplete last line but with trailing EOL
-%!test
-%! f = tempname ();
-%! fid = fopen (f, "w");
-%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d\n", ...
-%!                10, "a", 20, "b", 30, "c", 40);
-%! fclose (fid);
-%! [a, b] = textread (f, "%d %s", 4);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; ""});
-%! [a, b] = textread (f, "%d %s", 5);
-%! assert (a, int32 ([10; 20; 30; 40]));
-%! assert (b, {"a"; "b"; "c"; ""});
-%! unlink (f);
-
-### Tests with format repeat count #5, nr of data lines = limiting factor
-#%!test
-#%! f = tempname ();
-#%! fid = fopen (f, "w");
-#%! fprintf (fid, "%2d\n%s\n%2dn%s", ...
-#%!                1, "a", 2, "b");
-#%! fclose (fid);
-#%! [a, b] = textread (f, "%d %s", 2);
-#%! assert (a, int32 (1));
-#%! assert (b, {"a"});
-
-### Read multiple lines using empty format string, missing data (should be 0)
-#%!test
-#%! f = tempname ();
-#%! unlink (f);
-#%! fid = fopen (f, "w");
-#%! d = rand (1, 4);
-#%! fprintf (fid, "%f, %f, ,  %f,  %f ", d);
-#%! fclose (fid);
-#%! A = textread (f, "");
-#%! unlink (f);
-#%! assert (A, [ d(1:2) 0 d(3:4)], 1e-6);
-
-### Test with empty positions - ML returns 0 for empty fields
-#%!test
-#%! f = tempname ();
-#%! unlink (f);
-#%! fid = fopen (f, "w");
-#%! d = rand (1, 4);
-#%! fprintf (fid, ",2,,4\n5,,7,\n");
-#%! fclose (fid);
-#%! A = textread (f, "", "delimiter", ",");
-#%! unlink (f);
-#%! assert (A, [0 2 0 4; 5 0 7 0], 1e-6);
-
-### Another test with empty format + positions, now with more incomplete lower
-### row (must be appended with zeros to get rectangular matrix)
-#%!test
-#%! f = tempname ();
-#%! unlink (f);
-#%! fid = fopen (f, "w");
-#%! d = rand (1, 4);
-#%! fprintf (fid, ",2,,4\n5,\n");
-#%! fclose (fid);
-#%! A = textread (f, "", "delimiter", ",");
-#%! unlink (f);
-#%! assert (A, [0 2 0 4; 5 0 0 0], 1e-6);
-
-### Test endofline
-#%!test <*45046>
-#%! f = tempname ();
-#%! fid = fopen (f, "w");
-#%! fprintf (fid, "a\rb\rc");
-#%! fclose (fid);
-#%! ## Test EOL detection
-#%! d = textread (f, "%s");
-#%! assert (d, {"a";"b";"c"});
-#%! ## Test explicit EOL specification (bug #45046)
-#%! d = textread (f, "%s", "endofline", "\r");
-#%! assert (d, {"a"; "b"; "c"});
-#%! unlink (f);
-
-### Properly process single-quoted EOL args
-#%!test <*46477>
-#%! f = tempname ();
-#%! fid = fopen (f, "w");
-#%! fprintf (fid, "hello, world!");
-#%! fclose (fid);
-#%! [a, b] = textread (f, "%s%s", "endofline", '\n');
-#%! assert (a{1}, "hello,");
-#%! assert (b{1}, "world!");
-
-### Test input validation
-#%!error textread ()
-#%!error textread (1)
-#%!error <arguments must be strings> textread (1, "%f")
-#%!error <arguments must be strings> textread ("fname", 1)
-#%!error <missing or invalid value for> textread (file_in_loadpath ("textread.m"), "", "headerlines")
-#%!error <missing or invalid value for> textread (file_in_loadpath ("textread.m"), "", "headerlines", 'hh')
-#%!error <character value required for> textread (file_in_loadpath ("textread.m"), "%s", "endofline", true)
--- a/scripts/java/javaaddpath.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/java/javaaddpath.m	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,7 @@
     endif
 
     new_path = canonicalize_file_name (tilde_expand (clspath));
-    if (exist (new_path, "dir"))
+    if (isfolder (new_path))
       if (new_path(end) != filesep ())
         new_path = [new_path, filesep()];
       endif
--- a/scripts/java/javarmpath.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/java/javarmpath.m	Thu Dec 20 17:18:56 2018 -0500
@@ -42,7 +42,7 @@
     endif
 
     old_path = canonicalize_file_name (tilde_expand (clspath));
-    if (exist (old_path, "dir"))
+    if (isfolder (old_path))
       if (old_path(end) != filesep ())
         old_path = [old_path, filesep()];
       endif
--- a/scripts/java/org/octave/ClassHelper.java	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/java/org/octave/ClassHelper.java	Thu Dec 20 17:18:56 2018 -0500
@@ -40,7 +40,7 @@
    * Add the given path to the classpath.
    * @param name String - path to addd to the classpath
    * @return boolean - true if the given path exists and was added to the classpath.
-   * @throws Exception
+   * @throws Exception if an error occurs
    */
   public static boolean addClassPath (String name)
     throws Exception
@@ -61,7 +61,7 @@
    *
    * @param name String - path to remove from classpath.
    * @return boolean - true if the given path existed in the classpath before it was removed.
-   * @throws Exception
+   * @throws Exception if an error occurs
    */
   public static boolean removeClassPath (String name)
     throws Exception
@@ -98,7 +98,7 @@
 
   public static String getClassPath ()
   {
-    StringBuffer buf = new StringBuffer ();
+    StringBuilder buf = new StringBuilder();
     String pathSep = System.getProperty ("path.separator");
     java.net.URL[] urls = loader.getURLs ();
 
@@ -142,7 +142,7 @@
   // return list of methods for given class
   public static String getMethods (Class klass)
   {
-    StringBuffer sb = new StringBuffer ();
+    StringBuilder sb = new StringBuilder();
 
     Method theMethod[] = klass.getMethods ();
     for (int i = 0; i < theMethod.length; i++)
@@ -190,7 +190,7 @@
   // return list of fields for given class
   public static String getFields (Class klass)
   {
-    StringBuffer sb = new StringBuffer ();
+    StringBuilder sb = new StringBuilder();
 
     Field theField[] = klass.getFields ();
     for (int i = 0; i < theField.length; i++)
@@ -224,7 +224,7 @@
   }
 
 
-  public static Method findMethod (Class cls, String name, Class[] argTypes)
+  public static Method findMethod (Class<?> cls, String name, Class<?>[] argTypes)
   {
     try
       {
@@ -249,7 +249,7 @@
   }
 
 
-  public static Constructor findConstructor (Class cls, Class[] argTypes)
+  public static Constructor findConstructor (Class<?> cls, Class<?>[] argTypes)
   {
     try
       {
@@ -285,8 +285,8 @@
     catch (IllegalAccessException ex)
       {
         String mName = m.getName ();
-        Class[] pTypes = m.getParameterTypes ();
-        Class currClass = target.getClass ();
+        Class<?>[] pTypes = m.getParameterTypes ();
+        Class<?> currClass = target.getClass ();
 
         while (currClass != null)
           {
@@ -303,7 +303,7 @@
             catch (IllegalAccessException ex2)
               {}
 
-            Class[] ifaceList = currClass.getInterfaces ();
+            Class<?>[] ifaceList = currClass.getInterfaces ();
             for (int i = 0; i < ifaceList.length; i++)
               {
                 try
@@ -492,7 +492,7 @@
   }
 
 
-  private static boolean isCallableFrom (Class expCls, Class argCls)
+  private static boolean isCallableFrom (Class<?> expCls, Class<?> argCls)
   {
     //System.out.println("isCallableFrom: "+expCls.getCanonicalName() + " <=? " + argCls.getCanonicalName());
     if (argCls == null)
@@ -598,7 +598,7 @@
   }
 
 
-  private static Object castArgument (Object obj, Class type, Class expType)
+  private static Object castArgument (Object obj, Class<?> type, Class<?> expType)
   {
     // System.out.println("expType:"+expType.getCanonicalName() + " <= type:" + type.getCanonicalName());
     if (type == null || expType.isAssignableFrom (type))
--- a/scripts/java/org/octave/Octave.java	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/java/org/octave/Octave.java	Thu Dec 20 17:18:56 2018 -0500
@@ -28,8 +28,8 @@
 {
   private static Object notifyObject = null;
   private static Object[] args = null;
-  private static LinkedList invokeList = new LinkedList ();
-  private static LinkedList waitList = new LinkedList ();
+  private static LinkedList<Object> invokeList = new LinkedList<Object> ();
+  private static LinkedList<Object> waitList = new LinkedList<Object> ();
 
   public native static boolean call (String name, Object[] argin, Object[] argout);
   public native static void doInvoke (int ID, Object[] args);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/findstr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,158 @@
+## Copyright (C) 1996-2018 Kurt Hornik
+##
+## 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  {} {} findstr (@var{s}, @var{t})
+## @deftypefnx {} {} findstr (@var{s}, @var{t}, @var{overlap})
+##
+## This function is obsolete.  Use @code{strfind} instead.
+##
+## Return the vector of all positions in the longer of the two strings @var{s}
+## and @var{t} where an occurrence of the shorter of the two starts.
+##
+## If the optional argument @var{overlap} is true (default), the returned
+## vector can include overlapping positions.  For example:
+##
+## @example
+## @group
+## findstr ("ababab", "a")
+##      @result{} [1, 3, 5];
+## findstr ("abababa", "aba", 0)
+##      @result{} [1, 5]
+## @end group
+## @end example
+##
+## @strong{Caution:} @code{findstr} is obsolete.  Use @code{strfind} in all new
+## code.
+## @seealso{strfind, strmatch, strcmp, strncmp, strcmpi, strncmpi, find}
+## @end deftypefn
+
+## Note that this implementation swaps the strings if second one is longer
+## than the first, so try to put the longer one first.
+
+## Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
+## Adapted-By: jwe
+
+function v = findstr (s, t, overlap = true)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "findstr is obsolete; use strfind instead\n");
+  endif
+
+  if (nargin < 2 || nargin > 3)
+    print_usage ();
+  endif
+
+  if (all (size (s) > 1) || all (size (t) > 1))
+    error ("findstr: arguments must have only one non-singleton dimension");
+  endif
+
+  ## Make S be the longer string.
+  if (length (s) < length (t))
+    [s, t] = deal (t, s);
+  endif
+
+  l_s = length (s);
+  l_t = length (t);
+
+  if (l_t == 0)
+    ## zero length target: return empty set
+    v = [];
+
+  elseif (l_t == 1)
+    ## length one target: simple find
+    v = find (s == t);
+
+  elseif (l_t == 2)
+    ## length two target: find first at i and second at i+1
+    v = find (s(1:l_s-1) == t(1) & s(2:l_s) == t(2));
+
+  else
+    ## length three or more: match the first three by find then go through
+    ## the much smaller list to determine which of them are real matches
+    limit = l_s - l_t + 1;
+    v = find (  s(1:limit)   == t(1)
+              & s(2:limit+1) == t(2)
+              & s(3:limit+2) == t(3));
+  endif
+
+  ## Need to search the index vector if our find was too short
+  ## (target length > 3), or if we don't allow overlaps.  Note though
+  ## that there cannot be any overlaps if the first character in the
+  ## target is different from the remaining characters in the target,
+  ## so a single character, two different characters, or first character
+  ## different from the second two don't need to be searched.
+  if (l_t >= 3 || (! overlap && l_t > 1 && any (t(1) == t(2:l_t))))
+    ## force strings to be both row vectors or both column vectors
+    if (all (size (s) != size (t)))
+      t = t.';
+    endif
+
+    ## determine which ones to keep
+    keep = zeros (size (v));
+    ind = 0:l_t-1;
+    if (overlap)
+      for idx = 1:length (v)
+        keep(idx) = all (s(v(idx) + ind) == t);
+      endfor
+    else
+      ## First possible position for next non-overlapping match.
+      next = 1;
+      for idx = 1:length (v)
+        if (v(idx) >= next && s(v(idx) + ind) == t)
+          keep(idx) = 1;
+          ## Skip to the next possible match position.
+          next = v(idx) + l_t;
+        else
+          keep(idx) = 0;
+        endif
+      endfor
+    endif
+    if (! isempty (v))
+      v = v(find (keep));
+    endif
+  endif
+
+  if (isempty (v))
+    v = [];
+  endif
+
+  ## Always return a row vector, because that's what the old one did.
+  if (iscolumn (v))
+    v = v.';
+  endif
+
+endfunction
+
+
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:legacy-function", "local");
+%! findstr ("", "");
+
+%!assert (findstr ("abababa", "a"), [1, 3, 5, 7])
+%!assert (findstr ("abababa", "aba"), [1, 3, 5])
+%!assert (findstr ("aba", "abababa", 0), [1, 5])
+
+## Test input validation
+%!error findstr ()
+%!error findstr ("foo", "bar", 3, 4)
+%!error <must have only one non-singleton dimension> findstr (["AB" ; "CD"], "C")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/flipdim.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,37 @@
+## Copyright (C) 2004-2018 David Bateman
+## Copyright (C) 2009 VZLU Prague
+##
+## 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  {} {} flipdim (@var{x})
+## @deftypefnx {} {} flipdim (@var{x}, @var{dim})
+## This function is obsolete.  Use @code{flip} instead.
+## @seealso{flip, fliplr, flipud, rot90, rotdim}
+## @end deftypefn
+
+function y = flipdim (varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "flipdim is obsolete; please use flip instead");
+  endif
+
+  y = flip (varargin{:});
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/genvarname.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,221 @@
+## Copyright (C) 2008-2018 Bill Denney, Robert Platt
+##
+## 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{varname} =} genvarname (@var{str})
+## @deftypefnx {} {@var{varname} =} genvarname (@var{str}, @var{exclusions})
+##
+## This function is obsolete.  Use @code{matlab.lang.makeValidName} or
+## @code{matlab.lang.makeUniqueStrings} instead.
+##
+## Create valid unique variable name(s) from @var{str}.
+##
+## If @var{str} is a cellstr, then a unique variable is created for each cell
+## in @var{str}.
+##
+## @example
+## @group
+## genvarname (@{"foo", "foo"@})
+##   @result{}
+##      @{
+##        [1,1] = foo
+##        [1,2] = foo1
+##      @}
+## @end group
+## @end example
+##
+## If @var{exclusions} is given, then the variable(s) will be unique to each
+## other and to @var{exclusions} (@var{exclusions} may be either a string or a
+## cellstr).
+##
+## @example
+## @group
+## x = 3.141;
+## genvarname ("x", who ())
+##   @result{} x1
+## @end group
+## @end example
+##
+## Note that the result is a char array or cell array of strings, not the
+## variables themselves.  To define a variable, @code{eval()} can be used.
+## The following trivial example sets @code{x} to 42.
+##
+## @example
+## @group
+## name = genvarname ("x");
+## eval ([name " = 42"]);
+##   @result{} x =  42
+## @end group
+## @end example
+##
+## This can be useful for creating unique struct field names.
+##
+## @example
+## @group
+## x = struct ();
+## for i = 1:3
+##   x.(genvarname ("a", fieldnames (x))) = i;
+## endfor
+##   @result{} x =
+##      @{
+##        a =  1
+##        a1 =  2
+##        a2 =  3
+##      @}
+## @end group
+## @end example
+##
+## Since variable names may only contain letters, digits, and underscores,
+## @code{genvarname} will replace any sequence of disallowed characters with
+## an underscore.  Also, variables may not begin with a digit; in this case
+## an @samp{x} is added before the variable name.
+##
+## Variable names beginning and ending with two underscores @qcode{"__"} are
+## valid, but they are used internally by Octave and should generally be
+## avoided; therefore, @code{genvarname} will not generate such names.
+##
+## @code{genvarname} will also ensure that returned names do not clash with
+## keywords such as @qcode{"for"} and @qcode{"if"}.  A number will be
+## appended if necessary.  Note, however, that this does @strong{not} include
+## function names such as @qcode{"sin"}.  Such names should be included in
+## @var{exclusions} if necessary.
+## @seealso{matlab.lang.makeValidName, matlab.lang.makeUniqueStrings,
+## namelengthmax, isvarname, iskeyword, exist, who, tempname, eval}
+## @end deftypefn
+
+function varname = genvarname (str, exclusions = {})
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
+
+  strinput = ischar (str);
+  ## Process the inputs
+  if (strinput)
+    if (rows (str) != 1)
+      error ("genvarname: if more than one STR is given, it must be a cellstr");
+    endif
+    str = {str};
+  elseif (! iscellstr (str))
+    error ("genvarname: STR must be a string or cellstr");
+  endif
+
+  if (ischar (exclusions))
+    if (rows (exclusions) != 1)
+      error ("genvarname: if more than one exclusion is given, it must be a cellstr");
+    endif
+    exclusions = {exclusions};
+  elseif (! iscellstr (exclusions))
+    error ("genvarname: EXCLUSIONS must be a string or cellstr");
+  else
+    exclusions = exclusions(:);
+  endif
+
+  varname = cell (size (str));
+  for i = 1:numel (str)
+    ## Perform any modifications to the varname to make sure that it is
+    ## a valid variable name.
+
+    ## remove invalid characters
+    str{i}(! (isalnum (str{i}) | str{i} == "_")) = "_";
+    ## do not use keywords
+    if (iskeyword (str{i}))
+      firstcharacter = toupper (str{i}(1));
+      str{i} = ["x", firstcharacter, str{i}(2:end)];
+    endif
+    ## The variable cannot be empty
+    if (isempty (str{i}))
+      str{i} = "x";
+    endif
+    ## Leading underscores are not Matlab compatible
+    if (str{i}(1) == "_")
+      str{i} = ["x", str{i}];
+    endif
+    ## it cannot start with a number
+    if (isdigit (str{i}(1)))
+      str{i} = ["x", str{i}];
+    endif
+
+    ## make sure that the variable is unique relative to other variables
+    ## and the exclusions list
+    excluded = any (strcmp (str{i}, exclusions));
+    if (excluded && isdigit (str{i}(end)))
+      ## if it is not unique and ends with a digit, add an underscore to
+      ## make the variable name more readable ("x1_1" instead of "x11")
+      str{i} = [str{i}, "_"];
+    endif
+    varname(i) = str(i);
+    idx = 0;
+    while (excluded)
+      idx += 1;
+      varname{i} = sprintf ("%s%d", str{i}, idx);
+      excluded = any (strcmp (varname{i}, exclusions));
+    endwhile
+    exclusions(end+1) = varname(i);
+  endfor
+
+  if (strinput)
+    varname = varname{1};
+  endif
+
+endfunction
+
+
+## a single argument
+%!assert (genvarname ("a"), "a")
+## a single argument with a non-conflicting exception
+%!assert (genvarname ("a", "b"), "a")
+## a single argument with a conflicting exception
+%!assert (genvarname ("a", "a"), "a1")
+## a single argument as a cell
+%!assert (genvarname ({"a"}), {"a"})
+%!assert (genvarname ({"a"}, "b"), {"a"})
+%!assert (genvarname ({"a"}, {"b"}), {"a"})
+%!assert (genvarname ({"a"}, "a"), {"a1"})
+%!assert (genvarname ({"a"}, {"a"}), {"a1"})
+## Test different arguments
+## orientation
+%!assert (genvarname ({"a" "b"}), {"a" "b"})
+%!assert (genvarname ({"a";"b"}), {"a";"b"})
+%!assert (genvarname ({"a" "a"}), {"a" "a1"})
+%!assert (genvarname ({"a" "b";"c" "d"}), {"a" "b";"c" "d"})
+%!assert (genvarname ({"a" "a" "a";"a" "a" "a"}), {"a" "a2" "a4";"a1" "a3" "a5"})
+## more than one repetition
+%!assert (genvarname ({"a" "a" "a"}), {"a" "a1" "a2"})
+%!assert (genvarname ({"a" "a" "a"}, {"a" "a1" "a2"}), {"a3" "a4" "a5"})
+## more than one repetition not in order
+%!assert (genvarname ({"a" "b" "a" "b" "a"}), {"a" "b" "a1" "b1" "a2"})
+## Variable name munging
+%!assert (genvarname ("__x__"), "x__x__")
+%!assert (genvarname ("123456789"), "x123456789")
+%!assert (genvarname ("_$1__"), "x__1__")
+%!assert (genvarname ("__foo__", "x__foo__"), "x__foo__1")
+%!assert (genvarname ("1million_and1", "x1million_and1"), "x1million_and1_1")
+%!assert (genvarname ({"", "", ""}), {"x", "x1", "x2"})
+%!assert (genvarname ("if"), "xIf")
+%!assert (genvarname ({"if", "if", "if"}), {"xIf", "xIf1", "xIf2"})
+## Exclusions in odd format
+%!assert (genvarname ("x", {"a", "b"; "x", "d"}), "x1")
+
+## Test input validation
+%!error genvarname ()
+%!error genvarname (1,2,3)
+%!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"))
+%!error <EXCLUSIONS must be a string or cellstr> genvarname ("x", 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/isdir.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,66 @@
+## Copyright (C) 2004-2018 Alois Schloegl
+##
+## 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 {} {} isdir (@var{f})
+##
+## This function is not recommended.  Use @code{isfolder} or
+## @code{file_in_loadpath} instead.
+##
+## Return true if @var{f} is a directory and false otherwise.
+##
+## Compatibility Note: The @sc{matlab} function of the same name will also
+## search for @var{f} in the load path directories.  To emulate this behavior
+## use
+##
+## @example
+## @var{tf} = ! isempty (file_in_loadpath (@var{f}))
+## @end example
+##
+## @seealso{isfolder, file_in_loadpath, exist, stat, is_absolute_filename, is_rooted_relative_filename}
+## @end deftypefn
+
+function retval = isdir (f)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "isdir is obsolete; use isfolder or dir_in_loadpath instead\n");
+  endif
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  ## Exist returns an integer but isdir should return a logical.
+  retval = (exist (f, "dir") == 7);
+
+endfunction
+
+
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:legacy-function", "local");
+%! isdir (pwd ());
+
+%!assert (isdir (pwd ()))
+%!assert (! isdir (tempname ()))
+
+%!error isdir ()
+%!error isdir (1, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/isequalwithequalnans.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,40 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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 {} isequalwithequalnans (@var{x1}, @var{x2}, @dots{})
+## This function is obsolete.  Use @code{isequaln} instead.
+## @seealso{isequaln}
+## @end deftypefn
+
+## At one time, Matlab docs stated that this function is obsolete and would be
+## removed in some future version.  Now users are told that it should be
+## avoided, but there is no mention of possible future removal.
+
+function retval = isequalwithequalnans (varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "isequalwithequalnans is obsolete; please use isequaln instead");
+  endif
+
+  retval = isequaln (varargin{:});
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/isstr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,42 @@
+## Copyright (C) 2003-2018 John W. Eaton
+##
+## 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 {} {} isstr (@var{x})
+## This function is obsolete.  Use @code{ischar} instead.
+## @seealso{ischar}
+## @end deftypefn
+
+## Author: jwe
+
+## At one time, Matlab docs stated that this function is obsolete and would be
+## removed in some future version.  Now users are told that it should be
+## avoided, but there is no mention of possible future removal.
+
+function retval = isstr (varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "isstr is obsolete; please use ischar instead");
+  endif
+
+  retval = ischar (varargin{:});
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,23 @@
+FCN_FILE_DIRS += scripts/legacy
+
+%canon_reldir%_FCN_FILES = \
+  %reldir%/findstr.m \
+  %reldir%/flipdim.m \
+  %reldir%/genvarname.m \
+  %reldir%/isdir.m \
+  %reldir%/isequalwithequalnans.m \
+  %reldir%/isstr.m \
+  %reldir%/setstr.m \
+  %reldir%/strmatch.m \
+  %reldir%/strread.m \
+  %reldir%/textread.m
+
+%canon_reldir%dir = $(fcnfiledir)/legacy
+
+%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/legacy/setstr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,42 @@
+## Copyright (C) 2003-2018 John W. Eaton
+##
+## 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{s} =} setstr (@var{x})
+## This function is obsolete.  Use @code{char} instead.
+## @seealso{char}
+## @end deftypefn
+
+## Author: jwe
+
+## At one time, Matlab docs stated that this function is obsolete and would be
+## removed in some future version.  Now users are told that it should be
+## avoided, but there is no mention of possible future removal.
+
+function retval = setstr (varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "setstr is obsolete; please use char instead");
+  endif
+
+  retval = char (varargin{:});
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/strmatch.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,156 @@
+## Copyright (C) 2000-2018 Paul Kienzle
+## Copyright (C) 2003 Alois Schloegl
+## Copyright (C) 2010 VZLU Prague
+##
+## 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  {} {} strmatch (@var{s}, @var{A})
+## @deftypefnx {} {} strmatch (@var{s}, @var{A}, "exact")
+##
+## This function is obsolete.  Use an alternative such as @code{strncmp}
+## or @code{strcmp} instead.
+##
+## Return indices of entries of @var{A} which begin with the string @var{s}.
+##
+## The second argument @var{A} must be a string, character matrix, or a cell
+## array of strings.
+##
+## If the third argument @qcode{"exact"} is not given, then @var{s} only
+## needs to match @var{A} up to the length of @var{s}.  Trailing spaces and
+## nulls in @var{s} and @var{A} are ignored when matching.
+##
+## For example:
+##
+## @example
+## @group
+## strmatch ("apple", "apple juice")
+##      @result{} 1
+##
+## strmatch ("apple", ["apple  "; "apple juice"; "an apple"])
+##      @result{} [1; 2]
+##
+## strmatch ("apple", ["apple  "; "apple juice"; "an apple"], "exact")
+##      @result{} [1]
+## @end group
+## @end example
+##
+## @strong{Caution:} @code{strmatch} is obsolete.  Use @code{strncmp} (normal
+## case) or @code{strcmp} (@qcode{"exact"} case) in all new code.  Other
+## replacement possibilities, depending on application, include @code{regexp}
+## or @code{validatestring}.
+## @seealso{strncmp, strcmp, regexp, strfind, validatestring}
+## @end deftypefn
+
+## Author: Paul Kienzle, Alois Schloegl
+## Adapted-by: jwe
+
+function idx = strmatch (s, A, exact)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "strmatch is obsolete; use strncmp or strcmp instead\n");
+  endif
+
+  if (nargin < 2 || nargin > 3)
+    print_usage ();
+  endif
+
+  if (iscellstr (s))
+    if (numel (s) > 1)
+      error ("strmatch: a cell array S must contain only one string");
+    endif
+    s = char (s);
+  elseif (! ischar (s) || (! isempty (s) && ! isrow (s)))
+    error ("strmatch: S must be a string");
+  elseif (! (ischar (A) || iscellstr (A)))
+    error ("strmatch: A must be a string or cell array of strings");
+  endif
+
+  ## Trim blanks and nulls from search string
+  if (any (s != " " & s != "\0"))
+    s = regexprep (s, "[ \\0]+$", '');
+  endif
+  len = length (s);
+
+  exact = nargin == 3 && ischar (exact) && strcmp (exact, "exact");
+
+  if (ischar (A))
+    [nr, nc] = size (A);
+    if (len > nc)
+      idx = [];
+    else
+      match = all (bsxfun (@eq, A(:,1:len), s), 2);
+      if (exact)
+        AA = A(:,len+1:nc);
+        match &= all (AA == " " | AA == "\0", 2);
+      endif
+      idx = find (match);
+    endif
+  else
+    if (len > 0)
+      idx = find (strncmp (s, A, len));
+    else
+      idx = find (strcmp (s, A));
+    endif
+    if (exact)
+      ## We can't just use strcmp, because we need to ignore spaces at end.
+      B = regexprep (A(idx), "[ \\0]+$", '');
+      idx = idx(strcmp (s, B));
+    endif
+  endif
+
+endfunction
+
+
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:legacy-function", "local");
+%! strmatch ("", "");
+
+%!assert (strmatch ("a", {"aaa", "bab", "bbb"}), 1)
+%!assert (strmatch ("apple", "apple juice"), 1)
+%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), [1; 2])
+%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), [1; 2])
+%!assert (strmatch ("apple pie", "apple"), [])
+%!assert (strmatch ("a ", "a"), 1)
+%!assert (strmatch ("a", "a \0", "exact"), 1)
+%!assert (strmatch ("a b", {"a b", "a c", "c d"}), 1)
+%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4])
+%!assert (strmatch ('', { '', '% comment', 'var a = 5', ''}, "exact"), [1,4])
+
+## Weird Matlab corner cases
+%!test <*49601>
+%! assert (strmatch (" ", " "), 1);
+%! assert (strmatch (" ", "   "), 1);
+%! assert (strmatch ("  ", " "), []);
+%! assert (strmatch ("  ", "  "), 1);
+%!test <*54432>
+%! assert (strmatch ({"a"}, {"aaa", "bab", "bbb"}), 1);
+%! assert (isempty (strmatch ({}, {"aaa", "bab"})));
+
+## 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 <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")
+%!error <A must be a string> strmatch ("a", 1)
+%!error <A must be a string> strmatch ("a", {"hello", [1]})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/strread.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,1137 @@
+## Copyright (C) 2009-2018 Eric Chassande-Mottin, CNRS (France)
+## Parts Copyright (C) 2012-2018 Philip Nienhuis
+##
+## 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{a}, @dots{}] =} strread (@var{str})
+## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format})
+## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat})
+## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{prop1}, @var{value1}, @dots{})
+## @deftypefnx {} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat}, @var{prop1}, @var{value1}, @dots{})
+##
+## This function is obsolete.  Use @code{textscan} instead.
+##
+## Read data from a string.
+##
+## The string @var{str} is split into words that are repeatedly matched to the
+## specifiers in @var{format}.  The first word is matched to the first
+## specifier, the second to the second specifier and so forth.  If there are
+## more words than specifiers, the process is repeated until all words have
+## been processed.
+##
+## The string @var{format} describes how the words in @var{str} should be
+## parsed.  It may contain any combination of the following specifiers:
+##
+## @table @code
+## @item %s
+## The word is parsed as a string.
+##
+## @item  %f
+## @itemx %n
+## The word is parsed as a number and converted to double.
+##
+## @item  %d
+## @itemx %u
+## The word is parsed as a number and converted to int32.
+##
+## @item  %*
+## @itemx %*f
+## @itemx %*s
+## The word is skipped.
+##
+## For %s and %d, %f, %n, %u and the associated %*s @dots{} specifiers an
+## optional width can be specified as %Ns, etc.@: where N is an integer > 1.
+## For %f, format specifiers like %N.Mf are allowed.
+##
+## @item literals
+## In addition the format may contain literal character strings; these will be
+## skipped during reading.
+## @end table
+##
+## Parsed word corresponding to the first specifier are returned in the first
+## output argument and likewise for the rest of the specifiers.
+##
+## By default, @var{format} is @t{"%f"}, meaning that numbers are read from
+## @var{str}.  This will do if @var{str} contains only numeric fields.
+##
+## For example, the string
+##
+## @example
+## @group
+## @var{str} = "\
+## Bunny Bugs   5.5\n\
+## Duck Daffy  -7.5e-5\n\
+## Penguin Tux   6"
+## @end group
+## @end example
+##
+## @noindent
+## can be read using
+##
+## @example
+## [@var{a}, @var{b}, @var{c}] = strread (@var{str}, "%s %s %f");
+## @end example
+##
+## Optional numeric argument @var{format_repeat} can be used for limiting the
+## number of items read:
+##
+## @table @asis
+## @item -1
+## (default) read all of the string until the end.
+##
+## @item N
+## Read N times @var{nargout} items.  0 (zero) is an acceptable value for
+## @var{format_repeat}.
+## @end table
+##
+## The behavior of @code{strread} can be changed via property-value pairs.  The
+## following properties are recognized:
+##
+## @table @asis
+## @item @qcode{"commentstyle"}
+## Parts of @var{str} are considered comments and will be skipped.
+## @var{value} is the comment style and can be any of the following.
+##
+## @itemize
+## @item @qcode{"shell"}
+## Everything from @code{#} characters to the nearest end-of-line is skipped.
+##
+## @item @qcode{"c"}
+## Everything between @code{/*} and @code{*/} is skipped.
+##
+## @item @qcode{"c++"}
+## Everything from @code{//} characters to the nearest end-of-line is skipped.
+##
+## @item @qcode{"matlab"}
+## Everything from @code{%} characters to the nearest end-of-line is skipped.
+##
+## @item user-supplied.  Two options:
+## (1) One string, or 1x1 cell string: Skip everything to the right of it;
+## (2) 2x1 cell string array: Everything between the left and right strings
+## is skipped.
+## @end itemize
+##
+## @item @qcode{"delimiter"}
+## Any character in @var{value} will be used to split @var{str} into words
+## (default value = any whitespace).  Note that whitespace is implicitly added
+## to the set of delimiter characters unless a @qcode{"%s"} format conversion
+## specifier is supplied; see @qcode{"whitespace"} parameter below.  The set
+## of delimiter characters cannot be empty; if needed Octave substitutes a
+## space as delimiter.
+##
+## @item @qcode{"emptyvalue"}
+## Value to return for empty numeric values in non-whitespace delimited data.
+## The default is NaN@.  When the data type does not support NaN (int32 for
+## example), then default is zero.
+##
+## @item @qcode{"multipledelimsasone"}
+## Treat a series of consecutive delimiters, without whitespace in between,
+## as a single delimiter.  Consecutive delimiter series need not be vertically
+## @qcode{"aligned"}.
+##
+## @item @qcode{"treatasempty"}
+## Treat single occurrences (surrounded by delimiters or whitespace) of the
+## string(s) in @var{value} as missing values.
+##
+## @item @qcode{"returnonerror"}
+## If @var{value} true (1, default), ignore read errors and return normally.
+## If false (0), return an error.
+##
+## @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
+## 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"}
+## (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
+## @qcode{"delimiter"} is retained as delimiter and removed from the set of
+## whitespace characters.  If whitespace characters are to be kept as-is (in
+## e.g., strings), specify an empty value (i.e., @qcode{""}) for
+## @qcode{"whitespace"}; obviously, whitespace cannot be a delimiter then.
+##
+## @end table
+##
+## When the number of words in @var{str} doesn't match an exact multiple of
+## the number of format conversion specifiers, strread's behavior depends on
+## the last character of @var{str}:
+##
+## @table @asis
+## @item last character = @qcode{"@xbackslashchar{}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"}
+## Data columns are not padded; strread returns columns of unequal length
+##
+## @end table
+##
+## @seealso{textscan, sscanf}
+## @end deftypefn
+
+function varargout = strread (str, format = "%f", varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "strread is obsolete; use textscan instead\n");
+  endif
+
+  ## Check input
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (isempty (str))
+    ## Return empty args (no match), rather than raising an error
+    varargout = cell (1, nargout);
+    return;
+  endif
+
+  if (isempty (format))
+    format = "%f";
+  endif
+
+  if (! ischar (str) || ! ischar (format))
+    error ("strread: STR and FORMAT arguments must be strings");
+  endif
+
+  if (strcmp (typeinfo (format), "sq_string"))
+    format = do_string_escapes (format);
+  endif
+
+  ## Parse format string to compare number of conversion fields and nargout
+  nfields = numel (regexp (format, '(%(\d*|\d*\.\d*)?[nfduscq]|%\[)', "match"));
+  ## If str only has numeric fields, a (default) format ("%f") will do.
+  ## Otherwise:
+  if (! nfields)
+    error ("strread.m: no valid format conversion specifiers found\n");
+  elseif ((max (nargout, 1) != nfields) && ! strcmp (format, "%f"))
+    error ("strread: the number of output variables must match that specified by FORMAT");
+  endif
+
+  ## Check for format string repeat count
+  format_repeat_count = -1;
+  if (nargin > 2 && isnumeric (varargin{1}))
+    if (varargin{1} >= 0)
+      format_repeat_count = varargin{1};
+    endif
+    if (nargin > 3)
+      varargin = varargin(2:end);
+    else
+      varargin = {};
+    endif
+  endif
+
+  ## Parse options.  First initialize defaults
+  comment_flag = false;
+  open_comment = false;
+  cmt_eol = "\n";
+  delimiter_str = "";
+  empty_str = "";
+  eol_char = "";
+  err_action = 0;
+  mult_dlms_s1 = false;
+  numeric_fill_value = NaN;
+  white_spaces = " \b\r\n\t";
+  for n = 1:2:length (varargin)
+    switch (lower (varargin{n}))
+      case "bufsize"
+        ## We could synthesize this, but that just seems weird...
+        warning ("strread: property 'bufsize' is not implemented");
+      case "commentstyle"
+        comment_flag = true;
+        switch (lower (varargin{n+1}))
+          case "c"
+            [comment_start, comment_end] = deal ("/*", "*/");
+          case "c++"
+            [comment_start, comment_end] = deal ("//", "cmt_eol");
+            open_comment = true;
+          case "shell"
+            [comment_start, comment_end] = deal ("#" , "cmt_eol");
+            open_comment = true;
+          case "matlab"
+            [comment_start, comment_end] = deal ("%" , "cmt_eol");
+            open_comment = true;
+          otherwise
+            if (ischar (varargin{n+1})
+                || (numel (varargin{n+1}) == 1 && iscellstr (varargin{n+1})))
+              [comment_start, comment_end] = deal (char (varargin{n+1}), "cmt_eol");
+            open_comment = true;
+            elseif (iscellstr (varargin{n+1}) && numel (varargin{n+1}) == 2)
+              [comment_start, comment_end] = deal (varargin{n+1}{:});
+            else
+              ## FIXME: A user may have numeric values specified: {'//', 7}
+              ##        this will lead to an error in the warning message
+              error ("strread: unknown or unrecognized comment style '%s'",
+                      varargin{n+1});
+            endif
+        endswitch
+      case "delimiter"
+        delimiter_str = varargin{n+1};
+        if (strcmp (typeinfo (delimiter_str), "sq_string"))
+          delimiter_str = do_string_escapes (delimiter_str);
+        endif
+      case "emptyvalue"
+        numeric_fill_value = varargin{n+1};
+      case "expchars"
+        warning ("strread: property 'expchars' is not implemented");
+      case "whitespace"
+        white_spaces = varargin{n+1};
+        if (strcmp (typeinfo (white_spaces), "sq_string"))
+          white_spaces = do_string_escapes (white_spaces);
+        endif
+      ## The following parameters are specific to textscan and textread
+      case "endofline"
+        eol_char = varargin{n+1};
+        if (strcmp (typeinfo (eol_char), "sq_string"))
+          eol_char = do_string_escapes (eol_char);
+        endif
+        cmt_eol = eol_char;
+        open_comment = false;
+      case "returnonerror"
+        err_action = varargin{n+1};
+      case "multipledelimsasone"
+        mult_dlms_s1 = varargin{n+1};
+      case "treatasempty"
+        if (iscellstr (varargin{n+1}))
+          empty_str = varargin{n+1};
+        elseif (ischar (varargin{n+1}))
+          empty_str = varargin(n+1);
+        else
+          error ("strread: 'treatasempty' value must be string or cellstr");
+        endif
+      otherwise
+        warning ("strread: unknown property '%s'", varargin{n});
+    endswitch
+  endfor
+
+  ## First parse of FORMAT
+  if (strcmpi (strtrim (format), "%f"))
+    ## Default format specified.  Expand it (to desired nargout)
+    fmt_words = cell (max (nargout, 1), 1);
+    fmt_words (1:max (nargout, 1)) = format;
+  else
+    ## Determine the number of words per line as a first guess.  Forms
+    ## like %f<literal>) (w/o delimiter in between) are fixed further on
+    format = strrep (format, "%", " %");
+    fmt_words = regexp (format, '[^ ]+', "match");
+
+    ## Find position of conversion specifiers (they start with %)
+    fcs_ptrn = '(%\*?(\d*|\d*\.\d*)?[nfduscq]|%\*?\[)';
+    idy2 = find (! cellfun ("isempty", regexp (fmt_words, fcs_ptrn)));
+
+    ## 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.");
+    endif
+
+    ## Format conversion specifiers following literals w/o space/delim
+    ## in between are separate now.  Separate those w trailing literals
+    a = strfind (fmt_words(idy2), "%");
+    b = regexp (fmt_words(idy2), '[nfdus]', "end");
+    for jj = 1:numel (a)
+      ## From right to left to avoid losing track
+      ii = numel (a) - jj + 1;
+      ## Check for illegal format specifiers
+      if (isempty (b{ii}))
+        error ("strread: unknown format specifier #%d ('%s')\n",
+              ii, fmt_words{idy2(ii)});
+      endif
+      if (! (length (fmt_words{idy2(ii)}) == b{ii}(1)))
+        ## Split fmt_words(ii) into % conv specifier and trailing literal
+        fmt_words(idy2(ii)+1 : end+1) = fmt_words(idy2(ii) : end);
+        fmt_words{idy2(ii)} = fmt_words{idy2(ii)}(a{ii} : b{ii}(1));
+        fmt_words{idy2(ii)+1} = fmt_words{idy2(ii)+1}(b{ii}+1:end);
+      endif
+    endfor
+  endif
+  num_words_per_line = numel (fmt_words);
+
+  ## Special handling for CRLF EOL character in str
+  if (! isempty (eol_char) && strcmp (eol_char, "\r\n"))
+    ## Strip CR from CRLF sequences
+    str = strrep (str, "\r\n", "\n");
+    ## CR serves no further purpose in function
+    eol_char = "\n";
+  endif
+
+  ## Remove comments in str
+  if (comment_flag)
+    ## Expand 'cmt_eol' here, after option processing which may have set value
+    comment_end = strrep (comment_end, "cmt_eol", cmt_eol);
+    cstart = strfind (str, comment_start);
+    cstop  = strfind (str, comment_end);
+    if (open_comment)
+      cstop -= 1;
+    endif
+    ## Treat end of string as additional comment stop
+    if (isempty (cstop) || cstop(end) != length (str))
+      cstop(end+1) = length (str);
+    endif
+    if (! isempty (cstart))
+      ## Ignore nested openers.
+      [idx, cidx] = unique (lookup (cstop, cstart), "first");
+      if (idx(end) == length (cstop))
+        cidx(end) = []; # Drop the last one if orphaned.
+      endif
+      cstart = cstart(cidx);
+    endif
+    if (! isempty (cstop))
+      ## Ignore nested closers.
+      [idx, cidx] = unique (lookup (cstart, cstop), "first");
+      if (idx(1) == 0)
+        cidx(1) = []; # Drop the first one if orphaned.
+      endif
+      cstop = cstop(cidx);
+    endif
+    len = length (str);
+    c2len = length (comment_end);
+    if (cstop + c2len == len)
+      ## Ignore last char of to-the-end-of-line comments
+      c2len += 1;
+    endif
+    str = cellslices (str, [1, cstop + c2len], [cstart - 1, len]);
+    str = [str{:}];
+  endif
+
+  if (! isempty (white_spaces))
+    ## For numeric fields, whitespace is always a delimiter, but not for text
+    ## fields
+    if (isempty (regexp (format, '%\*?\d*s')))
+      ## Add whitespace to delimiter set
+      delimiter_str = unique ([white_spaces delimiter_str]);
+    else
+      ## Remove any delimiter chars from white_spaces list
+      white_spaces = setdiff (white_spaces, delimiter_str);
+    endif
+  endif
+  if (isempty (delimiter_str))
+    delimiter_str = " ";
+  endif
+  if (! isempty (eol_char))
+    ## Add eol_char to delimiter collection
+    delimiter_str = unique ([delimiter_str eol_char]);
+    ## and remove it from whitespace collection
+    white_spaces = strrep (white_spaces, eol_char, '');
+  endif
+
+  ii = numel (fmt_words);
+  while (ii > 0)
+    if (ismember (fmt_words{ii}, delimiter_str)(1))
+      fmt_words(ii) = [];
+      --num_words_per_line;
+    endif
+    --ii;
+  endwhile
+
+  pad_out = 0;
+  ## Trim whitespace if needed
+  if (! isempty (white_spaces))
+    ## Check if trailing "\n" might signal padding output arrays to equal size
+    ## before it is trimmed away below
+    if (str(end) == "\n" && nargout > 1)
+      pad_out = 1;
+    endif
+    ## Condense all repeated whitespace into one single space
+    ## FIXME: this will also fold repeated whitespace in a char field
+    rxp_wsp = sprintf ("[%s]+", white_spaces);
+    str = regexprep (str, rxp_wsp, ' ');
+    ## Remove possible leading space at string
+    if (str(1) == " ")
+       str = str(2:end);
+    endif
+    ## Check for single delimiter followed/preceded by whitespace
+    if (! isempty (delimiter_str))
+      dlmstr = setdiff (delimiter_str, " ");
+      if (! isempty (dlmstr))
+        rxp_dlmwsp = sprintf ('( [%s] | [%s]|[%s] )', dlmstr, dlmstr, dlmstr);
+        str = regexprep (str, rxp_dlmwsp, delimiter_str(1));
+      endif
+    endif
+    ## Wipe leading and trailing whitespace on each line (it may be
+    ## delimiter too)
+    ## FIXME: Double strrep on str is enormously expensive in CPU time.
+    ## Can this be eliminated?
+    if (! isempty (eol_char))
+      str = strrep (str, [eol_char " "], eol_char);
+      str = strrep (str, [" " eol_char], eol_char);
+    endif
+  endif
+
+  ## Split 'str' into words
+  words = split_by (str, delimiter_str, mult_dlms_s1, eol_char);
+  if (! isempty (white_spaces))
+    ## Trim leading and trailing 'white_spaces'.
+    ## All whitespace has been converted to space above
+    words = strtrim (words);
+  endif
+  num_words = numel (words);
+  ## First guess at nr. of lines in file (ignoring leading/trailing literals)
+  num_lines = ceil (num_words / num_words_per_line);
+
+  ## Replace TreatAsEmpty char sequences by empty strings
+  if (! isempty (empty_str))
+    for ii = 1:numel (empty_str)
+      idz = strncmp (empty_str{ii}, words, length (empty_str{ii}));
+      words(idz) = {""};
+    endfor
+  endif
+
+  ## fmt_words has been split properly now, but words{} has only been split on
+  ## delimiter positions.  As numeric fields can also be separated by
+  ## whitespace, more splits may be needed.
+  ## We also don't know the number of lines (as EndOfLine may have been set to
+  ## "" (empty) by the caller).
+  ##
+  ## We also may have to cope with 3 cases as far as literals go:
+  ## A: Trailing literals (%f<literal>) w/o delimiter in between.
+  ## B: Leading literals (<literal>%f) w/o delimiter in between.
+  ## C. Skipping leftover parts of specified skip fields (%*N )
+  ## Some words columns may have to be split further to fix these.
+  ## To find out, we'll match fmt_words to the words array to see what
+  ## needs to be done.  fwptr tracks which {fmt_words} starts in what {words}
+
+  ## Find indices and pointers to possible literals in fmt_words
+  idf = cellfun ("isempty", strfind (fmt_words, "%"));
+  ## Find indices and pointers to conversion specifiers with fixed width
+  idg = ! cellfun ("isempty", regexp (fmt_words, '%\*?\d'));
+  idy = find (idf | idg);
+  ## Find indices to numeric conversion specifiers
+  idn = ! cellfun ("isempty", regexp (fmt_words, '%[dnfu]'));
+
+  ## If needed, split up columns in three steps:
+  if (! isempty (idy))
+    ## Try-catch because complexity of strings to read can be infinite
+    try
+
+      ## 1. Assess "period" in the split-up words array ( < num_words_per_line).
+      ## Could be done using EndOfLine but that prohibits EndOfLine = "" option.
+      ## Alternative below goes by simply parsing a first grab of words and
+      ## matching fmt_words to words until the fmt_words array is exhausted.
+      ## iwrd: ptr to current analyzed word.
+      ## iwrdp: ptr to pos before analyzed char.
+      iwrd = 1; iwrdp = 0; iwrdl = length (words{1});
+      fwptr = zeros (1, numel (fmt_words));
+      ii = 1;
+      while (ii <= numel (fmt_words))
+
+        nxt_wrd = 0;
+        ## Keep track of which words nr. every fmt_words{} is (starts) in.
+        fwptr(ii) = iwrd;
+
+        if (idf(ii))
+          ## Literal expected
+          if (isempty (strfind (fmt_words{ii}, words(iwrd))))
+            ## Not found in current word; supposed to be in next word
+            nxt_wrd = 1;
+          else
+            ## Found it in current word.  Subtract literal length
+            iwrdp += length (fmt_words{ii});
+            if (iwrdp > iwrdl)
+              ## Parse error.  Literal extends beyond delimiter (word boundary)
+              warning ("strread: literal '%s' (fmt spec # %d) does not match data", ...
+                fmt_words{ii}, ii);
+              ## Word assumed to be completely "used up".  Next word
+              nxt_wrd = 1;
+            elseif (iwrdp == iwrdl)
+              ## Word completely "used up".  Next word
+              nxt_wrd = 1;
+            endif
+          endif
+
+        elseif (idg(ii))
+          ## Fixed width specifier (%N or %*N): read just a part of word
+          sw = regexp (fmt_words{ii}, '\d', "once");
+          ew = regexp (fmt_words{ii}, '[nfuds]') - 1;
+          iwrdp += floor (str2double (fmt_words{ii}(sw:ew)));
+          if (iwrdp > iwrdl)
+            ## Match error.  Field extends beyond word boundary.
+            warning  ...
+            ("strread: field width '%s' (fmt spec # %d) extends beyond actual word limit", ...
+               fmt_words{ii}, ii);
+            ## Assume word to be completely "used up".  Next word
+            nxt_wrd = 1;
+          elseif (iwrdp == iwrdl)
+            ## Word completely "used up".  Next word
+            nxt_wrd = 1;
+          endif
+
+        else
+          ## A simple format conv. specifier.  Either (1) uses rest of word, or
+          ## (2) is squeezed between current iwrdp and next literal, or (3) uses
+          ## next word. (3) is already taken care of.  So just check (1) & (2)
+          if (ii < numel (fmt_words) && idf(ii+1))
+            ## Next fmt_word is a literal...
+            if (! index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1}))
+              ## ...but not found in current word => field uses rest of word
+              nxt_wrd = 1;
+            else
+              ## ..or it IS found.  Add inferred width of current conversion field
+              iwrdp += index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1}) - 1;
+            endif
+          elseif (iwrdp <= iwrdl)
+            ## No bordering literal to the right => field occupies (rest of) word
+            nxt_wrd = 1;
+          endif
+
+        endif
+
+        if (nxt_wrd)
+          ++iwrd; iwrdp = 0;
+          if (iwrd > numel (words))
+            ## Apparently EOF; assume incomplete row already at L.1 of data
+            ii = numel (fmt_words);
+          elseif (ii < numel (fmt_words) && iwrd <= numel (words))
+            iwrdl = length (words{iwrd});
+          endif
+        endif
+
+        ++ii;
+
+      endwhile
+      ## Done
+      words_period = max (iwrd - 1, 1);
+      num_lines = ceil (num_words / words_period);
+
+      ## 2. Pad words array so that it can be reshaped
+      num_words_padded = num_lines * words_period - num_words;
+      if (num_words_padded)
+        words = [words'; cell(num_words_padded, 1)];
+      endif
+      words = reshape (words, words_period, num_lines);
+
+      ## 3. Do the column splitting on rectangular words array
+      icol = 1; ii = 1;    # icol = current column, ii = current fmt_word
+      while (ii <= num_words_per_line)
+
+        ## Check if fmt_words(ii) contains a literal or fixed-width
+        if ((idf(ii) || idg(ii)) && (rows (words) < num_words_per_line))
+          if (idf(ii))
+            s = strfind (words(icol, 1), fmt_words{ii});
+            if (isempty (s{:}))
+              error ("strread: Literal '%s' not found in column %d", fmt_words{ii}, icol);
+            endif
+            s = s{:}(1);
+            e = s(1) + length (fmt_words{ii}) - 1;
+          endif
+          if (! strcmp (fmt_words{ii}, words{icol, 1}))
+            ## Column doesn't exactly match literal => split needed.
+            ## Insert a column
+            words(icol+1:end+1, :) = words(icol:end, :);
+            ## Watch out for empty cells
+            jptr = find (! cellfun ("isempty", words(icol, :)));
+
+            ## Distinguish leading or trailing literals
+            if (! idg(ii) && ! isempty (s) && s(1) == 1)
+              ## Leading literal.
+              ## Assign literal to icol, paste rest in icol + 1
+              ## Apply only to those cells that do have something beyond literal
+              jptr = find (cellfun ("length", words(icol+1, jptr), ...
+                                    "UniformOutput", false) > e(1));
+              words(icol+1, :) = {""};
+              words(icol+1, jptr) = cellfun (
+                @(x) substr (x, e(1)+1, length (x) - e(1)), words(icol, jptr),
+                "UniformOutput", false);
+              words(icol, jptr) = fmt_words{ii};
+              fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
+
+            else
+              if (idg(ii))
+                ## Current field = fixed width.
+                ## Strip into icol, rest in icol+1
+                sw = regexp (fmt_words{ii}, '\d', "once");
+                ew = regexp (fmt_words{ii}, '[nfuds]') - 1;
+                wdth = floor (str2double (fmt_words{ii}(sw:ew)));
+                words(icol+1, jptr) = cellfun (@(x) x(wdth+1:end),
+                     words(icol,jptr), "UniformOutput", false);
+                if (isempty ([words(icol+1, :){:}]))
+                  ## Apparently split wasn't needed as turns out to cover
+                  ## entire column. So delete column again
+                  words(icol+1, :) = [];
+                else
+                  words(icol, jptr) = strtrunc (words(icol, jptr), wdth);
+                  fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
+                endif
+              else
+                if (! isempty (strfind (fmt_words{ii-1}, "%s")))
+                  ## Trailing literal.
+                  ## Could be ambiguous if preceding format == '%s'
+                  warning ("strread.m:\n  Ambiguous '%%s' specifier immediately before literal in column %d", icol);
+                endif
+                ## FIXME: this assumes char(254)/char(255) won't occur in input!
+                clear wrds;
+                wrds(1:2:2*numel (words(icol, jptr))) = ...
+                     strrep (words(icol, jptr), fmt_words{ii}, ...
+                     [char(255) char(254)]);
+                wrds(2:2:2*numel (words(icol, jptr))-1) = char (255);
+                wrds = ostrsplit ([wrds{:}], char (255));
+                words(icol, jptr) = ...
+                  wrds(find (cellfun ("isempty", strfind (wrds, char (254)))));
+                wrds(find (cellfun ("isempty", strfind (wrds, char (254))))) ...
+                   = char (255);
+                words(icol+1, jptr) = ostrsplit (strrep ([wrds{2:end}], ...
+                   char (254), fmt_words{ii}), char (255));
+                ## Former trailing literal may now be leading for next specifier
+                --ii;
+                fwptr = [fwptr(1:ii) (++fwptr(ii+1:end))];
+              endif
+            endif
+          endif
+
+        else
+          ## Conversion specifier.
+          ## Peek if next fmt_word needs split from current column.
+          if (ii < num_words_per_line)
+            if (fwptr(ii) == fwptr(ii+1))
+              --icol;
+            endif
+          endif
+        endif
+        ## Next fmt_word, next column
+        ++ii; ++icol;
+      endwhile
+
+      ## Done.
+      ## Reshape words back into one long vector and strip padded empty words
+      words = reshape (words, 1, numel (words))(1 : end-num_words_padded);
+
+    catch
+      warning ("strread: unable to parse text or file with given format string");
+      return;
+
+    end_try_catch
+  endif
+
+  ## For each specifier, process corresponding column
+  k = 1;
+  for m = 1:num_words_per_line
+    try
+      if (format_repeat_count < 0)
+        data = words(m:num_words_per_line:end);
+      elseif (format_repeat_count == 0)
+        data = {};
+      else
+        lastline = ...
+          min (num_words_per_line * format_repeat_count + m - 1, numel (words));
+        data = words(m:num_words_per_line:lastline);
+        if (num_lines > format_repeat_count)
+          num_lines = format_repeat_count;
+        endif
+      endif
+
+      ## Map to format
+      ## FIXME: Add support for formats like "<%s>", "%[a-zA-Z]"
+      ##        Someone with regexp experience is needed.
+      switch (fmt_words{m}(1:min (2, length (fmt_words{m}))))
+        case "%s"
+          if (pad_out)
+            data(end+1:num_lines) = {""};
+          endif
+          varargout{k} = data';
+          k += 1;
+        case {"%d", "%u", "%f", "%n"}
+          n = cellfun ("isempty", data);
+          ### FIXME: Erroneously formatted data lead to NaN, not an error
+          data = str2double (data);
+          if (! isempty (regexp (fmt_words{m}, "%[du]")))
+            ## Cast to integer
+            ## FIXME: NaNs will be transformed into zeros
+            data = int32 (data);
+          endif
+          data(n) = numeric_fill_value;
+          if (pad_out)
+            data(end+1:num_lines) = numeric_fill_value;
+          endif
+          varargout{k} = data.';
+          k += 1;
+        case {"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%8", "%9"}
+          sw = regexp (fmt_words{m}, '\d', "once");
+          ew = regexp (fmt_words{m}, '[nfudsq]') - 1;
+          nfmt = ostrsplit (fmt_words{m}(2:ew), ".");
+          swidth = str2double (nfmt{1});
+          switch (fmt_words{m}(ew+1))
+            case {"d", "u", "f", "n"}
+              n = cellfun ("isempty", data);
+              ### FIXME: Erroneously formatted data lead to NaN, not an error
+              ###        => ReturnOnError can't be implemented for numeric data
+              data = str2double (strtrunc (data, swidth));
+              data(n) = numeric_fill_value;
+              if (pad_out)
+                data(end+1:num_lines) = numeric_fill_value;
+              endif
+              if (numel (nfmt) > 1)
+                sprec = str2double (nfmt{2});
+                data = 10^-sprec * round (10^sprec * data);
+              elseif (! isempty (regexp (fmt_words{m}, "[du]")))
+                ## Cast to integer
+                ## FIXME: NaNs will be transformed into zeros
+                data = int32 (data);
+              endif
+              varargout{k} = data.';
+              k += 1;
+            case "s"
+              if (pad_out)
+                data(end+1:num_lines) = {""};
+              endif
+              varargout{k} = strtrunc (data, swidth)';
+              k += 1;
+            otherwise
+          endswitch
+        case {"%*", "%*s"}
+          ## skip the word
+        otherwise
+          ## Ensure descriptive content is consistent.
+          ## Test made a bit lax to accomodate for incomplete last lines
+          n = find (! cellfun ("isempty", data));
+          if (numel (unique (data(n))) > 1
+              || ! strcmpi (unique (data), fmt_words{m}))
+            error ("strread: FORMAT does not match data");
+          endif
+      endswitch
+    catch
+      ## As strread processes columnwise, ML-compatible error processing
+      ## (row after row) is not feasible.  In addition Octave sets
+      ## unrecognizable numbers to NaN w/o error.  But maybe Octave is better
+      ## in this respect.
+      if (err_action)
+        ## Just try the next column where ML bails out
+      else
+        rethrow (lasterror);
+      endif
+    end_try_catch
+  endfor
+
+endfunction
+
+function out = split_by (text, sep, mult_dlms_s1, eol_char)
+
+  ## Check & if needed, process MultipleDelimsAsOne parameter
+  if (mult_dlms_s1)
+    mult_dlms_s1 = true;
+    ## FIXME: Should re-implement strsplit() function here in order
+    ## to avoid strrep on megabytes of data.
+    ## If \n is in sep collection we need to enclose it in text
+    ## to avoid it being included in consecutive delim series
+    enchr = ' ';
+    ## However watch out if eol_char is also in delimiters
+    if (index (sep, eol_char)); enchr = char (255); endif
+    text = strrep (text, eol_char, [enchr eol_char enchr]);
+  else
+    mult_dlms_s1 = false;
+  endif
+
+  ## Split text string along delimiters
+  out = ostrsplit (text, sep, mult_dlms_s1);
+  if (index (sep, eol_char)); out = strrep (out, char (255), ''); endif
+  ## In case of trailing delimiter, strip stray last empty word
+  if (! isempty (out) && any (sep == text(end)) && ! mult_dlms_s1)
+    out(end) = [];
+  endif
+
+  ## Empty cells converted to empty cellstrings.
+  out(cellfun ("isempty", out)) = {""};
+
+endfunction
+
+
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:legacy-function", "local");
+%! strread ("");
+
+%!test
+%! [a, b] = strread ("1 2", "%f%f");
+%! assert (a, 1);
+%! assert (b, 2);
+
+%!test
+%! str = "";
+%! a = rand (10, 1);
+%! b = char (randi ([65, 85], 10, 1));
+%! for k = 1:10
+%!   str = sprintf ("%s %.6f %s\n", str, a(k), b(k));
+%! endfor
+%! [aa, bb] = strread (str, "%f %s");
+%! assert (aa, a, 1e-6);
+%! assert (bb, cellstr (b));
+
+%!test
+%! str = "";
+%! a = rand (10, 1);
+%! b = char (randi ([65, 85], 10, 1));
+%! for k = 1:10
+%!   str = sprintf ("%s %.6f %s\n", str, a(k), b(k));
+%! endfor
+%! aa = strread (str, "%f %*s");
+%! assert (aa, a, 1e-6);
+
+%!test
+%! str = sprintf ("/* this is\nacomment*/ 1 2 3");
+%! a = strread (str, "%f", "commentstyle", "c");
+%! assert (a, [1; 2; 3]);
+
+%!test
+%! str = "# comment\n# comment\n1 2 3";
+%! [a, b] = strread (str, "%n %s", "commentstyle", "shell", "endofline", "\n");
+%! assert (a, [1; 3]);
+%! assert (b, {"2"});
+
+%!test
+%! assert (strread ("Hello World! // this is comment", "%s",
+%!                  "commentstyle", "c++"),
+%!         {"Hello"; "World!"});
+%! assert (strread ("Hello World! % this is comment", "%s",...
+%!                  "commentstyle", "matlab"), ...
+%!         {"Hello"; "World!"});
+%! assert (strread ("Hello World! # this is comment", "%s",...
+%!                  "commentstyle", "shell"), ...
+%!         {"Hello"; "World!"});
+
+%!test <*49454>
+%! assert (strread ("hello%foo\nworld, another%bar\r\nday", "%s", ...
+%!                  "commentstyle", "matlab", "delimiter", " ,"),...
+%!         {"hello"; "world"; "another"; "day"});
+
+%!test
+%! str = sprintf ("Tom 100 miles/hr\nDick 90 miles/hr\nHarry 80 miles/hr");
+%! fmt = "%s %f miles/hr";
+%! c = cell (1, 2);
+%! [c{:}] = strread (str, fmt);
+%! assert (c{1}, {"Tom"; "Dick"; "Harry"});
+%! assert (c{2}, [100; 90; 80]);
+
+%!test
+%! a = strread ("a b c, d e, , f", "%s", "delimiter", ",");
+%! assert (a, {"a b c"; "d e"; ""; "f"});
+
+%! ## Format repeat counters w & w/o trailing EOL even within partly read files
+%!test
+%! [a, b] = strread ("10 a 20 b\n 30 c 40", "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"});
+%! [a, b] = strread ("10 a 20 b\n 30 c 40\n", "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; ""});
+%! [a, b] = strread ("10 a 20 b\n 30 c 40", "%d %s", 1);
+%! assert (a, int32 (10));
+%! assert (b, {"a"});
+
+%!test <*33536>
+%! [a, b, c] = strread ("1,,2", "%s%s%s", "delimiter", ",");
+%! assert (a{1}, "1");
+%! assert (b{1}, "");
+%! assert (c{1}, "2");
+
+%!test <*33536>
+%!test
+%! a = strread ("[SomeText]", "[%s", "delimiter", "]");
+%! assert (a{1}, "SomeText");
+
+%!test
+%! dat = "Data file.\r\n=  =  =  =  =\r\nCOMPANY    : <Company name>\r\n";
+%! a = strread (dat, "%s", "delimiter", "\n", "whitespace", "", "endofline", "\r\n");
+%! assert (a{2}, "=  =  =  =  =");
+%! assert (double (a{3}(end-5:end)), [32 110 97 109 101 62]);
+
+%!test
+%! [a, b, c, d] = strread ("1,2,3,,5,6", "%d%f%d%f", "delimiter", ",");
+%! assert (c, int32 (3));
+%! assert (d, NaN);
+
+%!test
+%! [a, b, c, d] = strread ("1,2,3,,5,6\n", "%d%d%f%d", "delimiter", ",");
+%! assert (c, [3; NaN]);
+%! assert (d, int32 ([0; 0]));
+
+## Default format (= %f)
+%!test
+%! [a, b, c] = strread ("0.12 0.234 0.3567");
+%! assert (a, 0.12);
+%! assert (b, 0.234);
+%! assert (c, 0.3567);
+
+%!test
+%! [a, b] = strread ("0.41 8.24 3.57 6.24 9.27", "%f%f", 2, "delimiter", " ");
+%! assert (a, [0.41; 3.57]);
+
+## TreatAsEmpty
+%!test
+%! [a, b, c, d] = strread ("1,2,3,NN,5,6\n", "%d%d%d%f", "delimiter", ",", "TreatAsEmpty", "NN");
+%! assert (c, int32 ([3; 0]));
+%! assert (d, [NaN; NaN]);
+
+## No delimiters at all besides EOL.  Plain reading numbers & strings
+%!test
+%! str = "Text1Text2Text\nText398Text4Text\nText57Text";
+%! [a, b] = strread (str, "Text%dText%1sText");
+%! assert (a, int32 ([1; 398; 57]));
+%! assert (b(1:2), {"2"; "4"});
+%! assert (isempty (b{3}), true);
+
+## MultipleDelimsAsOne
+%!test
+%! str = "11, 12, 13,, 15\n21,, 23, 24, 25\n,, 33, 34, 35";
+%! [a b c d] = strread (str, "%f %f %f %f", "delimiter", ",", "multipledelimsasone", 1, "endofline", "\n");
+%! assert (a', [11, 21, NaN]);
+%! assert (b', [12, 23, 33]);
+%! assert (c', [13, 24, 34]);
+%! assert (d', [15, 25, 35]);
+
+%!assert <*44750> (strread ('/home/foo/','%s','delimiter','/','MultipleDelimsAsOne',1),
+%!                {"home"; "foo"})
+
+## delimiter as sq_string and dq_string
+%!assert (strread ("1\n2\n3", "%d", "delimiter", "\n"),
+%!        strread ("1\n2\n3", "%d", "delimiter", '\n'))
+
+## whitespace as sq_string and dq_string
+%!assert (strread ("1\b2\r3\b4\t5", "%d", "whitespace", "\b\r\n\t"),
+%!        strread ("1\b2\r3\b4\t5", "%d", "whitespace", '\b\r\n\t'))
+
+%!test
+%! str =  "0.31 0.86 0.94\n 0.60 0.72 0.87";
+%! fmt = "%f %f %f";
+%! args = {"delimiter", " ", "endofline", "\n", "whitespace", " "};
+%! [a, b, c] = strread (str, fmt, args{:});
+%! assert (a, [0.31; 0.60], 0.01);
+%! assert (b, [0.86; 0.72], 0.01);
+%! assert (c, [0.94; 0.87], 0.01);
+
+%!test
+%! str =  "0.31,0.86,0.94\n0.60,0.72,0.87";
+%! fmt = "%f %f %f";
+%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
+%! [a, b, c] = strread (str, fmt, args{:});
+%! assert (a, [0.31; 0.60], 0.01);
+%! assert (b, [0.86; 0.72], 0.01);
+%! assert (c, [0.94; 0.87], 0.01);
+
+%!test
+%! str =  "0.31 0.86 0.94\n 0.60 0.72 0.87";
+%! fmt = "%f %f %f";
+%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
+%! [a, b, c] = strread (str, fmt, args{:});
+%! assert (a, [0.31; 0.60], 0.01);
+%! assert (b, [0.86; 0.72], 0.01);
+%! assert (c, [0.94; 0.87], 0.01);
+
+%!test
+%! str =  "0.31, 0.86, 0.94\n 0.60, 0.72, 0.87";
+%! fmt = "%f %f %f";
+%! args = {"delimiter", ",", "endofline", "\n", "whitespace", " "};
+%! [a, b, c] = strread (str, fmt, args{:});
+%! assert (a, [0.31; 0.60], 0.01);
+%! assert (b, [0.86; 0.72], 0.01);
+%! assert (c, [0.94; 0.87], 0.01);
+
+%!test
+%! [a, b] = strread (["Empty 1" char(10)], "Empty%s %f");
+%! assert (a{1}, '1');
+%! assert (b, NaN);
+
+%!test
+%! [a, b] = strread (["Empty" char(10)], "Empty%f %f");
+%! assert (a, NaN);
+%! assert (b, NaN);
+
+%!test <*35999>
+%! [a, b, c] = strread ("", "%f");
+%! assert (isempty (a));
+%! assert (isempty (b));
+%! assert (isempty (c));
+
+%!test <*37023>
+%! [a, b] = strread (" 1. 1 \n  2 3 \n", "%f %f", "endofline", "\n");
+%! assert (a, [1; 2], 1e-15);
+%! assert (b, [1; 3], 1e-15);
+
+## Test for no output arg (interactive use)
+%!assert (strread (",2,,4\n5,,7,", "", "delimiter", ","),
+%!        [NaN; 2; NaN; 4; 5; NaN; 7])
+
+## Test #1 bug #42609
+%!test <*42609>
+%! [a, b, c] = strread ("1 2 3\n4 5 6\n7 8 9\n", "%f %f %f\n");
+%! assert (a, [1; 4; 7]);
+%! assert (b, [2; 5; 8]);
+%! assert (c, [3; 6; 9]);
+
+## Test #2 bug #42609
+%!test <*42609>
+%! [a, b, c] = strread ("1 2\n3\n4 5\n6\n7 8\n9\n", "%f %f\n%f");
+%! assert (a, [1;4;7]);
+%! assert (b, [2; 5; 8]);
+%! assert (c, [3; 6; 9]);
+
+## Test #3 bug #42609
+%!test <*42609>
+%! [a, b, c] = strread ("1 2 3\n4 5 6\n7 8 9\n", '%f %f %f\n');
+%! assert (a, [1; 4; 7]);
+%! assert (b, [2; 5; 8]);
+%! assert (c, [3; 6; 9]);
+
+## Test #4 bug #42609
+%!test <*42609>
+%! [a, b, c] = strread ("1 2\n3\n4 5\n6\n7 8\n9\n", '%f %f\n%f');
+%! assert (a, [1;4;7]);
+%! assert (b, [2; 5; 8]);
+%! assert (c, [3; 6; 9]);
+
+## Unsupported format specifiers
+%!error <format specifiers are not supported> strread ("a", "%c")
+%!error <format specifiers are not supported> strread ("a", "%*c %d")
+%!error <format specifiers are not supported> strread ("a", "%q")
+%!error <format specifiers are not supported> strread ("a", "%*q %d")
+%!error <format specifiers are not supported> strread ("a", "%[a]")
+%!error <format specifiers are not supported> strread ("a", "%*[a] %d")
+%!error <format specifiers are not supported> strread ("a", "%[^a]")
+%!error <format specifiers are not supported> strread ("a", "%*[^a] %d")
+%!error <format specifiers are not supported> strread ("a", "%d8")
+%!error <format specifiers are not supported> strread ("a", "%*d8 %s")
+%!error <format specifiers are not supported> strread ("a", "%f64")
+%!error <format specifiers are not supported> strread ("a", "%*f64 %s")
+%!error <format specifiers are not supported> strread ("a", "%u32")
+%!error <format specifiers are not supported> strread ("a", "%*u32 %d")
+
+## Illegal format specifiers
+%!error <no valid format conversion specifiers> strread ("1.0", "%z")
+
+## Test for false positives in check for non-supported format specifiers
+%!assert (strread ("Total: 32.5 % (of cm values)","Total: %f % (of cm values)"), 32.5, 1e-5)
+
+## Test various forms of string format specifiers
+%!test <*45712>
+%! str = "14 :1 z:2 z:3 z:5 z:11";
+%! [a, b, c, d] = strread (str, "%f %s %*s %3s %*3s %f", "delimiter", ":");
+%! assert ({a, b, c, d}, {14, {"1 z"}, {"3 z"}, 11});
+
+## Allow cuddling %sliteral but warn that it is ambiguous
+%!warning <Ambiguous '%s' specifier immediately before literal in column 1>
+%! [a, b] = strread ("abcxyz51\nxyz83\n##xyz101", "%s xyz %d");
+%! assert (a([1 3]), {"abc"; "##"});
+%! assert (isempty (a{2}), true);
+%! assert (b, int32([51; 83; 101]));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/textread.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,529 @@
+## Copyright (C) 2009-2018 Eric Chassande-Mottin, CNRS (France)
+##
+## 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{a}, @dots{}] =} textread (@var{filename})
+## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format})
+## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n})
+## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{prop1}, @var{value1}, @dots{})
+## @deftypefnx {} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n}, @var{prop1}, @var{value1}, @dots{})
+##
+## This function is obsolete.  Use @code{textscan} instead.
+##
+## Read data from a text file.
+##
+## The file @var{filename} is read and parsed according to @var{format}.  The
+## function behaves like @code{strread} except it works by parsing a file
+## instead of a string.  See the documentation of @code{strread} for details.
+##
+## In addition to the options supported by @code{strread}, this function
+## supports two more:
+##
+## @itemize
+## @item @qcode{"headerlines"}:
+## The first @var{value} number of lines of @var{filename} are skipped.
+##
+## @item @qcode{"endofline"}:
+## Specify a single character or
+## @qcode{"@xbackslashchar{}r@xbackslashchar{}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
+##
+## The optional input @var{n} (format repeat count) specifies the number of
+## times the format string is to be used or the number of lines to be read,
+## whichever happens first while reading.  The former is equivalent to
+## requesting that the data output vectors should be of length @var{N}.
+## Note that when reading files with format strings referring to multiple
+## lines, @var{n} should rather be the number of lines to be read than the
+## number of format string uses.
+##
+## If the format string is empty (not just omitted) and the file contains only
+## numeric data (excluding headerlines), textread will return a rectangular
+## matrix with the number of columns matching the number of numeric fields on
+## the first data line of the file.  Empty fields are returned as zero values.
+##
+## Examples:
+##
+## @example
+## @group
+##   Assume a data file like:
+##   1 a 2 b
+##   3 c 4 d
+##   5 e
+## @end group
+## @end example
+##
+## @example
+## @group
+##   [a, b] = textread (f, "%f %s")
+##   returns two columns of data, one with doubles, the other a
+##   cellstr array:
+##   a = [1; 2; 3; 4; 5]
+##   b = @{"a"; "b"; "c"; "d"; "e"@}
+## @end group
+## @end example
+##
+## @example
+## @group
+##   [a, b] = textread (f, "%f %s", 3)
+##   (read data into two culumns, try to use the format string
+##   three times)
+##   returns
+##   a = [1; 2; 3]
+##   b = @{"a"; "b"; "c"@}
+##
+## @end group
+## @end example
+##
+## @example
+## @group
+##   With a data file like:
+##   1
+##   a
+##   2
+##   b
+##
+##   [a, b] = textread (f, "%f %s", 2)
+##   returns a = 1 and b = @{"a"@}; i.e., the format string is used
+##   only once because the format string refers to 2 lines of the
+##   data file.  To obtain 2x1 data output columns, specify N = 4
+##   (number of data lines containing all requested data) rather
+##   than 2.
+## @end group
+## @end example
+##
+## @seealso{textscan, load, dlmread, fscanf, strread}
+## @end deftypefn
+
+function varargout = textread (filename, format = "%f", varargin)
+
+  persistent warned = false;
+  if (! warned)
+    warned = true;
+    warning ("Octave:legacy-function",
+             "textread is obsolete; use textscan instead\n");
+  endif
+
+  ## Check input
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (! ischar (filename) || ! ischar (format))
+    error ("textread: FILENAME and FORMAT arguments must be strings");
+  endif
+
+  if (! isempty (varargin) && isnumeric (varargin{1}))
+    nlines = varargin{1};
+  else
+    nlines = Inf;
+  endif
+  if (nlines < 1)
+    printf ("textread: N = 0, no data read\n");
+    varargout = cell (1, nargout);
+    return;
+  endif
+
+  BUFLENGTH = 4096;       # Read buffer to speed up processing @var{n}
+
+  ## Read file
+  fid = fopen (filename, "r");
+  if (fid == -1)
+    error ("textread: could not open '%s' for reading", filename);
+  endif
+
+  ## Skip header lines if requested
+  headerlines = find (strcmpi (varargin, "headerlines"), 1);
+  if (! isempty (headerlines))
+    ## Beware of missing or wrong headerline value
+    if (headerlines == numel (varargin)
+       || ! isnumeric (varargin{headerlines + 1}))
+      error ("textread: missing or invalid value for 'headerlines'" );
+    endif
+    ## Avoid conveying floats to fskipl
+    varargin{headerlines + 1} = round (varargin{headerlines + 1});
+    ## Beware of zero valued headerline, fskipl would skip to EOF
+    if (varargin{headerlines + 1} > 0)
+      fskipl (fid, varargin{headerlines + 1});
+    elseif (varargin{headerlines + 1} < 0)
+      warning ("textread: negative headerline value ignored");
+    endif
+    varargin(headerlines:headerlines+1) = [];
+  endif
+  st_pos = ftell (fid);
+
+  ## Read a first file chunk.  Rest follows after endofline processing
+  [str, count] = fscanf (fid, "%c", BUFLENGTH);
+  if (isempty (str) || count < 1)
+    warning ("textread: empty file");
+    varargout = cell (1, nargout);
+    return;
+  endif
+
+  endofline = find (strcmpi (varargin, "endofline"), 1);
+  if (! isempty (endofline))
+    ## 'endofline' option set by user.
+    if (ischar (varargin{endofline + 1}))
+      eol_char = varargin{endofline + 1};
+      if (strcmp (typeinfo (eol_char), "sq_string"))
+        eol_char = do_string_escapes (eol_char);
+      endif
+      if (! any (strcmp (eol_char, {"", "\n", "\r", "\r\n"})))
+        error ("textread: invalid EndOfLine character value specified");
+      endif
+    else
+      error ("textread: character value required for EndOfLine");
+    endif
+  else
+    ## Determine EOL from file.
+    ## Search for EOL candidates in the first BUFLENGTH chars
+    ## FIXME: Ignore risk of 2-byte EOL (\r\n) being split at exactly BUFLENGTH
+    eol_srch_len = min (length (str), BUFLENGTH);
+    ## First try DOS (CRLF)
+    if (! isempty (strfind (str(1 : eol_srch_len), "\r\n")))
+      eol_char = "\r\n";
+    ## Perhaps old Macintosh? (CR)
+    elseif (! isempty (strfind (str(1 : eol_srch_len), "\r")))
+      eol_char = "\r";
+    ## Otherwise, use plain *nix (LF)
+    else
+      eol_char = "\n";
+    endif
+    ## Set up default endofline param value
+    varargin(end+1:end+2) = {"endofline", eol_char};
+  endif
+
+  ## Now that we know what EOL looks like, we can process format_repeat_count.
+  ## FIXME: The below isn't ML-compatible: counts lines, not format string uses
+  if (isfinite (nlines) && (nlines > 0))
+    l_eol_char = length (eol_char);
+    eoi = strfind (str, eol_char);
+    n_eoi = length (eoi);
+    nblks = 0;
+    ## Avoid slow repeated str concatenation, first seek requested end of data
+    while (n_eoi < nlines && count == BUFLENGTH)
+      [nstr, count] = fscanf (fid, "%c", BUFLENGTH);
+      if (count > 0)
+        ## Watch out for multichar EOL being missed across buffer boundaries
+        if (l_eol_char > 1)
+          str = [str(end - length (eol_char) + 2 : end) nstr];
+        else
+          str = nstr;
+        endif
+        eoi = strfind (str, eol_char);
+        n_eoi += numel (eoi);
+        ++nblks;
+      endif
+    endwhile
+    ## Handle case of missing or incomplete trailing EOL
+    if (! strcmp (str(end - length (eol_char) + 1 : end), eol_char))
+      eoi = [ eoi (length (str)) ];
+      ++n_eoi;
+    endif
+    ## Found EOL delimiting last requested line.  Compute ptr (incl. EOL)
+    if (isempty (eoi))
+      eoi_pos = nblks * BUFLENGTH + count;
+    else
+      eoi_pos = (nblks * BUFLENGTH) + eoi(end + min (nlines, n_eoi) - n_eoi);
+    endif
+    fseek (fid, st_pos, "bof");
+    str = fscanf (fid, "%c", eoi_pos);
+  else
+    fseek (fid, st_pos, "bof");
+    str = fread (fid, "char=>char").';
+  endif
+  fclose (fid);
+
+  ## Set up default whitespace param value if needed
+  if (isempty (find (strcmpi ("whitespace", varargin))))
+    varargin(end+1:end+2) = {"whitespace", " \b\t"};
+  endif
+
+  ## Call strread to make it do the real work
+  warning ("off", "Octave:legacy-function", "local");
+  [varargout{1:max (nargout, 1)}] = strread (str, format, varargin{:});
+
+  ## Hack to concatenate/reshape numeric output into 2D array (undocumented ML)
+  ## In ML this only works in case of an empty format string
+  if (isempty (format))
+    ## Get number of fields per line.
+    ## 1. Get eol_char position
+    iwhsp = find (strcmpi ("whitespace", varargin));
+    whsp = varargin{iwhsp + 1};
+    idx = regexp (str, eol_char, "once");
+    ## 2. Get first data line til EOL. Avoid corner case of just one line
+    if (! isempty (idx))
+      str = str(1:idx-1);
+    endif
+    idelimiter = find (strcmpi (varargin, "delimiter"), 1);
+    if (isempty (idelimiter))
+      ## Assume delimiter = whitespace
+      ## 3A. whitespace incl. consecutive whitespace => single space
+      str = regexprep (str, sprintf ("[%s]+", whsp), ' ');
+      ## 4A. Remove possible leading & trailing spaces
+      str = strtrim (str);
+      ## 5A. Count spaces, add one to get nr of data fields per line
+      ncols = numel (strfind (str, " ")) + 1;
+    else
+      ## 3B. Just count delimiters. FIXME: delimiters could occur in literals
+      delimiter = varargin{idelimiter+1};
+      ncols = numel (regexp (str, sprintf ("[%s]", delimiter))) + 1;
+    endif
+    ## 6. Reshape; watch out, we need a transpose
+    nrows = ceil (numel (varargout{1}) / ncols);
+    pad = mod (numel (varargout{1}), ncols);
+    if (pad > 0)
+      pad = ncols - pad;
+      varargout{1}(end+1 : end+pad) = NaN;
+    endif
+    varargout{1} = reshape (varargout{1}, ncols, nrows)';
+    ## ML replaces empty values with NaNs
+    varargout{1}(find (isnan (varargout{1}))) = 0;
+  endif
+
+endfunction
+
+
+## First test is necessary to provoke 1-time legacy warning
+%!test
+%! warning ("off", "Octave:legacy-function", "local");
+%! try
+%!   textread ("");
+%! catch
+%!   ## Nothing to do, just wanted to suppress error.
+%! end_try_catch
+
+%!test
+%! f = tempname ();
+%! d = rand (5, 3);
+%! dlmwrite (f, d, "precision", "%5.2f");
+%! [a, b, c] = textread (f, "%f %f %f", "delimiter", ",", "headerlines", 3);
+%! unlink (f);
+%! assert (a, d(4:5, 1), 1e-2);
+%! assert (b, d(4:5, 2), 1e-2);
+%! assert (c, d(4:5, 3), 1e-2);
+
+%!test
+%! f = tempname ();
+%! d = rand (7, 2);
+%! dlmwrite (f, d, "precision", "%5.2f");
+%! [a, b] = textread (f, "%f, %f", "headerlines", 1);
+%! unlink (f);
+%! assert (a, d(2:7, 1), 1e-2);
+
+## Test reading 2D matrix with empty format
+%!test
+%! f = tempname ();
+%! d = rand (5, 2);
+%! dlmwrite (f, d, "precision", "%5.2f");
+%! A = textread (f, "", "headerlines", 3);
+%! unlink (f);
+%! assert (A, d(4:5, :), 1e-2);
+
+## Read multiple lines using empty format string
+%!test
+%! f = tempname ();
+%! unlink (f);
+%! fid = fopen (f, "w");
+%! d = rand (1, 4);
+%! fprintf (fid, "  %f %f   %f  %f ", d);
+%! fclose (fid);
+%! A = textread (f, "");
+%! unlink (f);
+%! assert (A, d, 1e-6);
+
+## Empty format, corner case = one line w/o EOL
+%!test
+%! f = tempname ();
+%! unlink (f);
+%! fid = fopen (f, "w");
+%! d = rand (1, 4);
+%! fprintf (fid, "  %f %f   %f  %f ", d);
+%! fclose (fid);
+%! A = textread (f, "");
+%! unlink (f);
+%! assert (A, d, 1e-6);
+
+## Tests with format repeat count #1
+%!test
+%! f = tempname ();
+%! fid = fopen (f, "w");
+%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d %s \n", ...
+%!                10, "a", 20, "b", 30, "c", 40, "d");
+%! fclose (fid);
+%! [a, b] = textread (f, "%d %s", 1);
+%! assert (a, int32 (10));
+%! assert (b, {"a"});
+%! [a, b] = textread (f, "%d %s", 2);
+%! assert (a, int32 ([10; 20]));
+%! assert (b, {"a"; "b"});
+%! [a, b] = textread (f, "%d %s", 3);
+%! assert (a, int32 ([10; 20; 30]));
+%! assert (b, {"a"; "b"; "c"});
+%! [a, b] = textread (f, "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; "d"});
+%! [a, b] = textread (f, "%d %s", 5);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; "d"});
+%! unlink (f);
+
+## Tests with format repeat count #2, missing last EOL
+%!test
+%! f = tempname ();
+%! fid = fopen (f, "w");
+%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d %s", ...
+%!                10, "a", 20, "b", 30, "c", 40, "d");
+%! fclose (fid);
+%! [a, b] = textread (f, "%d %s", 1);
+%! assert (a, int32 (10));
+%! assert (b, {"a"});
+%! [a, b] = textread (f, "%d %s", 2);
+%! assert (a, int32 ([10; 20]));
+%! assert (b, {"a"; "b"});
+%! [a, b] = textread (f, "%d %s", 3);
+%! assert (a, int32 ([10; 20; 30]));
+%! assert (b, {"a"; "b"; "c"});
+%! [a, b] = textread (f, "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; "d"});
+%! [a, b] = textread (f, "%d %s", 5);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; "d"});
+%! unlink (f);
+
+## Tests with format repeat count #3, incomplete last line
+%!test
+%! f = tempname ();
+%! fid = fopen (f, "w");
+%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d", ...
+%!                10, "a", 20, "b", 30, "c", 40);
+%! fclose (fid);
+%! [a, b] = textread (f, "%d %s", 1);
+%! assert (a, int32 (10));
+%! assert (b, {"a"});
+%! [a, b] = textread (f, "%d %s", 2);
+%! assert (a, int32 ([10; 20]));
+%! assert (b, {"a"; "b"});
+%! [a, b] = textread (f, "%d %s", 3);
+%! assert (a, int32 ([10; 20; 30]));
+%! assert (b, {"a"; "b"; "c"});
+%! [a, b] = textread (f, "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"});
+%! [a, b] = textread (f, "%d %s", 5);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"});
+%! unlink (f);
+
+## Tests with format repeat count #4, incomplete last line but with trailing EOL
+%!test
+%! f = tempname ();
+%! fid = fopen (f, "w");
+%! fprintf (fid, "%2d %s %2d %s\n %2d %s %2d\n", ...
+%!                10, "a", 20, "b", 30, "c", 40);
+%! fclose (fid);
+%! [a, b] = textread (f, "%d %s", 4);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; ""});
+%! [a, b] = textread (f, "%d %s", 5);
+%! assert (a, int32 ([10; 20; 30; 40]));
+%! assert (b, {"a"; "b"; "c"; ""});
+%! unlink (f);
+
+### Tests with format repeat count #5, nr of data lines = limiting factor
+#%!test
+#%! f = tempname ();
+#%! fid = fopen (f, "w");
+#%! fprintf (fid, "%2d\n%s\n%2dn%s", ...
+#%!                1, "a", 2, "b");
+#%! fclose (fid);
+#%! [a, b] = textread (f, "%d %s", 2);
+#%! assert (a, int32 (1));
+#%! assert (b, {"a"});
+
+### Read multiple lines using empty format string, missing data (should be 0)
+#%!test
+#%! f = tempname ();
+#%! unlink (f);
+#%! fid = fopen (f, "w");
+#%! d = rand (1, 4);
+#%! fprintf (fid, "%f, %f, ,  %f,  %f ", d);
+#%! fclose (fid);
+#%! A = textread (f, "");
+#%! unlink (f);
+#%! assert (A, [ d(1:2) 0 d(3:4)], 1e-6);
+
+### Test with empty positions - ML returns 0 for empty fields
+#%!test
+#%! f = tempname ();
+#%! unlink (f);
+#%! fid = fopen (f, "w");
+#%! d = rand (1, 4);
+#%! fprintf (fid, ",2,,4\n5,,7,\n");
+#%! fclose (fid);
+#%! A = textread (f, "", "delimiter", ",");
+#%! unlink (f);
+#%! assert (A, [0 2 0 4; 5 0 7 0], 1e-6);
+
+### Another test with empty format + positions, now with more incomplete lower
+### row (must be appended with zeros to get rectangular matrix)
+#%!test
+#%! f = tempname ();
+#%! unlink (f);
+#%! fid = fopen (f, "w");
+#%! d = rand (1, 4);
+#%! fprintf (fid, ",2,,4\n5,\n");
+#%! fclose (fid);
+#%! A = textread (f, "", "delimiter", ",");
+#%! unlink (f);
+#%! assert (A, [0 2 0 4; 5 0 0 0], 1e-6);
+
+### Test endofline
+#%!test <*45046>
+#%! f = tempname ();
+#%! fid = fopen (f, "w");
+#%! fprintf (fid, "a\rb\rc");
+#%! fclose (fid);
+#%! ## Test EOL detection
+#%! d = textread (f, "%s");
+#%! assert (d, {"a";"b";"c"});
+#%! ## Test explicit EOL specification (bug #45046)
+#%! d = textread (f, "%s", "endofline", "\r");
+#%! assert (d, {"a"; "b"; "c"});
+#%! unlink (f);
+
+### Properly process single-quoted EOL args
+#%!test <*46477>
+#%! f = tempname ();
+#%! fid = fopen (f, "w");
+#%! fprintf (fid, "hello, world!");
+#%! fclose (fid);
+#%! [a, b] = textread (f, "%s%s", "endofline", '\n');
+#%! assert (a{1}, "hello,");
+#%! assert (b{1}, "world!");
+
+### Test input validation
+#%!error textread ()
+#%!error textread (1)
+#%!error <arguments must be strings> textread (1, "%f")
+#%!error <arguments must be strings> textread ("fname", 1)
+#%!error <missing or invalid value for> textread (file_in_loadpath ("textread.m"), "", "headerlines")
+#%!error <missing or invalid value for> textread (file_in_loadpath ("textread.m"), "", "headerlines", 'hh')
+#%!error <character value required for> textread (file_in_loadpath ("textread.m"), "%s", "endofline", true)
--- a/scripts/linear-algebra/condest.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/condest.m	Thu Dec 20 17:18:56 2018 -0500
@@ -146,18 +146,6 @@
     print_usage ();
   endif
 
-  if ((nargin == 3 && is_function_handle (varargin{3}))
-      || (nargin == 4 && is_function_handle (varargin{3})
-          && isnumeric (varargin{4})))
-    ## onenormest syntax, deprecated in 4.2
-    [cest, v] = condest_legacy (varargin{:});
-    return;
-  elseif ((nargin >= 5) && is_function_handle (varargin{4}))
-    ## onenormest syntax, deprecated in 4.2
-    [cest, v] = condest_legacy (varargin{:});
-    return;
-  endif
-
   have_A = false;
   have_t = false;
   have_apply_normest1 = false;
@@ -168,8 +156,8 @@
     if (! issquare (A))
       error ("condest: A must be square");
     endif
+    have_A = true;
     n = rows (A);
-    have_A = true;
     if (nargin > 1)
       if (is_function_handle (varargin{2}))
         solve = varargin{2};
@@ -186,12 +174,15 @@
     else
       real_op = isreal (A);
     endif
-  else  # varargin{1} is a function handle
+  elseif (is_function_handle (varargin{1}))
     if (nargin == 1)
       error("condest: must provide SOLVEFCN when using AFCN");
     endif
     apply = varargin{1};
     have_apply_normest1 = true;
+    if (! is_function_handle (varargin{2}))
+      error("condest: SOLVEFCN must be a function handle");
+    endif
     solve = varargin{2};
     have_solve_normest1 = true;
     n = apply ("dim", [], varargin{4:end});
@@ -199,12 +190,17 @@
       t = varargin{3};
       have_t = true;
     endif
+  else
+    error ("condest: first argument must be a square matrix or function handle");
   endif
 
   if (! have_t)
     t = min (n, 5);
   endif
 
+  ## 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 (issparse (A))
@@ -214,6 +210,13 @@
       [L, U, P] = lu (A);
       solve = @(flag, x) solve_not_sparse (flag, x, n, real_op, L, U, P);
     endif
+
+    ## Check for singular matrices before continuing
+    if (any (diag (U) == 0))
+      cest = Inf;
+      v = [];
+      return;
+    endif
   endif
 
   if (have_A)
@@ -224,7 +227,9 @@
   [Ainv_norm, v, w] = normest1 (solve, t, [], varargin{4:end});
 
   cest = Anorm * Ainv_norm;
-  v = w / norm (w, 1);
+  if (isargout (2))
+    v = w / norm (w, 1);
+  endif
 
 endfunction
 
@@ -254,96 +259,6 @@
   endswitch
 endfunction
 
-## FIXME: remove after 4.4
-function [cest, v] = condest_legacy (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "condest: this syntax is deprecated, call condest (A, SOLVEFUN, T, P1, P2, ...) instead.");
-  endif
-
-  default_t = 5;
-
-  have_A = false;
-  have_t = false;
-  have_solve = false;
-  if (isnumeric (varargin{1}))
-    A = varargin{1};
-    if (! issquare (A))
-      error ("condest: matrix must be square");
-    endif
-    n = rows (A);
-    have_A = true;
-
-    if (nargin > 1)
-      if (! is_function_handle (varargin{2}))
-        t = varargin{2};
-        have_t = true;
-      elseif (nargin > 2)
-        solve = varargin{2};
-        solve_t = varargin{3};
-        have_solve = true;
-        if (nargin > 3)
-          t = varargin{4};
-          have_t = true;
-        endif
-      else
-        error ("condest: must supply both SOLVE and SOLVE_T");
-      endif
-    endif
-  elseif (nargin > 4)
-    apply = varargin{1};
-    apply_t = varargin{2};
-    solve = varargin{3};
-    solve_t = varargin{4};
-    have_solve = true;
-    n = varargin{5};
-    if (! isscalar (n))
-      error ("condest: dimension argument of implicit form must be scalar");
-    endif
-    if (nargin > 5)
-      t = varargin{6};
-      have_t = true;
-    endif
-  else
-    error ("condest: implicit form of condest requires at least 5 arguments");
-  endif
-
-  if (! have_t)
-    t = min (n, default_t);
-  endif
-
-  if (! have_solve)
-    if (issparse (A))
-      [L, U, P, Pc] = lu (A);
-      solve = @(x) Pc' * (U \ (L \ (P * x)));
-      solve_t = @(x) P' * (L' \ (U' \ (Pc * x)));
-    else
-      [L, U, P] = lu (A);
-      solve = @(x) U \ (L \ (P*x));
-      solve_t = @(x) P' * (L' \ (U' \ x));
-    endif
-  endif
-
-  ## We already warned about this usage being deprecated.
-  ## Don't warn again about onenormest.
-  warning ("off", "Octave:deprecated-function", "local");
-
-  if (have_A)
-    Anorm = norm (A, 1);
-  else
-    Anorm = onenormest (apply, apply_t, n, t);
-  endif
-
-  [Ainv_norm, v, w] = onenormest (solve, solve_t, n, t);
-
-  cest = Anorm * Ainv_norm;
-  v = w / norm (w, 1);
-
-endfunction
-
 
 ## Note: These test bounds are very loose.  There is enough randomization to
 ## trigger odd cases with hilb().
@@ -373,9 +288,9 @@
 %!    case "real"
 %!      value = isreal (A);
 %!    case "notransp"
-%!      value = x; for i = 1:m, value = A \ value;, endfor;
+%!      value = x; for i = 1:m, value = A \ value;, endfor
 %!    case "transp"
-%!      value = x; for i = 1:m, value = A' \ value;, endfor;
+%!      value = x; for i = 1:m, value = A' \ value;, endfor
 %!  endswitch
 %!endfunction
 
@@ -386,37 +301,7 @@
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-8);
 
-%!test # to be removed after 4.4
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 6;
-%! A = hilb (N);
-%! solve = @(x) A\x; solve_t = @(x) A'\x;
-%! cA = condest (A, solve, solve_t);
-%! cA_test = norm (inv (A), 1) * norm (A, 1);
-%! assert (cA, cA_test, -2^-8);
-
-%!test # to be removed after 4.4
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 6;
-%! A = hilb (N);
-%! apply = @(x) A*x; apply_t = @(x) A'*x;
-%! solve = @(x) A\x; solve_t = @(x) A'\x;
-%! cA = condest (apply, apply_t, solve, solve_t, N);
-%! cA_test = norm (inv (A), 1) * norm (A, 1);
-%! assert (cA, cA_test, -2^-6);
-
-%!test # to be removed after 4.4
-%! warning ("off", "Octave:deprecated-function", "local");
-%! N = 6;
-%! A = hilb (N);
-%! apply = @(x) A*x; apply_t = @(x) A'*x;
-%! solve = @(x) A\x; solve_t = @(x) A'\x;
-%! cA = condest (apply, apply_t, solve, solve_t, N, 2);
-%! cA_test = norm (inv (A), 1) * norm (A, 1);
-%! assert (cA, cA_test, -2^-6);
-
 %!test
-%! warning ("off", "Octave:nearly-singular-matrix", "local");
 %! N = 12;
 %! A = hilb (N);
 %! [~, v] = condest (A);
@@ -448,8 +333,18 @@
 %! cA_test = norm (inv (A^2), 1) * norm (A^2, 1);
 %! assert (cA, cA_test, -2^-6);
 
+%!test <*46737>
+%! A = [ 0         0         0
+%!       0   3.33333 0.0833333
+%!       0 0.0833333   1.66667];
+%! [cest, v] = condest (A);
+%! assert (cest, Inf);
+%! assert (v, []);
+
 ## 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 <argument must be a square matrix or function handle> condest ({1})
--- a/scripts/linear-algebra/expm.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/expm.m	Thu Dec 20 17:18:56 2018 -0500
@@ -82,7 +82,10 @@
     error ("expm: A must be a square matrix");
   endif
 
-  if (isscalar (A))
+  if (isempty (A))
+    r = A;
+    return;
+  elseif (isscalar (A))
     r = exp (A);
     return;
   elseif (strfind (typeinfo (A), "diagonal matrix"))
@@ -91,36 +94,31 @@
   endif
 
   n = rows (A);
+  id = eye (n);
   ## Trace reduction.
   A(A == -Inf) = -realmax;
-  trshift = trace (A) / length (A);
+  trshift = trace (A) / n;
   if (trshift > 0)
-    A -= trshift*eye (n);
+    A -= trshift * id;
   endif
   ## Balancing.
   [d, p, aa] = balance (A);
-  ## FIXME: can we both permute and scale at once? Or should we rather do
-  ## this:
-  ##
-  ##   [d, xx, aa] = balance (A, "noperm");
-  ##   [xx, p, aa] = balance (aa, "noscal");
-  [f, e] = log2 (norm (aa, "inf"));
+  [~, e] = log2 (norm (aa, "inf"));
   s = max (0, e);
   s = min (s, 1023);
   aa *= 2^(-s);
 
   ## Pade approximation for exp(A).
-  c = [5.0000000000000000e-1,...
-       1.1666666666666667e-1,...
-       1.6666666666666667e-2,...
-       1.6025641025641026e-3,...
-       1.0683760683760684e-4,...
-       4.8562548562548563e-6,...
-       1.3875013875013875e-7,...
+  c = [5.0000000000000000e-1, ...
+       1.1666666666666667e-1, ...
+       1.6666666666666667e-2, ...
+       1.6025641025641026e-3, ...
+       1.0683760683760684e-4, ...
+       4.8562548562548563e-6, ...
+       1.3875013875013875e-7, ...
        1.9270852604185938e-9];
 
   a2 = aa^2;
-  id = eye (n);
   x = (((c(8) * a2 + c(6) * id) * a2 + c(4) * id) * a2 + c(2) * id) * a2 + id;
   y = (((c(7) * a2 + c(5) * id) * a2 + c(3) * id) * a2 + c(1) * id) * aa;
 
@@ -136,7 +134,7 @@
   r = d * r / d;
   r(p, p) = r;
   ## Inverse trace reduction.
-  if (trshift >0)
+  if (trshift > 0)
     r *= exp (trshift);
   endif
 
@@ -146,11 +144,13 @@
 %!assert (norm (expm ([1 -1;0 1]) - [e -e; 0 e]) < 1e-5)
 %!assert (expm ([1 -1 -1;0 1 -1; 0 0 1]), [e -e -e/2; 0 e -e; 0 0 e], 1e-5)
 
-%!assert (expm (10), expm (10))
+%!assert (expm ([]), [])
+%!assert (expm (10), exp (10))
 %!assert (full (expm (eye (3))), expm (full (eye (3))))
 %!assert (full (expm (10*eye (3))), expm (full (10*eye (3))), 8*eps)
 
 ## Test input validation
 %!error expm ()
 %!error expm (1, 2)
+%!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/isdefinite.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/isdefinite.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,12 +19,24 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} isdefinite (@var{A})
 ## @deftypefnx {} {} isdefinite (@var{A}, @var{tol})
-## Return 1 if @var{A} is symmetric positive definite within the
-## tolerance specified by @var{tol} or 0 if @var{A} is symmetric
-## positive semi-definite.  Otherwise, return -1.
+## Return true if @var{A} is symmetric positive definite matrix within the
+## tolerance specified by @var{tol}.
 ##
 ## If @var{tol} is omitted, use a tolerance of
-## @code{100 * eps * norm (@var{A}, "fro")}
+## @code{100 * eps * norm (@var{A}, "fro")}.
+##
+## Background: A positive definite matrix has eigenvalues which are all
+## greater than zero.  A positive semi-definite matrix has eigenvalues which
+## are all greater than or equal to zero.  The matrix @var{A} is very likely to
+## be positive semi-definite if the following two conditions hold for a
+## suitably small tolerance @var{tol}.
+##
+## @example
+## @group
+## isdefinite (@var{A}) @result{} 0
+## isdefinite (@var{A} + 5*@var{tol}, @var{tol}) @result{} 1
+## @end group
+## @end example
 ## @seealso{issymmetric, ishermitian}
 ## @end deftypefn
 
@@ -38,50 +50,58 @@
     print_usage ();
   endif
 
+  ## Validate inputs
+  retval = false;
+  if (! isnumeric (A))
+    return;
+  endif
+
   if (! isfloat (A))
     A = double (A);
   endif
 
   if (nargin == 1)
     tol = 100 * eps (class (A)) * norm (A, "fro");
+  elseif (! (isnumeric (tol) && isscalar (tol) && tol >= 0))
+    error ("isdefinite: TOL must be a scalar >= 0");
   endif
 
   if (! ishermitian (A, tol))
-    error ("isdefinite: A must be a Hermitian matrix");
+    return;
   endif
 
   e = tol * eye (rows (A));
-  [r, p] = chol (A - e);
+  [~, p] = chol (A - e);
   if (p == 0)
-    retval = 1;
-  else
-    [r, p] = chol (A + e);
-    if (p == 0)
-      retval = 0;
-    else
-      retval = -1;
-    endif
+    retval = true;
   endif
 
 endfunction
 
 
 %!test
-%! A = [-1 0; 0 -1];
-%! assert (isdefinite (A), -1);
+%! A = [-1, 0; 0, -1];
+%! assert (isdefinite (A), false);
+
+%!test
+%! A = [1, 0; 0, 1];
+%! assert (isdefinite (A), true);
 
 %!test
-%! A = [1 0; 0 1];
-%! assert (isdefinite (A), 1);
+%! A = [2, -1,  0; -1, 2, -1; 0, -1, 2];
+%! assert (isdefinite (A), true);
 
+## Test for positive semi-definite matrix
 %!test
-%! A = [2 -1 0; -1 2 -1; 0 -1 2];
-%! assert (isdefinite (A), 1);
+%! A = [1, 0; 0, 0];
+%! assert (isdefinite (A), false);
+%! tol = 100*eps;
+%! assert (isdefinite (A+5*tol, tol), true);
 
-%!test
-%! A = [1 0; 0 0];
-%! assert (isdefinite (A), 0);
+%!assert (! isdefinite (magic (3)))
 
 %!error isdefinite ()
 %!error isdefinite (1,2,3)
-%!error <A must be a Hermitian matrix> isdefinite ([1 2; 3 4])
+%!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	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/isdiag.m	Thu Dec 20 17:18:56 2018 -0500
@@ -30,7 +30,7 @@
     print_usage ();
   endif
 
-  if (strcmp (typeinfo (A), "diagonal matrix"))
+  if (strfind (typeinfo (A), "diagonal matrix"))
     retval = true;
   elseif ((isnumeric (A) || islogical (A)) && ndims (A) == 2)
     [i, j] = find (A);
@@ -49,8 +49,9 @@
 %!assert (isdiag ([1, 1]), false)
 %!assert (isdiag ([1; 1]), false)
 %!assert (isdiag (eye (10)))
+%!assert (isdiag (single (eye (10))))
 %!assert (isdiag (logical (eye (10))))
-%!assert (isdiag (speye (1e6)))
+%!assert (isdiag (speye (1e2)))
 %!assert (isdiag (diag (1:10)))
 
 ## Test input validation
--- a/scripts/linear-algebra/ishermitian.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/ishermitian.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,13 +20,27 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} ishermitian (@var{A})
 ## @deftypefnx {} {} ishermitian (@var{A}, @var{tol})
-## Return true if @var{A} is Hermitian within the tolerance specified by
-## @var{tol}.
+## @deftypefnx {} {} ishermitian (@var{A}, @qcode{"skew"})
+## @deftypefnx {} {} ishermitian (@var{A}, @qcode{"skew"}, @var{tol})
+## Return true if @var{A} is a Hermitian or skew-Hermitian matrix within the
+## tolerance specified by @var{tol}.
 ##
 ## The default tolerance is zero (uses faster code).
 ##
-## Matrix @var{A} is considered symmetric if
+## The type of symmetry to check may be specified with the additional input
+## @qcode{"nonskew"} (default) for regular Hermitian or @qcode{"skew"} for
+## skew-Hermitian.
+##
+## Background: A matrix is Hermitian if the complex conjugate transpose of the
+## matrix is equal to the original matrix: @w{@tcode{@var{A} == @var{A}'}}.  If
+## a tolerance is given then the calculation is
 ## @code{norm (@var{A} - @var{A}', Inf) / norm (@var{A}, Inf) < @var{tol}}.
+##
+## A matrix is skew-Hermitian if the complex conjugate transpose of the matrix
+## is equal to the negative of the original matrix:
+## @w{@tcode{@var{A} == -@var{A}'}}.  If a
+## tolerance is given then the calculation is
+## @code{norm (@var{A} + @var{A}', Inf) / norm (@var{A}, Inf) < @var{tol}}.
 ## @seealso{issymmetric, isdefinite}
 ## @end deftypefn
 
@@ -34,19 +48,52 @@
 ## Created: August 1993
 ## Adapted-By: jwe
 
-function retval = ishermitian (A, tol = 0)
+function retval = ishermitian (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
-  retval = isnumeric (A) && issquare (A);
-  if (retval)
+  if (nargin == 2)
+    ## Decode whether second argument is skewopt or tol
+    if (isnumeric (skewopt))
+      tol = skewopt;
+      skewopt = "nonskew";
+    elseif (! ischar (skewopt))
+      error ("ishermitian: second argument must be a non-negative scalar TOL, or one of the strings: 'skew' / 'nonskew'");
+    endif
+  endif
+
+  ## Validate inputs
+  retval = (isnumeric (A) || islogical (A)) && issquare (A);
+  if (! retval)
+    return;
+  endif
+
+  if (! (strcmp (skewopt, "skew") || strcmp (skewopt, "nonskew")))
+    error ("ishermitian: SKEWOPT must be 'skew' or 'nonskew'");
+  endif
+
+  if (! (isnumeric (tol) && isscalar (tol) && tol >= 0))
+    error ("ishermitian: TOL must be a scalar >= 0");
+  endif
+
+  ## Calculate Hermitian-ness
+  if (strcmp (skewopt, "nonskew"))
     if (tol == 0)
-      retval = all ((A == A')(:));
+      ## check for exact symmetry
+      retval = ! any ((A != A')(:));
     else
-      norm_x = norm (A, inf);
-      retval = norm_x == 0 || norm (A - A', inf) / norm_x <= tol;
+      norm_x = norm (A, Inf);
+      retval = norm_x == 0 || norm (A - A', Inf) / norm_x <= tol;
+    endif
+  else
+    ## skew-Hermitian
+    if (tol == 0)
+      retval = ! any ((A != -A')(:));
+    else
+      norm_x = norm (A, Inf);
+      retval = norm_x == 0 || norm (A + A', Inf) / norm_x <= tol;
     endif
   endif
 
@@ -57,15 +104,28 @@
 %!assert (! ishermitian ([1, 2]))
 %!assert (ishermitian ([]))
 %!assert (ishermitian ([1, 2; 2, 1]))
-%!assert (! ishermitian ("test"))
 %!assert (ishermitian ([1, 2.1; 2, 1.1], 0.2))
 %!assert (ishermitian ([1, -2i; 2i, 1]))
-%!assert (! ishermitian ("t"))
-%!assert (! ishermitian (["te"; "et"]))
+%!assert (ishermitian (speye (100)))
+%!assert (ishermitian (logical (eye (2))))
+%!assert (ishermitian ([0, 2i; 2i, 0], "skew"))
+%!assert (! ishermitian ([0, 2; -2, eps], "skew"))
+%!assert (ishermitian ([0, 2; -2, eps], "skew", eps))
 
+%!assert (! (ishermitian ("test")))
+%!assert (! (ishermitian ("t")))
+%!assert (! (ishermitian (["te"; "et"])))
+%!assert (! ishermitian ({1}))
 %!test
 %! s.a = 1;
 %! assert (! ishermitian (s));
 
-%!error ishermitian ([1, 2; 2, 1], 0, 0)
+## Test input validation
 %!error ishermitian ()
+%!error ishermitian (1,2,3,4)
+%!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")
+%!error <TOL must be a scalar .= 0> ishermitian (1, "skew", {1})
+%!error <TOL must be a scalar .= 0> ishermitian (1, "skew", [1 1])
+%!error <TOL must be a scalar .= 0> ishermitian (1, -1)
--- a/scripts/linear-algebra/issymmetric.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/issymmetric.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,13 +20,26 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} issymmetric (@var{A})
 ## @deftypefnx {} {} issymmetric (@var{A}, @var{tol})
-## Return true if @var{A} is a symmetric matrix within the tolerance specified
-## by @var{tol}.
+## @deftypefnx {} {} issymmetric (@var{A}, @qcode{"skew"})
+## @deftypefnx {} {} issymmetric (@var{A}, @qcode{"skew"}, @var{tol})
+## Return true if @var{A} is a symmetric or skew-symmetric matrix within the
+## tolerance specified by @var{tol}.
 ##
 ## The default tolerance is zero (uses faster code).
 ##
-## Matrix @var{A} is considered symmetric if
+## The type of symmetry to check may be specified with the additional input
+## @qcode{"nonskew"} (default) for regular symmetry or @qcode{"skew"} for
+## skew-symmetry.
+##
+## Background: A matrix is symmetric if the transpose of the matrix is equal
+## to the original matrix: @w{@tcode{@var{A} == @var{A}.'}}.  If a tolerance
+## is given then symmetry is determined by
 ## @code{norm (@var{A} - @var{A}.', Inf) / norm (@var{A}, Inf) < @var{tol}}.
+##
+## A matrix is skew-symmetric if the transpose of the matrix is equal to the
+## negative of the original matrix: @w{@tcode{@var{A} == -@var{A}.'}}.  If a
+## tolerance is given then skew-symmetry is determined by
+## @code{norm (@var{A} + @var{A}.', Inf) / norm (@var{A}, Inf) < @var{tol}}.
 ## @seealso{ishermitian, isdefinite}
 ## @end deftypefn
 
@@ -34,20 +47,52 @@
 ## Created: August 1993
 ## Adapted-By: jwe
 
-function retval = issymmetric (A, tol = 0)
+function retval = issymmetric (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
+  if (nargin == 2)
+    ## Decode whether second argument is skewopt or tol
+    if (isnumeric (skewopt))
+      tol = skewopt;
+      skewopt = "nonskew";
+    elseif (! ischar (skewopt))
+      error ("issymmetric: second argument must be a non-negative scalar TOL, or one of the strings: 'skew' / 'nonskew'");
+    endif
+  endif
+
+  ## Validate inputs
   retval = (isnumeric (A) || islogical (A)) && issquare (A);
-  if (retval)
+  if (! retval)
+    return;
+  endif
+
+  if (! (strcmp (skewopt, "skew") || strcmp (skewopt, "nonskew")))
+    error ("issymmetric: SKEWOPT must be 'skew' or 'nonskew'");
+  endif
+
+  if (! (isnumeric (tol) && isscalar (tol) && tol >= 0))
+    error ("issymmetric: TOL must be a scalar >= 0");
+  endif
+
+  ## Calculate symmetry
+  if (strcmp (skewopt, "nonskew"))
     if (tol == 0)
-      ## Handle large sparse matrices as well as full ones
-      retval = nnz (A != A.') == 0;
+      ## check for exact symmetry
+      retval = ! any ((A != A.')(:));
     else
-      norm_x = norm (A, inf);
-      retval = norm_x == 0 || norm (A - A.', inf) / norm_x <= tol;
+      norm_x = norm (A, Inf);
+      retval = norm_x == 0 || norm (A - A.', Inf) / norm_x <= tol;
+    endif
+  else
+    ## skew symmetry
+    if (tol == 0)
+      retval = ! any ((A != -A.')(:));
+    else
+      norm_x = norm (A, Inf);
+      retval = norm_x == 0 || norm (A + A.', Inf) / norm_x <= tol;
     endif
   endif
 
@@ -58,17 +103,28 @@
 %!assert (! issymmetric ([1, 2]))
 %!assert (issymmetric ([]))
 %!assert (issymmetric ([1, 2; 2, 1]))
-%!assert (! (issymmetric ("test")))
 %!assert (issymmetric ([1, 2.1; 2, 1.1], 0.2))
 %!assert (issymmetric ([1, 2i; 2i, 1]))
+%!assert (issymmetric (speye (100)))
+%!assert (issymmetric (logical (eye (2))))
+%!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 (speye (100000)))
-%!assert (issymmetric (logical (eye (2))))
-
+%!assert (! issymmetric ({1}))
 %!test
 %! s.a = 1;
 %! assert (! issymmetric (s));
 
-%!error issymmetric ([1, 2; 2, 1], 0, 0)
+## Test input validation
 %!error issymmetric ()
+%!error issymmetric (1,2,3,4)
+%!error <second argument must be> issymmetric (1, {"skew"})
+%!error <SKEWOPT must be 'skew' or 'nonskew'> issymmetric (1, "foobar")
+%!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])
+%!error <TOL must be a scalar .= 0> issymmetric (1, -1)
--- a/scripts/linear-algebra/krylov.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/krylov.m	Thu Dec 20 17:18:56 2018 -0500
@@ -221,7 +221,7 @@
   ## Back out complete U matrix.
   ## back out U matrix.
   j1 = columns (U);
-  for i = j1:-1:1;
+  for i = j1:-1:1
     idx = pivot_vec(i:na);
     hv = U(idx,i);
     av = alpha(i);
--- a/scripts/linear-algebra/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/linear-algebra/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -26,6 +26,7 @@
   %reldir%/normest1.m \
   %reldir%/null.m \
   %reldir%/ols.m \
+  %reldir%/ordeig.m \
   %reldir%/orth.m \
   %reldir%/planerot.m \
   %reldir%/qzhess.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/linear-algebra/ordeig.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,140 @@
+## Copyright (C) 2018 Marco Caliari
+## Copyright (C) 2018 Sébastien Villemot <sebastien@debian.org>
+##
+## 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{lambda} =} ordeig (@var{A})
+## @deftypefnx {} {@var{lambda} =} ordeig (@var{A}, @var{B})
+## Return the eigenvalues of quasi-triangular matrices in their order of
+## appearance in the matrix @var{A}.
+##
+## The quasi-triangular matrix @var{A} is usually the result of a Schur
+## factorization.  If called with a second input @var{B} then the generalized
+## eigenvalues of the pair @var{A}, @var{B} are returned in the order of
+## 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}
+## @end deftypefn
+
+function lambda = ordeig (A, B)
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
+
+  if (! isnumeric (A) || ! issquare (A))
+    error ("ordeig: A must be a square matrix")
+  endif
+
+  n = length (A);
+
+  if (nargin == 1)
+    B = eye (n);
+    if (isreal (A))
+      if (! isquasitri (A))
+        error ("ordeig: A must be quasi-triangular (i.e., upper block triangular with 1x1 or 2x2 blocks on the diagonal)");
+      endif
+    else
+      if (! istriu (A))
+        error ("ordeig: A must be upper-triangular when it is complex");
+      endif
+    endif
+  else
+    if (! isnumeric (B) || ! issquare (B))
+      error ("ordeig: B must be a square matrix");
+    elseif (length (B) != n)
+      error ("ordeig: A and B must be the same size");
+    endif
+    if (isreal (A) && isreal (B))
+      if (! isquasitri (A) || ! isquasitri (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
+      if (! istriu (A) || ! istriu (B))
+        error ("ordeig: A and B must both be upper-triangular if either is complex");
+      endif
+    endif
+  endif
+
+  ## Start of algorithm
+  lambda = zeros (n, 1);
+
+  i = 1;
+  while (i <= n)
+    if (i == n || (A(i+1,i) == 0 && B(i+1,i) == 0))
+      lambda(i) = A(i,i) / B(i,i);
+    else
+      a = B(i,i) * B(i+1,i+1);
+      b = - (A(i,i) * B(i+1,i+1) + A(i+1,i+1) * B(i,i));
+      c = A(i,i) * A(i+1,i+1) - ...
+          (A(i,i+1) - B(i,i+1)) * (A(i+1,i) - B(i+1,i));
+      if (b > 0)
+        lambda(i) = 2*c / (-b - sqrt (b^2 - 4*a*c));
+        i += 1;
+        lambda(i) = (-b - sqrt (b^2 - 4*a*c)) / 2 / a;
+      else
+        lambda(i) = (-b + sqrt (b^2 - 4*a*c)) / 2 / a;
+        i += 1;
+        lambda(i) = 2*c / (-b + sqrt (b^2 - 4*a*c));
+      endif
+    endif
+    i += 1;
+  endwhile
+
+endfunction
+
+# Checks whether a matrix is quasi-triangular
+function retval = isquasitri (A)
+  v = diag (A, -1) != 0;
+  retval = all (tril (A, -2)(:) == 0) && all (v(1:end-1) + v(2:end) < 2);
+endfunction
+
+
+%!test
+%! A = toeplitz ([0, 1, 0, 0], [0, -1, 0, 0]);
+%! T = schur (A);
+%! lambda = ordeig (T);
+%! assert (lambda, [1.61803i; -1.61803i; 0.61803i; -0.61803i], 1e-4);
+
+%!test
+%! A = toeplitz ([0, 1, 0, 0], [0, -1, 0, 0]);
+%! B = toeplitz ([0, 0, 0, 1], [0, -1, 0, 2]);
+%! [AA, BB] = qz (A, B);
+%! assert (isreal (AA) && isreal (BB));
+%! lambda = ordeig (AA, BB);
+%! assert (lambda, [0.5+0.86603i; 0.5-0.86603i; i; -i], 1e-4);
+%! [AA, BB] = qz (complex (A), complex (B));
+%! assert (iscomplex (AA) && iscomplex (BB));
+%! lambda = ordeig (AA, BB);
+%! assert (lambda, diag (AA) ./ diag (BB));
+
+## Test input validation
+%!error ordeig ()
+%!error ordeig (1,2,3)
+%!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))
+%!error <A must be upper-triangular> ordeig ([1, 0; i, 1])
+%!error <B must be a square matrix> ordeig (1, 'a')
+%!error <B must be a square matrix> ordeig (1, [1, 2])
+%!error <A and B must be the same size> ordeig (1, ones (2,2))
+%!error <A and B must be quasi-triangular>
+%! ordeig (triu (magic (3)), magic (3))
+%!error <A and B must both be upper-triangular>
+%! ordeig ([1, 1; 0, 1], [1, 0; i, 1])
--- a/scripts/miscellaneous/bunzip2.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/bunzip2.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,8 +17,9 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{filelist} =} bunzip2 (@var{bzfile})
-## @deftypefnx {} {@var{filelist} =} bunzip2 (@var{bzfile}, @var{dir})
+## @deftypefn  {} {} bunzip2 (@var{bzfile})
+## @deftypefnx {} {} bunzip2 (@var{bzfile}, @var{dir})
+## @deftypefnx {} {@var{filelist} =} bunzip2 (@dots{})
 ## Unpack the bzip2 archive @var{bzfile}.
 ##
 ## If @var{dir} is specified the files are unpacked in this directory rather
@@ -36,14 +37,14 @@
     print_usage ();
   endif
 
-  if (isempty (dir))
+  if (isempty (dir) && ischar (bzfile))
     dir = fileparts (bzfile);
   endif
 
   if (nargout > 0)
-    filelist = unpack (bzfile, dir, "bunzip2");
+    filelist = unpack (bzfile, dir, "bz2");
   else
-    unpack (bzfile, dir, "bunzip2");
+    unpack (bzfile, dir, "bz2");
   endif
 
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/clearvars.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,223 @@
+## Copyright (C) 2018 Rik Wehbring
+## Copyright (C) 2013 David Turner
+##
+## 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  {} {} clearvars
+## @deftypefnx {} {} clearvars @var{pattern} @dots{}
+## @deftypefnx {} {} clearvars -regexp @var{pattern} @dots{}
+## @deftypefnx {} {} clearvars @dots{} -except @var{pattern} @dots{}
+## @deftypefnx {} {} clearvars @dots{} -except -regexp @var{pattern} @dots{}
+## @deftypefnx {} {} clearvars -global @dots{}
+## Delete the variables matching the given @var{pattern}s from memory.
+##
+## The @var{pattern} may contain the following special characters:
+##
+## @table @code
+## @item ?
+## Match any single character.
+##
+## @item *
+## Match zero or more characters.
+##
+## @item [ @var{list} ]
+## Match the list of characters specified by @var{list}.  If the first
+## character is @code{!} or @code{^}, match all characters except those
+## specified by @var{list}.  For example, the pattern @code{[a-zA-Z]} will
+## match all lowercase and uppercase alphabetic characters.
+## @end table
+##
+## If the @option{-regexp} option is given then subsequent patterns are treated
+## as regular expressions and any matches will be cleared.
+##
+## If the @option{-except} option is given then subsequent patterns select
+## variables that will @strong{not} be cleared.
+##
+## If the @option{-global} option is given then all patterns will be applied
+## to global variables rather than local variables.
+##
+## When called with no arguments, @code{clearvars} deletes all local variables.
+##
+## Example Code:
+##
+## Clear all variables starting with @qcode{'x'} and the specific variable
+## @qcode{"foobar"}
+##
+## @example
+## clearvars x* foobar
+## @end example
+##
+## Clear the specific variable @qcode{"foobar"} and use regular expressions to
+## clear all variables starting with @qcode{'x'} or @qcode{'y'}.
+##
+## @example
+## clearvars foobar -regexp ^x ^y
+## @end example
+##
+## Clear all variables except for @qcode{"foobar"}
+##
+## @example
+## clearvars -except foobar
+## @end example
+##
+## Clear all variables beginning with @qcode{"foo"}, except for those ending
+## in @qcode{"bar"}
+##
+## @example
+## clearvars foo* -except -regexp bar$
+## @end example
+##
+## @seealso{clear, who, whos, exist}
+## @end deftypefn
+
+function clearvars (varargin)
+
+  numvar = 0;
+  global_mode = false;
+  except_mode = false;
+  regexp_mode = false;
+
+  ## Parse arguments
+  for cellarg = varargin
+    arg = cellarg{1};
+
+    ## Parse options
+    if (strcmp (arg, "-global"))
+      if (numvar > 0)
+        error ("clearvars: '-global' must be the first option when present");
+      endif
+      global_mode = true;
+      continue;
+    elseif (strcmp (arg, "-except"))
+      if (except_mode)
+        error ("clearvars: '-except' may only be specified once");
+      endif
+      except_mode = true;
+      regexp_mode = false;
+      continue;
+    elseif (strcmp (arg, "-regexp"))
+      regexp_mode = true;
+      continue;
+    endif
+
+    ## Parse patterns
+    numvar += 1;
+    vars(numvar).except = except_mode;
+    if (! regexp_mode)
+      vars(numvar).var_name = [ '\<' regexptranslate("wildcard", arg) '\>' ];
+    else
+      vars(numvar).var_name = arg;
+    endif
+
+  endfor
+
+  if (global_mode)
+    varlist = evalin ("caller", "who global");
+  else
+    varlist = evalin ("caller", "who");
+  endif
+
+  ## evalin will cause the automatic creation of 'ans' variable (bug #53339).
+  ## Determine if it needs to be removed at the end of the function.
+  clear_ans = ! any (strcmp (varlist, "ans"));
+
+  if (numvar == 0 || all ([vars.except]))
+    ## For wildcard, select all variables in list
+    idx_clear = true (numel (varlist), 1);
+  else
+    ptn = strjoin ({ vars(! [vars.except]).var_name }, '|');
+    idx_clear = ! cellfun (@isempty, regexp (varlist, ptn));
+  endif
+
+  if (numvar > 0 && any ([vars.except]))
+    ptn = strjoin ({ vars([vars.except]).var_name }, '|');
+    idx_except = ! cellfun (@isempty, regexp (varlist, ptn));
+    idx_clear(idx_except) = false; 
+  endif
+
+  varlist = varlist(idx_clear);
+  names = strjoin (varlist, " ");
+
+  if (! isempty (names))
+    if (global_mode)
+      evalin ("caller", ["clear -global " names]);
+    else
+      evalin ("caller", ["clear " names]);
+    endif
+  endif
+
+  ## Clean up automatic variable "ans" if necessary
+  if (clear_ans)
+    evalin ("caller", "clear ans");
+  endif
+
+endfunction
+
+
+## Tests must be done in a function namespace;
+## Otherwise, they interfere with the BIST environment itself.
+%!function __test_local_vars__ ()
+%!  global x y z
+%!  a = 1; b = 2; c = 3;
+%!  assert (all (ismember ({"a"; "b"; "c"}, who ())));
+%!  ## Test 0-argument form
+%!  clearvars
+%!  assert (isempty (who ()));
+%!
+%!  a = 1; a2 = 2; a33 = 3;
+%!  ## Test special wildcard pattern
+%!  clearvars a?3
+%!  assert (isempty (who ("a33")));
+%!
+%!  a33 = 3;
+%!  ## Test -regexp option
+%!  clearvars -regexp 2 3$
+%!  assert (who ("a*"), {"a"});
+%!
+%!  a = 1; a2 = 2; a33 = 3;
+%!  ## Test -except option
+%!  clearvars a* -except a33
+%!  assert (who ("a", "a2", "a33"), {"a33"});
+%!
+%!  ## Test that non-regexp patterns only select full words
+%!  clearvars a3
+%!  assert (who ("a33"), {"a33"});
+%!endfunction
+
+%!function __test_global_vars__ ()
+%!  global x y z
+%!  a = 1; b = 2; c = 3;
+%!  assert (all (ismember ({"x"; "y"; "z"}, who ("global"))));
+%!  clearvars -global
+%!  assert (isempty (who ("global")));
+%!
+%!  global x y z
+%!  clearvars -global -regexp ^y
+%!  assert (! any (strcmp ("y", who ("global"))));
+%!endfunction
+
+## Run BIST test functions
+%!test __test_local_vars__ ();
+%!test __test_global_vars__ ();
+
+## Test input validation
+%!error <'-global' must be the first option> clearvars ("ans", "-global")
+%!error <'-except' may only be specified once> clearvars ("-except", "-except")
+
+%!test
+%!  clear -global x y z;  # cleanup after test
--- a/scripts/miscellaneous/copyfile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/copyfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -78,7 +78,7 @@
   endif
 
   ## If f1 has more than 1 element then f2 must be a directory
-  isdir = (exist (f2, "dir") != 0);
+  isdir = isfolder (f2);
   if (numel (f1) > 1 && ! isdir)
     error ("copyfile: when copying multiple files, F2 must be a directory");
   endif
--- a/scripts/miscellaneous/edit.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/edit.m	Thu Dec 20 17:18:56 2018 -0500
@@ -220,7 +220,7 @@
 
   ## Start the editor without a file if no file is given.
   if (nargin == 0)
-    if (exist (FUNCTION.HOME, "dir") == 7)
+    if (isfolder (FUNCTION.HOME))
       curr_dir = pwd ();
       unwind_protect
         cd (FUNCTION.HOME);
@@ -332,7 +332,7 @@
 
     ## If editing a new file, prompt for creation if GUI is running
     if (isguirunning ())
-      if (! __octave_link_edit_file__ (file, "prompt"));
+      if (! __octave_link_edit_file__ (file, "prompt"))
         return;
       endif
     endif
--- a/scripts/miscellaneous/fact.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/fact.m	Thu Dec 20 17:18:56 2018 -0500
@@ -274,7 +274,7 @@
   out = "\n";
   i = 1;
   numwords = numel (wc);
-  while (i <= numwords);
+  while (i <= numwords)
     line = wc{i};
     while (i < numwords
            && length (newline = [line " " wc{i+1}]) < ncol)
--- a/scripts/miscellaneous/genvarname.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-## Copyright (C) 2008-2018 Bill Denney, Robert Platt
-##
-## 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{varname} =} genvarname (@var{str})
-## @deftypefnx {} {@var{varname} =} genvarname (@var{str}, @var{exclusions})
-## Create valid unique variable name(s) from @var{str}.
-##
-## If @var{str} is a cellstr, then a unique variable is created for each cell
-## in @var{str}.
-##
-## @example
-## @group
-## genvarname (@{"foo", "foo"@})
-##   @result{}
-##      @{
-##        [1,1] = foo
-##        [1,2] = foo1
-##      @}
-## @end group
-## @end example
-##
-## If @var{exclusions} is given, then the variable(s) will be unique to each
-## other and to @var{exclusions} (@var{exclusions} may be either a string or a
-## cellstr).
-##
-## @example
-## @group
-## x = 3.141;
-## genvarname ("x", who ())
-##   @result{} x1
-## @end group
-## @end example
-##
-## Note that the result is a char array or cell array of strings, not the
-## variables themselves.  To define a variable, @code{eval()} can be used.
-## The following trivial example sets @code{x} to 42.
-##
-## @example
-## @group
-## name = genvarname ("x");
-## eval ([name " = 42"]);
-##   @result{} x =  42
-## @end group
-## @end example
-##
-## This can be useful for creating unique struct field names.
-##
-## @example
-## @group
-## x = struct ();
-## for i = 1:3
-##   x.(genvarname ("a", fieldnames (x))) = i;
-## endfor
-##   @result{} x =
-##      @{
-##        a =  1
-##        a1 =  2
-##        a2 =  3
-##      @}
-## @end group
-## @end example
-##
-## Since variable names may only contain letters, digits, and underscores,
-## @code{genvarname} will replace any sequence of disallowed characters with
-## an underscore.  Also, variables may not begin with a digit; in this case
-## an @samp{x} is added before the variable name.
-##
-## Variable names beginning and ending with two underscores @qcode{"__"} are
-## valid, but they are used internally by Octave and should generally be
-## avoided; therefore, @code{genvarname} will not generate such names.
-##
-## @code{genvarname} will also ensure that returned names do not clash with
-## keywords such as @qcode{"for"} and @qcode{"if"}.  A number will be
-## appended if necessary.  Note, however, that this does @strong{not} include
-## function names such as @qcode{"sin"}.  Such names should be included in
-## @var{exclusions} if necessary.
-## @seealso{isvarname, iskeyword, exist, who, tempname, eval}
-## @end deftypefn
-
-## Authors: Rob Platt <robert.platt@postgrad.manchester.ac.uk>
-##          Bill Denney <bill@denney.ws>
-
-function varname = genvarname (str, exclusions = {})
-
-  if (nargin < 1 || nargin > 2)
-    print_usage ();
-  endif
-
-  strinput = ischar (str);
-  ## Process the inputs
-  if (strinput)
-    if (rows (str) != 1)
-      error ("genvarname: if more than one STR is given, it must be a cellstr");
-    endif
-    str = {str};
-  elseif (! iscellstr (str))
-    error ("genvarname: STR must be a string or cellstr");
-  endif
-
-  if (ischar (exclusions))
-    if (rows (exclusions) != 1)
-      error ("genvarname: if more than one exclusion is given, it must be a cellstr");
-    endif
-    exclusions = {exclusions};
-  elseif (! iscellstr (exclusions))
-    error ("genvarname: EXCLUSIONS must be a string or cellstr");
-  else
-    exclusions = exclusions(:);
-  endif
-
-  varname = cell (size (str));
-  for i = 1:numel (str)
-    ## Perform any modifications to the varname to make sure that it is
-    ## a valid variable name.
-
-    ## remove invalid characters
-    str{i}(! (isalnum (str{i}) | str{i} == "_")) = "_";
-    ## do not use keywords
-    if (iskeyword (str{i}))
-      firstcharacter = toupper (str{i}(1));
-      str{i} = ["x", firstcharacter, str{i}(2:end)];
-    endif
-    ## The variable cannot be empty
-    if (isempty (str{i}))
-      str{i} = "x";
-    endif
-    ## Leading underscores are not Matlab compatible
-    if (str{i}(1) == "_")
-      str{i} = ["x", str{i}];
-    endif
-    ## it cannot start with a number
-    if (isdigit (str{i}(1)))
-      str{i} = ["x", str{i}];
-    endif
-
-    ## make sure that the variable is unique relative to other variables
-    ## and the exclusions list
-    excluded = any (strcmp (str{i}, exclusions));
-    if (excluded && isdigit (str{i}(end)))
-      ## if it is not unique and ends with a digit, add an underscore to
-      ## make the variable name more readable ("x1_1" instead of "x11")
-      str{i} = [str{i}, "_"];
-    endif
-    varname(i) = str(i);
-    idx = 0;
-    while (excluded)
-      idx += 1;
-      varname{i} = sprintf ("%s%d", str{i}, idx);
-      excluded = any (strcmp (varname{i}, exclusions));
-    endwhile
-    exclusions(end+1) = varname(i);
-  endfor
-
-  if (strinput)
-    varname = varname{1};
-  endif
-
-endfunction
-
-
-## a single argument
-%!assert (genvarname ("a"), "a")
-## a single argument with a non-conflicting exception
-%!assert (genvarname ("a", "b"), "a")
-## a single argument with a conflicting exception
-%!assert (genvarname ("a", "a"), "a1")
-## a single argument as a cell
-%!assert (genvarname ({"a"}), {"a"})
-%!assert (genvarname ({"a"}, "b"), {"a"})
-%!assert (genvarname ({"a"}, {"b"}), {"a"})
-%!assert (genvarname ({"a"}, "a"), {"a1"})
-%!assert (genvarname ({"a"}, {"a"}), {"a1"})
-## Test different arguments
-## orientation
-%!assert (genvarname ({"a" "b"}), {"a" "b"})
-%!assert (genvarname ({"a";"b"}), {"a";"b"})
-%!assert (genvarname ({"a" "a"}), {"a" "a1"})
-%!assert (genvarname ({"a" "b";"c" "d"}), {"a" "b";"c" "d"})
-%!assert (genvarname ({"a" "a" "a";"a" "a" "a"}), {"a" "a2" "a4";"a1" "a3" "a5"})
-## more than one repetition
-%!assert (genvarname ({"a" "a" "a"}), {"a" "a1" "a2"})
-%!assert (genvarname ({"a" "a" "a"}, {"a" "a1" "a2"}), {"a3" "a4" "a5"})
-## more than one repetition not in order
-%!assert (genvarname ({"a" "b" "a" "b" "a"}), {"a" "b" "a1" "b1" "a2"})
-## Variable name munging
-%!assert (genvarname ("__x__"), "x__x__")
-%!assert (genvarname ("123456789"), "x123456789")
-%!assert (genvarname ("_$1__"), "x__1__")
-%!assert (genvarname ("__foo__", "x__foo__"), "x__foo__1")
-%!assert (genvarname ("1million_and1", "x1million_and1"), "x1million_and1_1")
-%!assert (genvarname ({"", "", ""}), {"x", "x1", "x2"})
-%!assert (genvarname ("if"), "xIf")
-%!assert (genvarname ({"if", "if", "if"}), {"xIf", "xIf1", "xIf2"})
-## Exclusions in odd format
-%!assert (genvarname ("x", {"a", "b"; "x", "d"}), "x1")
-
-## Test input validation
-%!error genvarname ()
-%!error genvarname (1,2,3)
-%!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"))
-%!error <EXCLUSIONS must be a string or cellstr> genvarname ("x", 1)
--- a/scripts/miscellaneous/gunzip.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/gunzip.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,8 +17,9 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{filelist} =} gunzip (@var{gzfile})
-## @deftypefnx {} {@var{filelist} =} gunzip (@var{gzfile}, @var{dir})
+## @deftypefn  {} {} gunzip (@var{gzfile})
+## @deftypefnx {} {} gunzip (@var{gzfile}, @var{dir})
+## @deftypefnx {} {@var{filelist} =} gunzip (@dots{})
 ## Unpack the gzip archive @var{gzfile}.
 ##
 ## If @var{gzfile} is a directory, all gzfiles in the directory will be
@@ -39,14 +40,14 @@
     print_usage ();
   endif
 
-  if (isempty (dir))
+  if (isempty (dir) && ischar (gzfile))
     dir = fileparts (gzfile);
   endif
 
   if (nargout > 0)
-    filelist = unpack (gzfile, dir, "gunzip");
+    filelist = unpack (gzfile, dir, "gz");
   else
-    unpack (gzfile, dir, "gunzip");
+    unpack (gzfile, dir, "gz");
   endif
 
 endfunction
--- a/scripts/miscellaneous/inputname.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/inputname.m	Thu Dec 20 17:18:56 2018 -0500
@@ -21,6 +21,7 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {} {} inputname (@var{n})
+## @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
@@ -29,12 +30,17 @@
 ##
 ## @code{inputname} is only useful within a function.  When used at the command
 ## line 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.
 ## @seealso{nargin, nthargout}
 ## @end deftypefn
 
-function name = inputname (n)
+function name = inputname (n, ids_only = true)
 
-  if (nargin != 1)
+  if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
@@ -47,7 +53,7 @@
 
   ## For compatibility with Matlab,
   ## return empty string if argument name is not a valid identifier.
-  if (! isvarname (name))
+  if (ids_only && ! isvarname (name))
     name = "";
   endif
 
@@ -77,11 +83,17 @@
 %!assert (inputname (-1), "")
 %!assert (inputname (1), "")
 
-%!function r = __foo__ (x, y)
+%!function r = __foo1__ (x, y)
 %!  r = inputname (2);
 %!endfunction
-%!assert (__foo__ (pi, e), "e")
-%!assert (feval (@__foo__, pi, e), "e")
+%!assert (__foo1__ (pi, e), "e")
+%!assert (feval (@__foo1__, pi, e), "e")
+
+%!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")
 
 %!error inputname ()
-%!error inputname (1,2)
+%!error inputname (1,2,3)
--- a/scripts/miscellaneous/isdir.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-## Copyright (C) 2004-2018 Alois Schloegl
-##
-## 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 {} {} isdir (@var{f})
-## Return true if @var{f} is a directory.
-## @seealso{exist, stat, is_absolute_filename, is_rooted_relative_filename}
-## @end deftypefn
-
-function retval = isdir (f)
-
-  if (nargin != 1)
-    print_usage ();
-  endif
-
-  ## Exist returns an integer but isdir should return a logical.
-  retval = (exist (f, "dir") == 7);
-
-endfunction
-
-
-%!assert (isdir (pwd ()))
-%!assert (! isdir ("this is highly unlikely to be a directory name"))
-
-%!error isdir ()
-%!error isdir (1, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/isfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,73 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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{tf} =} isfile (@var{f})
+## Return true if @var{f} is a regular file and false otherwise.
+##
+## If @var{f} is a cell array of strings, @var{tf} is a logical array of the
+## same size.
+## @seealso{isfolder, exist, stat, is_absolute_filename, is_rooted_relative_filename}
+## @end deftypefn
+
+function retval = isfile (f)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! (ischar (f) || iscellstr (f)))
+    error ("isfile: F must be a string or cell array of strings");
+  endif
+
+  f = cellstr (f);
+  retval = false (size (f));
+  for i = 1:numel (f)
+    [info, err] = stat (f{i});
+    retval(i) = (! err && S_ISREG (info.mode));
+  endfor
+
+endfunction
+
+
+%!shared mfile
+%! mfile = which ("isfile");
+
+%!assert (isfile (mfile))
+%!assert (! isfile (tempdir ()))
+%!assert (isfile ({mfile, pwd()}), [true, false])
+%!assert (isfile ({mfile; pwd()}), [true; false])
+
+%!test
+%! unwind_protect
+%!   tmp = tempname ();
+%!   [d, n] = fileparts (tmp);
+%!   assert (! isfile (tmp));
+%!   save ("-text", tmp, "tmp");  # cheap way to create a file
+%!   assert (isfile (tmp));
+%!   addpath (d);
+%!   assert (! isfile (n));
+%! unwind_protect_cleanup
+%!   try, unlink (tmp); end_try_catch
+%!   try, rmpath (d); end_try_catch
+%! end_unwind_protect
+
+## Test input validation
+%!error isfile ()
+%!error isfile ("a", "b")
+%!error <F must be a string> isfile (1.0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/isfolder.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,73 @@
+## Copyright (C) 2018 Guillaume Flandin
+##
+## 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  {} {} isfolder (@var{f})
+## @deftypefnx {} {@var{tf} =} isfolder (@var{f})
+## Return true if @var{f} is a directory and false otherwise.
+##
+## If @var{f} is a cell array of strings, @var{tf} is a logical array of the
+## same size.
+## @seealso{isfile, exist, stat, is_absolute_filename, is_rooted_relative_filename}
+## @end deftypefn
+
+function retval = isfolder (f)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! (ischar (f) || iscellstr (f)))
+    error ("isfolder: F must be a string or cell array of strings");
+  endif
+
+  f = cellstr (f);
+  retval = false (size (f));
+  for i = 1:numel (f)
+    [info, err] = stat (f{i});
+    retval(i) = (! err && S_ISDIR (info.mode));
+  endfor
+
+endfunction
+
+
+%!assert (isfolder (pwd ()))
+%!assert (! isfolder (tempname ()))
+%!assert (! isfolder (which ("isfolder")))
+%!assert (isfolder ( {pwd(), tempname()}), [true, false])
+%!assert (isfolder ( {pwd(); tempname()}), [true; false])
+
+%!test
+%! unwind_protect
+%!   tmp = tempname ();
+%!   [d, n] = fileparts (tmp);
+%!   assert (! isfolder (tmp));
+%!   mkdir (tmp);
+%!   assert (isfolder (tmp));
+%!   assert (! isfolder (n));
+%!   addpath (d);
+%!   assert (! isfolder (n));
+%! unwind_protect_cleanup
+%!   try, rmdir (tmp); end_try_catch
+%!   try, rmpath (d); end_try_catch
+%! end_unwind_protect
+
+## Test input validation
+%!error isfolder ()
+%!error isfolder ("a", "b")
+%!error <F must be a string> isfolder (1.0)
--- a/scripts/miscellaneous/ls.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/ls.m	Thu Dec 20 17:18:56 2018 -0500
@@ -55,12 +55,6 @@
 
 function retval = ls (varargin)
 
-  global __ls_command__;
-
-  if (isempty (__ls_command__) || ! ischar (__ls_command__))
-    ls_command ();  # Initialize global value for __ls_command__.
-  endif
-
   if (! iscellstr (varargin))
     error ("ls: all arguments must be character strings");
   endif
@@ -90,7 +84,7 @@
     args = ["-1 ", args];
   endif
 
-  cmd = [__ls_command__ " " args];
+  cmd = [ls_command() " " args];
 
   if (page_screen_output () || nargout > 0)
     [status, output] = system (cmd);
--- a/scripts/miscellaneous/ls_command.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/ls_command.m	Thu Dec 20 17:18:56 2018 -0500
@@ -27,7 +27,7 @@
 
 function old_val = ls_command (new_val)
 
-  global __ls_command__;
+  persistent __ls_command__;
 
   if (isempty (__ls_command__))
     ## MinGW uses different ls_command
--- a/scripts/miscellaneous/mkdir.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/mkdir.m	Thu Dec 20 17:18:56 2018 -0500
@@ -71,7 +71,7 @@
 
   status = 1;
 
-  if (! isdir (parent))
+  if (! isfolder (parent))
     [grandparent, name, ext] = fileparts (parent);
     [status, msg, msgid] = mkdir_recur (grandparent, [name, ext]);
   endif
@@ -90,7 +90,7 @@
 %! unwind_protect
 %!   status = mkdir (dir);
 %!   assert (status);
-%!   assert (isdir (dir));
+%!   assert (isfolder (dir));
 %! unwind_protect_cleanup
 %!   confirm_recursive_rmdir (false, "local");
 %!   rmdir (dir1, "s");
@@ -104,7 +104,7 @@
 %!   setenv ("HOME", tmp_dir);
 %!   status = mkdir ("~/subdir");
 %!   assert (status);
-%!   assert (isdir (fullfile (tmp_dir, "subdir")));
+%!   assert (isfolder (fullfile (tmp_dir, "subdir")));
 %! unwind_protect_cleanup
 %!   rmdir (fullfile (tmp_dir, "subdir"));
 %!   rmdir (tmp_dir);
--- a/scripts/miscellaneous/mkoctfile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/mkoctfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -74,36 +74,82 @@
 ##
 ## @item  -p VAR
 ## @itemx --print VAR
-## Print the configuration variable VAR@.  Recognized variables are:
+## Print configuration variable VAR@.  There are three categories of
+## variables:
+##
+## Octave configuration variables that users may override with environment
+## variables.  These are used in commands that @code{mkoctfile} executes.
+##
+## @example
+##    ALL_CFLAGS                  LAPACK_LIBS
+##    ALL_CXXFLAGS                LDFLAGS
+##    ALL_FFLAGS                  LD_CXX
+##    ALL_LDFLAGS                 LD_STATIC_FLAG
+##    BLAS_LIBS                   LFLAGS
+##    CC                          LIBDIR
+##    CFLAGS                      LIBOCTAVE
+##    CPICFLAG                    LIBOCTINTERP
+##    CPPFLAGS                    OCTAVE_LINK_OPTS
+##    CXX                         OCTINCLUDEDIR
+##    CXXFLAGS                    OCTAVE_LIBS
+##    CXXPICFLAG                  OCTAVE_LINK_DEPS
+##    DL_LD                       OCTLIBDIR
+##    DL_LDFLAGS                  OCT_LINK_DEPS
+##    F77                         OCT_LINK_OPTS
+##    F77_INTEGER8_FLAG           RDYNAMIC_FLAG
+##    FFLAGS                      SPECIAL_MATH_LIB
+##    FPICFLAG                    XTRA_CFLAGS
+##    INCFLAGS                    XTRA_CXXFLAGS
+##    INCLUDEDIR
+## @end example
+##
+## Octave configuration variables as above, but currently unused by
+## @code{mkoctfile}.
 ##
 ## @example
-##    ALL_CFLAGS                  INCFLAGS
-##    ALL_CXXFLAGS                INCLUDEDIR
-##    ALL_FFLAGS                  LAPACK_LIBS
-##    ALL_LDFLAGS                 LD_CXX
-##    AR                          LDFLAGS
-##    BLAS_LIBS                   LD_STATIC_FLAG
-##    CC                          LFLAGS
-##    CFLAGS                      LIBDIR
-##    CPICFLAG                    LIBOCTAVE
-##    CPPFLAGS                    LIBOCTINTERP
-##    CXX                         LIBS
-##    CXXFLAGS                    OCTAVE_HOME
-##    CXXPICFLAG                  OCTAVE_LIBS
-##    DEPEND_EXTRA_SED_PATTERN    OCTAVE_LINK_DEPS
-##    DEPEND_FLAGS                OCTAVE_LINK_OPTS
-##    DL_LD                       OCTAVE_PREFIX
-##    DL_LDFLAGS                  OCTINCLUDEDIR
-##    F77                         OCTLIBDIR
-##    F77_INTEGER8_FLAG           OCT_LINK_DEPS
-##    FFLAGS                      OCT_LINK_OPTS
-##    FFTW3F_LDFLAGS              RANLIB
-##    FFTW3F_LIBS                 RDYNAMIC_FLAG
-##    FFTW3_LDFLAGS               READLINE_LIBS
-##    FFTW3_LIBS                  SED
-##    FFTW_LIBS                   SPECIAL_MATH_LIB
-##    FLIBS                       XTRA_CFLAGS
-##    FPICFLAG                    XTRA_CXXFLAGS
+##    AR
+##    DEPEND_EXTRA_SED_PATTERN
+##    DEPEND_FLAGS
+##    FFTW3F_LDFLAGS
+##    FFTW3F_LIBS
+##    FFTW3_LDFLAGS
+##    FFTW3_LIBS
+##    FFTW_LIBS
+##    FLIBS
+##    LIBS
+##    RANLIB
+##    READLINE_LIBS
+## @end example
+##
+## Octave configuration variables that are provided for informational
+## purposes only.  Except for @samp{OCTAVE_HOME} and @samp{OCTAVE_EXEC_HOME},
+## users may not override these variables.
+##
+## If @env{OCTAVE_HOME} or @env{OCTAVE_EXEC_HOME} are set in the environment,
+## then other variables are adjusted accordingly with @env{OCTAVE_HOME} or
+## @env{OCTAVE_EXEC_HOME} substituted for the original value of the directory
+## specified by the @samp{--prefix} or @samp{--exec-prefix} options that were
+## used when Octave was configured.
+##
+## @example
+##    API_VERSION                 LOCALFCNFILEDIR
+##    ARCHLIBDIR                  LOCALOCTFILEDIR
+##    BINDIR                      LOCALSTARTUPFILEDIR
+##    CANONICAL_HOST_TYPE         LOCALVERARCHLIBDIR
+##    DATADIR                     LOCALVERFCNFILEDIR
+##    DATAROOTDIR                 LOCALVEROCTFILEDIR
+##    DEFAULT_PAGER               MAN1DIR
+##    EXEC_PREFIX                 MAN1EXT
+##    EXEEXT                      MANDIR
+##    FCNFILEDIR                  OCTAVE_EXEC_HOME
+##    IMAGEDIR                    OCTAVE_HOME
+##    INFODIR                     OCTDATADIR
+##    INFOFILE                    OCTDOCDIR
+##    LIBEXECDIR                  OCTFILEDIR
+##    LOCALAPIARCHLIBDIR          OCTFONTSDIR
+##    LOCALAPIFCNFILEDIR          STARTUPFILEDIR
+##    LOCALAPIOCTFILEDIR          VERSION
+##    LOCALARCHLIBDIR
 ## @end example
 ##
 ## @item --link-stand-alone
@@ -122,14 +168,18 @@
 ## Echo commands as they are executed.
 ##
 ## @item file
-## The file to compile or link.  Recognized file types are
+## The file to compile or link.  Recognized file types are:
 ##
 ## @example
 ## @group
 ##    .c    C source
 ##    .cc   C++ source
+##    .cp   C++ source
+##    .cpp  C++ source
+##    .CPP  C++ source
+##    .cxx  C++ source
+##    .c++  C++ source
 ##    .C    C++ source
-##    .cpp  C++ source
 ##    .f    Fortran source (fixed form)
 ##    .F    Fortran source (fixed form)
 ##    .f90  Fortran source (free form)
--- a/scripts/miscellaneous/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -13,6 +13,7 @@
   %reldir%/bunzip2.m \
   %reldir%/cast.m \
   %reldir%/citation.m \
+  %reldir%/clearvars.m \
   %reldir%/compare_versions.m \
   %reldir%/computer.m \
   %reldir%/copyfile.m \
@@ -25,7 +26,6 @@
   %reldir%/fileattrib.m \
   %reldir%/fileparts.m \
   %reldir%/fullfile.m \
-  %reldir%/genvarname.m \
   %reldir%/getfield.m \
   %reldir%/grabcode.m \
   %reldir%/gunzip.m \
@@ -33,7 +33,8 @@
   %reldir%/inputParser.m \
   %reldir%/inputname.m \
   %reldir%/isdeployed.m \
-  %reldir%/isdir.m \
+  %reldir%/isfile.m \
+  %reldir%/isfolder.m \
   %reldir%/ismac.m \
   %reldir%/ispc.m \
   %reldir%/isunix.m \
--- a/scripts/miscellaneous/movefile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/movefile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -87,7 +87,7 @@
   endif
 
   ## If f1 has more than 1 element f2 must be a directory
-  isdir = (exist (f2, "dir") != 0);
+  isdir = isfolder (f2);
   if (numel (f1) > 1 && ! isdir)
     error ("movefile: when moving multiple files, F2 must be a directory");
   endif
@@ -117,12 +117,16 @@
         p2 = strrep (p2, '\', '/');
       endif
 
+      ## Close old file(s) in editor
+      __octave_link_file_remove__ (p1, p2);
       ## Move the file(s).
       [err, msg] = system (sprintf ('%s %s "%s"', cmd, p1, p2));
       if (err != 0)
         status = false;
         msgid = "movefile";
       endif
+      ## Load new file(s) in editor
+      __octave_link_file_renamed__ (status);
     endwhile
   else
     if (ispc () && ! isunix ()
@@ -131,12 +135,16 @@
       p2 = strrep (p2, '\', '/');
     endif
 
+    ## Close old file(s) in editor
+    __octave_link_file_remove__ (p1, p2);
     ## Move the file(s).
     [err, msg] = system (sprintf ('%s %s "%s"', cmd, p1, p2));
     if (err != 0)
       status = false;
       msgid = "movefile";
     endif
+    ## Load new file(s) in editor
+    __octave_link_file_renamed__ (status);
   endif
 
 endfunction
--- a/scripts/miscellaneous/nthargout.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/nthargout.m	Thu Dec 20 17:18:56 2018 -0500
@@ -72,12 +72,12 @@
     print_usage ();
   endif
 
-  if (isa (varargin{1}, "function_handle") || ischar (varargin{1}))
+  if (is_function_handle (varargin{1}) || ischar (varargin{1}))
     ntot = max (n(:));
     func = varargin{1};
     args = varargin(2:end);
   elseif (isnumeric (varargin{1})
-          && (isa (varargin{2}, "function_handle") || ischar (varargin{2})))
+          && (is_function_handle (varargin{2}) || ischar (varargin{2})))
     ntot = varargin{1};
     func = varargin{2};
     args = varargin(3:end);
--- a/scripts/miscellaneous/open.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/open.m	Thu Dec 20 17:18:56 2018 -0500
@@ -22,19 +22,45 @@
 ## Open the file @var{file} in Octave or in an external application based on
 ## the file type as determined by the filename extension.
 ##
-## Recognized file types are
+## By default, recognized file types are
 ##
 ## @table @code
 ## @item .m
-## Open file in the editor.
+## Open file in the editor.  No @var{output} value is returned.
 ##
-## @item .mat
-## Load the file in the base workspace.
+## @item  .mat
+## @itemx octave-workspace
+## Open the data file with @code{load}.  If no return value @var{output}
+## is requested, variables are loaded in the base workspace.  Otherwise
+## @var{output} will be a structure containing loaded data.
+## @xref{XREFload, , load function}.
+##
+## @item .ofig
+## Open the figure with hgload.  @xref{XREFhgload, , hgload function}.
+##
+## @item .fig, .ofig
+## Load the figure
 ##
 ## @item .exe
-## Execute the program (on Windows systems only).
+## Execute the program (on Windows systems only).  No @var{output} value
+## is returned.
 ## @end table
 ##
+## Custom file extensions may also be handled if a function @code{openxxx},
+## where @code{xxx} is the extension, is found in the load path.  The function
+## must accept the file name as input.  For example, in order to load
+## @nospell{@qcode{".dat"}} data files in the base workspace, as is done by
+## default for @qcode{".mat"} files, one may define
+## @nospell{@qcode{"opendat.m"}} with the following contents:
+##
+## @example
+## @group
+## function retval = opendat (fname)
+##   evalin ("base", sprintf ("load ('%s');", fname));
+## endfunction
+## @end group
+## @end example
+##
 ## Other file types are opened in the appropriate external application.
 ## @end deftypefn
 
@@ -48,17 +74,39 @@
     error ("open: FILE must be a string");
   endif
 
-  [~, ~, ext] = fileparts (file);
+  if (! exist (file, "file"))
+    error ("open: unable to find file %s", file);
+  endif
+
+  [~, fname, ext] = fileparts (file);
 
-  if (strcmpi (ext, ".m"))
+  if (! isempty (ext)
+      && any (exist (["open" tolower(ext(2:end))]) == [2 3 5 103]))
+    try
+      openfcn = ["open" tolower(ext(2:end))];
+      if (nargout > 0)
+        output = feval (openfcn, file);
+      else
+        feval (openfcn, file);
+      endif
+    catch
+      error ("open: %s", lasterr);
+    end_try_catch
+  elseif (strcmpi (ext, ".m"))
     edit (file);
-  elseif (strcmpi (ext, ".mat"))
+  elseif (strcmpi (ext, ".mat") || strcmp (fname, "octave-workspace"))
     if (nargout > 0)
       output = load (file);
     else
       evalin ("base", sprintf ("load ('%s');", file));
     endif
-  elseif (any (strcmpi (ext, {".fig", ".mdl", ".slx", ".prj"})))
+  elseif (strcmpi (ext, ".ofig"))
+    if (nargout > 0)
+      output = openfig (file);
+    else
+      openfig (file);
+    endif
+  elseif (any (strcmpi (ext, {".mdl", ".slx", ".prj"})))
     error ("open: opening file type '%s' is not supported", ext);
   elseif (strcmpi (ext, ".exe"))
     if (ispc ())
--- a/scripts/miscellaneous/publish.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/publish.m	Thu Dec 20 17:18:56 2018 -0500
@@ -393,6 +393,7 @@
 
   if (options.evalCode)
     doc = eval_code (doc, options);
+    eval_context ("clear");
   endif
 
   output_file = create_output (doc, options);
@@ -425,9 +426,23 @@
   ##
   ## Checks line to have N "%" or "#" lines
   ## followed either by a space or end of string
-  is_publish_markup = @(cstr, N) ...
-    any (strncmp (char (cstr), {"%%%", "##"}, N)) ...
-    && ((length (char (cstr)) == N) || ((char (cstr))(N + 1) == " "));
+  function r = is_publish_markup (cstr, N)
+    str = char (cstr);
+
+    r = any (strncmp (str, {"%%%", "##"}, N));
+    if (r)
+      len = length (str);
+      if (len == N)
+        r = true;
+      elseif (len > N && str(N+1) == " ")
+        r = true;
+      else
+        r = false;
+      endif
+    endif
+
+    return;
+  endfunction
   ## Checks line of cellstring to be a paragraph line
   is_paragraph = @(cstr) is_publish_markup (cstr, 1);
   ## Checks line of cellstring to be a section headline
@@ -945,11 +960,8 @@
   fig_num = 1;
   fig_list = struct ();
 
-  ## File used as temporary context
-  tmp_context = [tempname() ".var"];
-
   ## Evaluate code, that does not appear in the output.
-  eval_code_helper (tmp_context, options.codeToEvaluate);
+  eval_code_helper (options.codeToEvaluate);
 
   ## Create a new figure, if there are existing plots
   if (! isempty (fig_ids) && options.useNewFigure)
@@ -962,13 +974,13 @@
       code_str = strjoin (doc.m_source(r(1):r(2)), "\n");
       if (options.catchError)
         try
-          doc.body{i}.output = eval_code_helper (tmp_context, code_str);
+          doc.body{i}.output = eval_code_helper (code_str);
          catch err
           doc.body{i}.output = cellstr (["error: ", err.message, ...
                                                  "\n\tin:\n\n", code_str]);
         end_try_catch
       else
-        doc.body{i}.output = eval_code_helper (tmp_context, code_str);
+        doc.body{i}.output = eval_code_helper (code_str);
       endif
 
       ## Check for newly created figures ...
@@ -1022,9 +1034,6 @@
   ## Close any figures opened by publish function
   delete (setdiff (findall (0, "type", "figure"), fig_ids));
 
-  ## Remove temporary context
-  unlink (tmp_context);
-
   ## Insert figures to document
   fig_code_blocks = fieldnames (fig_list);
   body_offset = 0;
@@ -1039,29 +1048,63 @@
 endfunction
 
 
-function cstr = eval_code_helper (context, code)
+function cstr = eval_code_helper (__code__)
   ## EVAL_CODE_HELPER evaluates a given string with Octave code in an extra
   ## temporary context and returns a cellstring with the eval output.
 
-  if (isempty (code))
+  if (isempty (__code__))
     return;
   endif
 
-  load_snippet = "";
-  if (exist (context, "file") == 2)
-    load_snippet = sprintf ('load ("%s");', context);
-  endif
-  save_snippet = sprintf ('save ("-binary", "%s");', context);
-
-  eval (sprintf ("function __eval__ ()\n%s\n%s\n%s\nendfunction",
-                 load_snippet, code, save_snippet));
-
-  cstr = strsplit (evalc ("__eval__"), "\n");
+  eval_context ("load");
+  cstr = evalc (__code__);
+  ## Split string by lines and preserve blank lines.
+  cstr = strsplit (strrep (cstr, "\n\n", "\n \n"), "\n");
+  eval_context ("save");
 endfunction
 
 
-## FIXME: Missing any functional BIST tests
-## FIXME: Need to create a temporary file for use with error testing
+function cstr = eval_context (op)
+  ## EVAL_CONTEXT temporary evaluation context.
+  persistent ctext
+
+  ## Variable cstr in "eval_code_helper" is newly created anyways.
+  forbidden_var_names = {"__code__"};
+
+  switch (op)
+    case "save"
+      ## Clear previous context
+      ctext = containers.Map;
+      ## Get variable names
+      var_names = evalin ("caller", "whos");
+      var_names = {var_names.name};
+      ## Store all variables to context
+      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
+      endfor
+
+    case "load"
+      if (! isempty (ctext))
+        keys = ctext.keys ();
+        for i = 1:length (keys)
+          assignin ("caller", keys{i}, ctext(keys{i}));
+        endfor
+      endif
+
+    case "clear"
+      ## Clear any context
+      ctext = [];
+
+    otherwise
+      ## Do nothing
+
+  endswitch
+endfunction
+
+
+## Note: Functional BIST tests are located in the `test/publish` directory.
 
 ## Test input validation
 %!error publish ()
--- a/scripts/miscellaneous/run.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/run.m	Thu Dec 20 17:18:56 2018 -0500
@@ -59,7 +59,7 @@
   endif
 
   if (! isempty (d))
-    if (! exist (d, "dir"))
+    if (! isfolder (d))
       error ("run: the path %s doesn't exist", d);
     endif
 
--- a/scripts/miscellaneous/tempdir.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/tempdir.m	Thu Dec 20 17:18:56 2018 -0500
@@ -37,7 +37,7 @@
     dirname = [dirname filesep];
   endif
 
-  if (! isdir (dirname))
+  if (! isfolder (dirname))
     warning ("tempdir: '%s' does not exist or is not a directory", dirname);
   endif
 
--- a/scripts/miscellaneous/unpack.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/unpack.m	Thu Dec 20 17:18:56 2018 -0500
@@ -71,7 +71,7 @@
 
 ## Author: Bill Denney <denney@seas.upenn.edu>
 
-function filelist = unpack (file, dir = ".", filetype = "")
+function filelist = unpack (file, dir = [], filetype = "")
 
   if (nargin < 1 || nargin > 3)
     print_usage ();
@@ -86,8 +86,8 @@
     file = cellstr (file);
   endif
   if (numel (file) == 1)
+    ## FIXME: The code below is not a perfect test for a URL
     if (isempty (strfind (file{1}, "://")))
-      ## FIXME: The above code is not a perfect test for a URL
       gfile = glob (file);
       if (isempty (gfile))
         error ('unpack: FILE "%s" not found', file{1});
@@ -101,7 +101,11 @@
   if (numel (file) > 1)
     files = {};
     for i = 1:numel (file)
-      tmpfiles = unpack (file{i}, dir);
+      if (! isempty (dir))
+        tmpfiles = unpack (file{i}, dir);
+      else
+        tmpfiles = unpack (file{i}, fileparts (file{i}));
+      endif
       files = {files{:} tmpfiles{:}};
     endfor
 
@@ -115,16 +119,29 @@
     file = file{1};
   endif
 
-  if (isdir (file))
+  if (nargin == 3 && (! ischar (filetype) || ! isrow (filetype)))
+    error ("unpack: FILETYPE must be a string");
+  endif
+
+  if (isfolder (file))
     if (isempty (filetype))
       error ("unpack: FILETYPE must be given for a directory");
-    elseif (! any (strcmpi (filetype, "gunzip")))
-      error ('unpack: FILETYPE must be "gunzip" for a directory');
+    elseif (! strcmpi (filetype, "gz"))
+      error ('unpack: FILETYPE must be "gz" for a directory');
     endif
     ext = ".gz";
   else
     [pathstr, name, ext] = fileparts (file);
 
+    if (nargin == 3 && ! strcmpi (ext, filetype))
+      ## override extension with given filetype
+      if (isempty (ext))
+        ext = filetype;
+      else
+        ext = regexprep (ext, '(\.?)\S*$', ['$1' filetype]);
+      endif
+    endif
+
     ## Check to see if it's .tar.gz, .tar.Z, etc.
     if (any (strcmpi ({".gz" ".Z" ".bz2" ".bz"}, ext)))
       [~, tmpname, tmpext] = fileparts (name);
@@ -193,7 +210,7 @@
   endif
 
   ## Unzip doesn't actually care about the extension
-  if (strcmpi (filetype, "unzip"))
+  if (strcmpi (filetype, "zip"))
     nodotext = "zip";
   else
     nodotext = ext(ext != '.');
@@ -224,8 +241,8 @@
       command = commandq;
     endif
   else
-    warning ("unpack: unrecognized FILETYPE <%s>", ext);
-    files = file;
+    warning ("unpack: unrecognized FILETYPE <%s>", nodotext);
+    filelist = {};
     return;
   endif
 
@@ -366,13 +383,19 @@
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ("_%NOT_A_FILENAME%_")
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ({"_%NOT_A_FILENAME%_"})
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ({"_%NOT_A_FILENAME%_", "2nd_filename"})
+%!error <FILETYPE must be a string>
+%! if (isunix || ismac)
+%!   unpack ("/", [], 1)
+%! else
+%!   unpack ('C:\', [], 1)
+%! endif
 %!error <FILETYPE must be given for a directory>
 %! if (isunix || ismac)
 %!   unpack ("/");
 %! else
 %!   unpack ('C:\');
 %! endif
-%!error <FILETYPE must be "gunzip" for a directory>
+%!error <FILETYPE must be "gz" for a directory>
 %! if (isunix || ismac)
 %!   unpack ("/", [], "foobar");
 %! else
--- a/scripts/miscellaneous/untar.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/untar.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,6 +19,7 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} untar (@var{tarfile})
 ## @deftypefnx {} {} untar (@var{tarfile}, @var{dir})
+## @deftypefnx {} {@var{filelist} =} untar (@dots{})
 ## Unpack the TAR archive @var{tarfile}.
 ##
 ## If @var{dir} is specified the files are unpacked in this directory rather
@@ -42,9 +43,9 @@
   endif
 
   if (nargout > 0)
-    filelist = unpack (tarfile, dir, "untar");
+    filelist = unpack (tarfile, dir, "tar");
   else
-    unpack (tarfile, dir, "untar");
+    unpack (tarfile, dir, "tar");
   endif
 
 endfunction
--- a/scripts/miscellaneous/unzip.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/unzip.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,8 +17,9 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{filelist} =} unzip (@var{zipfile})
-## @deftypefnx {} {@var{filelist} =} unzip (@var{zipfile}, @var{dir})
+## @deftypefn  {} {} unzip (@var{zipfile})
+## @deftypefnx {} {} unzip (@var{zipfile}, @var{dir})
+## @deftypefnx {} {@var{filelist} =} unzip (@dots{})
 ## Unpack the ZIP archive @var{zipfile}.
 ##
 ## If @var{dir} is specified the files are unpacked in this directory rather
@@ -42,9 +43,9 @@
   endif
 
   if (nargout > 0)
-    filelist = unpack (zipfile, dir, "unzip");
+    filelist = unpack (zipfile, dir, "zip");
   else
-    unpack (zipfile, dir, "unzip");
+    unpack (zipfile, dir, "zip");
   endif
 
 endfunction
--- a/scripts/miscellaneous/what.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/miscellaneous/what.m	Thu Dec 20 17:18:56 2018 -0500
@@ -116,7 +116,7 @@
         w.oct{end+1} = n;
       elseif (strcmp (e, mexext ()))
         w.mex{end+1} = n;
-      elseif (n(1) == "@" && isdir (fullfile (dir, n)))
+      elseif (n(1) == "@" && isfolder (fullfile (dir, n)))
         w.classes{end+1} = n;
       endif
     endif
--- a/scripts/mk-doc.pl	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/mk-doc.pl	Thu Dec 20 17:18:56 2018 -0500
@@ -57,8 +57,15 @@
     }
   elsif ($paths[-2] =~ m/^\+/)
     {
-      ## +package functions have package.name their function name
-      $fcn = substr ($paths[-2], 1) . "." . $paths[-1];
+      $fcn = $paths[-1];
+      for (my $i = 2; $i < @paths; $i++)
+        {
+          if ($paths[-$i] =~ m/^\+/)
+            {
+              ## +package functions have package.name their function name
+              $fcn = substr ($paths[-$i], 1) . "." . $fcn;
+            }
+        }
     }
   else
     {
--- a/scripts/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -5,6 +5,7 @@
 %canon_reldir%_MAINTAINERCLEANFILES =
 
 include %reldir%/+containers/module.mk
+include %reldir%/+matlab/+lang/module.mk
 include %reldir%/audio/module.mk
 include %reldir%/deprecated/module.mk
 include %reldir%/elfun/module.mk
@@ -15,6 +16,7 @@
 include %reldir%/image/module.mk
 include %reldir%/io/module.mk
 include %reldir%/java/module.mk
+include %reldir%/legacy/module.mk
 include %reldir%/linear-algebra/module.mk
 include %reldir%/miscellaneous/module.mk
 include %reldir%/ode/module.mk
--- a/scripts/ode/decic.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/decic.m	Thu Dec 20 17:18:56 2018 -0500
@@ -95,7 +95,7 @@
   endif
 
   ## Validate inputs
-  if (! isa (fun, "function_handle"))
+  if (! is_function_handle (fun))
     error ("Octave:invalid-input-arg",
            "decic: FUN must be a valid function handle");
   endif
@@ -162,7 +162,7 @@
   endif
 
   x0 = [y0(! fixed_y0); yp0(! fixed_yp0)];
-  opt = optimset ("tolfun", TolFun, "tolx", TolX, "display", "iter-detailed");
+  opt = optimset ("tolfun", TolFun, "tolx", TolX, "FinDiffType", "central");
   x = ...
     fminunc (@(x) objective (x, t0, y0, fixed_y0, yp0, fixed_yp0, nl, nu, fun),
              x0, opt);
--- a/scripts/ode/ode15i.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/ode15i.m	Thu Dec 20 17:18:56 2018 -0500
@@ -115,7 +115,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.Jacobian, "function_handle"))
+      if (! is_function_handle (options.Jacobian))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'Jacobian'"]);
       endif
@@ -129,7 +129,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.OutputFcn, "function_handle"))
+      if (! is_function_handle (options.OutputFcn))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'OutputFcn'"]);
       endif
@@ -143,7 +143,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.Events, "function_handle")
+      if (! is_function_handle (options.Events)
           && ! ismatrix (options.Events))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'Events'"]);
@@ -194,7 +194,7 @@
                [solver ": invalid value assigned to field 'Jacobian'"]);
       endif
 
-    elseif (isa (options.Jacobian, "function_handle"))
+    elseif (is_function_handle (options.Jacobian))
       options.havejacfun = true;
       if (nargin (options.Jacobian) == 3)
         [A, B] = options.Jacobian (trange(1), y0, yp0);
--- a/scripts/ode/ode15s.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/ode15s.m	Thu Dec 20 17:18:56 2018 -0500
@@ -109,7 +109,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.Mass, "function_handle"))
+      if (! is_function_handle (options.Mass))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'Mass'"]);
       endif
@@ -123,7 +123,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.Jacobian, "function_handle"))
+      if (! is_function_handle (options.Jacobian))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'Jacobian'"]);
       endif
@@ -137,7 +137,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.OutputFcn, "function_handle"))
+      if (! is_function_handle (options.OutputFcn))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field '%s'"], "OutputFcn");
       endif
@@ -151,7 +151,7 @@
       catch
         warning (lasterr);
       end_try_catch
-      if (! isa (options.Events, "function_handle"))
+      if (! is_function_handle (options.Events))
         error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field 'Events'"]);
       endif
@@ -173,7 +173,7 @@
   options.havemasssparse = false;
 
   if (! isempty (options.Mass))
-    if (isa (options.Mass, "function_handle"))
+    if (is_function_handle (options.Mass))
       options.havemassfun = true;
       if (nargin (options.Mass) == 2)
         options.havestatedep = true;
@@ -215,7 +215,7 @@
 
   if (! isempty (options.Jacobian))
     options.havejac = true;
-    if (isa (options.Jacobian, "function_handle"))
+    if (is_function_handle (options.Jacobian))
       options.havejacfun = true;
       if (nargin (options.Jacobian) == 2)
         [A] = options.Jacobian (trange(1), y0);
--- a/scripts/ode/ode23.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/ode23.m	Thu Dec 20 17:18:56 2018 -0500
@@ -145,7 +145,7 @@
       warning (lasterr);
     end_try_catch
   endif
-  if (! isa (fun, "function_handle"))
+  if (! is_function_handle (fun))
     error ("Octave:invalid-input-arg",
            "ode23: FUN must be a valid function handle");
   endif
@@ -199,7 +199,7 @@
   if (! isempty (odeopts.Mass) && isnumeric (odeopts.Mass))
     havemasshandle = false;
     mass = odeopts.Mass;    # constant mass
-  elseif (isa (odeopts.Mass, "function_handle"))
+  elseif (is_function_handle (odeopts.Mass))
     havemasshandle = true;  # mass defined by a function handle
   else  # no mass matrix - creating a diag-matrix of ones for mass
     havemasshandle = false; # mass = diag (ones (length (init), 1), 0);
--- a/scripts/ode/ode45.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/ode45.m	Thu Dec 20 17:18:56 2018 -0500
@@ -142,7 +142,7 @@
       warning (lasterr);
     end_try_catch
   endif
-  if (! isa (fun, "function_handle"))
+  if (! is_function_handle (fun))
     error ("Octave:invalid-input-arg",
            "ode45: FUN must be a valid function handle");
   endif
@@ -199,7 +199,7 @@
   if (! isempty (odeopts.Mass) && isnumeric (odeopts.Mass))
     havemasshandle = false;
     mass = odeopts.Mass;  # constant mass
-  elseif (isa (odeopts.Mass, "function_handle"))
+  elseif (is_function_handle (odeopts.Mass))
     havemasshandle = true;    # mass defined by a function handle
   else  # no mass matrix - creating a diag-matrix of ones for mass
     havemasshandle = false;   # mass = diag (ones (length (init), 1), 0);
--- a/scripts/ode/private/check_default_input.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/private/check_default_input.m	Thu Dec 20 17:18:56 2018 -0500
@@ -33,7 +33,7 @@
       warning (lasterr);
     end_try_catch
   endif
-  if (! isa (fun, "function_handle"))
+  if (! is_function_handle (fun))
     error ("Octave:invalid-input-arg",
                [solver ": invalid value assigned to field '%s'"], "fun");
   endif
--- a/scripts/ode/private/odemergeopts.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/ode/private/odemergeopts.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,7 +19,7 @@
 function options = odemergeopts (caller, useroptions, options, classes,
                                  attributes);
 
-  for [value, key] = options;
+  for [value, key] = options
 
     if (isfield (useroptions, key) && ! isempty (useroptions.(key)))
 
--- a/scripts/optimization/__all_opts__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/__all_opts__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -18,14 +18,16 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{names} =} __all_opts__ (@dots{})
-## Undocumented internal function.
-## @end deftypefn
-
+## Internal function.
+##
 ## Query all options from all known optimization functions and return a
 ## list of possible values.
+## @end deftypefn
 
 function names = __all_opts__ (varargin)
 
+  ## This variable is filled by the auto-generated PKG_ADD script at
+  ## Octave startup.
   persistent saved_names = {};
 
   ## do not clear this function
@@ -39,7 +41,7 @@
   elseif (nargin == 0)
     names = saved_names;
   else
-    ## query all options from all known functions.  These will call optimset,
+    ## Query all options from all known functions.  These may call optimset,
     ## which will in turn call us, but we won't answer.
     recursive = true;
     names = saved_names;
--- a/scripts/optimization/fminbnd.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/fminbnd.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,37 +19,58 @@
 ## Author: Jaroslav Hajek <highegg@gmail.com>
 
 ## -*- texinfo -*-
-## @deftypefn {} {[@var{x}, @var{fval}, @var{info}, @var{output}] =} fminbnd (@var{fun}, @var{a}, @var{b}, @var{options})
+## @deftypefn  {} {@var{x} =} fminbnd (@var{fun}, @var{a}, @var{b})
+## @deftypefnx {} {@var{x} =} fminbnd (@var{fun}, @var{a}, @var{b}, @var{options})
+## @deftypefnx {} {[@var{x}, @var{fval}, @var{info}, @var{output}] =} fminbnd (@dots{})
 ## Find a minimum point of a univariate function.
 ##
-## @var{fun} should be a function handle or name.  @var{a}, @var{b} specify a
-## starting interval.  @var{options} is a structure specifying additional
-## options.  Currently, @code{fminbnd} recognizes these options:
-## @qcode{"FunValCheck"}, @qcode{"OutputFcn"}, @qcode{"TolX"},
-## @qcode{"MaxIter"}, @qcode{"MaxFunEvals"}.  For a description of these
-## options, see @ref{XREFoptimset,,optimset}.
+## @var{fun} must be a function handle or name.
+##
+## The starting interval is specified by @var{a} (left boundary) and @var{b}
+## (right boundary).  The endpoints must be finite.
+##
+## @var{options} is a structure specifying additional parameters which
+## control the algorithm.  Currently, @code{fminbnd} recognizes these options:
+## @qcode{"Display"}, @qcode{"FunValCheck"}, @qcode{"MaxFunEvals"},
+## @qcode{"MaxIter"}, @qcode{"OutputFcn"}, @qcode{"TolX"}.
+##
+## @qcode{"MaxFunEvals"} proscribes the maximum number of function evaluations
+## before optimization is halted.  The default value is 500.
+## The value must be a positive integer.
 ##
-## On exit, the function returns @var{x}, the approximate minimum point and
-## @var{fval}, the function value thereof.
+## @qcode{"MaxIter"} proscribes the maximum number of algorithm iterations
+## before optimization is halted.  The default value is 500.
+## The value must be a positive integer.
+##
+## @qcode{"TolX"} specifies the termination tolerance for the solution @var{x}.
+## The default is @code{1e-4}.
 ##
-## @var{info} is an exit flag that can have these values:
+## For a description of the other options, see @ref{XREFoptimset,,optimset}.
+## To initialize an options structure with default values for @code{fminbnd}
+## use @code{options = optimset ("fminbnd")}.
+##
+## On exit, the function returns @var{x}, the approximate minimum point, and
+## @var{fval}, the function evaluated @var{x}.
+##
+## The third output @var{info} reports whether the algorithm succeeded and may
+## take one of the following values:
 ##
 ## @itemize
 ## @item 1
 ## The algorithm converged to a solution.
 ##
 ## @item 0
-## Maximum number of iterations or function evaluations has been exhausted.
+## Iteration limit (either @code{MaxIter} or @code{MaxFunEvals}) exceeded.
 ##
 ## @item -1
-## The algorithm has been terminated from user output function.
+## The algorithm was terminated by a user @code{OutputFcn}.
 ## @end itemize
 ##
-## Notes: The search for a minimum is restricted to be in the interval bound by
-## @var{a} and @var{b}.  If you only have an initial point to begin searching
-## from you will need to use an unconstrained minimization algorithm such as
-## @code{fminunc} or @code{fminsearch}.  @code{fminbnd} internally uses a
-## Golden Section search strategy.
+## Programming Notes: The search for a minimum is restricted to be in the
+## finite interval bound by @var{a} and @var{b}.  If you have only one initial
+## point to begin searching from then you will need to use an unconstrained
+## minimization algorithm such as @code{fminunc} or @code{fminsearch}.
+## @code{fminbnd} internally uses a Golden Section search strategy.
 ## @seealso{fzero, fminunc, fminsearch, optimset}
 ## @end deftypefn
 
@@ -63,9 +84,10 @@
 function [x, fval, info, output] = fminbnd (fun, a, b, options = struct ())
 
   ## Get default options if requested.
-  if (nargin == 1 && ischar (fun) && strcmp (fun, 'defaults'))
-    x = optimset ("MaxIter", Inf, "MaxFunEvals", Inf, "TolX", 1e-8,
-                  "OutputFcn", [], "FunValCheck", "off");
+  if (nargin == 1 && ischar (fun) && strcmp (fun, "defaults"))
+    x = struct ("Display", "notify", "FunValCheck", "off",
+                "MaxFunEvals", 500, "MaxIter", 500,
+                "OutputFcn", [], "TolX", 1e-4);
     return;
   endif
 
@@ -79,15 +101,15 @@
   endif
 
   if (ischar (fun))
-    fun = str2func (fun, "global");
+    fun = str2func (fun);
   endif
 
   displ = optimget (options, "Display", "notify");
   funvalchk = strcmpi (optimget (options, "FunValCheck", "off"), "on");
   outfcn = optimget (options, "OutputFcn");
-  tolx = optimget (options, "TolX", 1e-8);
-  maxiter = optimget (options, "MaxIter", Inf);
-  maxfev = optimget (options, "MaxFunEvals", Inf);
+  tolx = optimget (options, "TolX", 1e-4);
+  maxiter = optimget (options, "MaxIter", 500);
+  maxfev = optimget (options, "MaxFunEvals", 500);
 
   if (funvalchk)
     ## Replace fun with a guarded version.
@@ -160,9 +182,8 @@
     if (dogs)
       ## Default to golden section step.
 
-      ## WARNING: This is also the "initial" procedure following
-      ## MATLAB nomenclature.  After the loop we'll fix the string
-      ## for the first step.
+      ## WARNING: This is also the "initial" procedure following MATLAB
+      ## nomenclature.  After the loop we'll fix the string for the first step.
       iter(niter+1).procedure = "golden";
 
       e = ifelse (x >= xm, a - x, b - x);
@@ -225,13 +246,13 @@
   switch (displ)
     case "iter"
       print_formatted_table (iter);
-      print_exit_msg (info, struct("TolX", tolx, "fx", fval));
+      print_exit_msg (info, struct ("TolX", tolx, "fx", fval));
     case "notify"
       if (info == 0)
-        print_exit_msg (info, struct("fx",fval));
+        print_exit_msg (info, struct ("fx",fval));
       endif
     case "final"
-      print_exit_msg (info, struct("TolX", tolx, "fx", fval));
+      print_exit_msg (info, struct ("TolX", tolx, "fx", fval));
     case "off"
       "skip";
     otherwise
@@ -240,6 +261,7 @@
 
   output.iterations = niter;
   output.funcCount = nfev;
+  output.algorithm = "golden section search, parabolic interpolation";
   output.bracket = [a, b];
   ## FIXME: bracketf possibly unavailable.
 
--- a/scripts/optimization/fminsearch.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/fminsearch.m	Thu Dec 20 17:18:56 2018 -0500
@@ -21,9 +21,11 @@
 ## @deftypefn  {} {@var{x} =} fminsearch (@var{fun}, @var{x0})
 ## @deftypefnx {} {@var{x} =} fminsearch (@var{fun}, @var{x0}, @var{options})
 ## @deftypefnx {} {@var{x} =} fminsearch (@var{fun}, @var{x0}, @var{options}, @var{fun_arg1}, @var{fun_arg2}, @dots{})
+## @deftypefnx {} {@var{x} =} fminsearch (@var{problem})
 ## @deftypefnx {} {[@var{x}, @var{fval}, @var{exitflag}, @var{output}] =} fminsearch (@dots{})
 ##
-## Find a value of @var{x} which minimizes the function @var{fun}.
+## Find a value of @var{x} which minimizes the multi-variable function
+## @var{fun}.
 ##
 ## The search begins at the point @var{x0} and iterates using the
 ## @nospell{Nelder & Mead} Simplex algorithm (a derivative-free method).  This
@@ -32,25 +34,59 @@
 ##
 ## Options for the search are provided in the parameter @var{options} using the
 ## function @code{optimset}.  Currently, @code{fminsearch} accepts the options:
-## @qcode{"TolX"}, @qcode{"TolFun"}, @qcode{"MaxFunEvals"}, @qcode{"MaxIter"},
-## @qcode{"Display"}, @qcode{"FunValCheck"}, and @qcode{"OutputFcn"}.
-## For a description of these options, see @code{optimset}.
+## @qcode{"Display"}, @qcode{"FunValCheck"},@qcode{"MaxFunEvals"},
+## @qcode{"MaxIter"}, @qcode{"OutputFcn"}, @qcode{"TolFun"}, @qcode{"TolX"}.
+##
+## @qcode{"MaxFunEvals"} proscribes the maximum number of function evaluations
+## before optimization is halted.  The default value is
+## @code{200 * number_of_variables}, i.e., @code{200 * length (@var{x0})}.
+## The value must be a positive integer.
+##
+## @qcode{"MaxIter"} proscribes the maximum number of algorithm iterations
+## before optimization is halted.  The default value is
+## @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
+## @code{options = optimset ("fminsearch")}.
 ##
 ## Additional inputs for the function @var{fun} can be passed as the fourth
 ## and higher arguments.  To pass function arguments while using the default
 ## @var{options} values, use @code{[]} for @var{options}.
 ##
+## @code{fminsearch} may also be called with a single structure argument
+## with the following fields:
+##
+## @table @code
+## @item objective
+## The objective function.
+##
+## @item x0
+## The initial point.
+##
+## @item solver
+## Must be set to @qcode{"fminsearch"}.
+##
+## @item options
+## A structure returned from @code{optimset} or an empty matrix to
+## indicate that defaults should be used.
+## @end table
+##
+## @noindent
+## The field @code{options} is optional.  All others are required.
+##
 ## On exit, the function returns @var{x}, the minimum point, and @var{fval},
 ## the function value at the minimum.
 ##
-## The third return value @var{exitflag} is
+## The third output @var{exitflag} reports whether the algorithm succeeded and
+## may take one of the following values:
 ##
 ## @table @asis
 ## @item 1
 ## if the algorithm converged
-## (size of the simplex is smaller than @code{@var{options}.TolX} @strong{AND}
-## the step in the function value between iterations is smaller than
-## @code{@var{options}.TolFun}).
+## (size of the simplex is smaller than @code{TolX} @strong{AND} the step in
+## function value between iterations is smaller than @code{TolFun}).
 ##
 ## @item 0
 ## if the maximum number of iterations or the maximum number of function
@@ -60,10 +96,11 @@
 ## if the iteration is stopped by the @qcode{"OutputFcn"}.
 ## @end table
 ##
-## The fourth return value is a structure @var{output} with the fields,
-## @code{funcCount} containing the number of function calls to @var{fun},
-## @code{iterations} containing the number of iteration steps,
-## @code{algorithm} with the name of the search algorithm (always:
+## The fourth output is a structure @var{output} containing runtime
+## about the algorithm.  Fields in the structure are @code{funcCount}
+## containing the number of function calls to @var{fun}, @code{iterations}
+## containing the number of iteration steps, @code{algorithm} with the name of
+## the search algorithm (always:
 ## @nospell{@qcode{"Nelder-Mead simplex direct search"}}), and @code{message}
 ## with the exit message.
 ##
@@ -72,6 +109,9 @@
 ## @example
 ## fminsearch (@@(x) (x(1)-5).^2+(x(2)-8).^4, [0;0])
 ## @end example
+##
+## Note: If you need to find the minimum of a single variable function it is
+## probably better to use @code{fminbnd}.
 ## @seealso{fminbnd, fminunc, optimset}
 ## @end deftypefn
 
@@ -80,22 +120,50 @@
 
 ## FIXME: Add support for output function with "state" set to "interrupt".
 
-function [x, fval, exitflag, output] = fminsearch (fun, x0, options, varargin)
+function [x, fval, exitflag, output] = fminsearch (varargin)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
 
   ## Get default options if requested.
-  if (nargin == 1 && ischar (fun) && strcmp (fun, "defaults"))
-    x = optimset ("Display", "notify", "FunValCheck", "off",
-                  "MaxFunEvals", 400, "MaxIter", 400,
-                  "OutputFcn", [],
-                  "TolFun", 1e-7, "TolX", 1e-4);
+  if (nargin == 1 && ischar (varargin{1}) && strcmp (varargin{1}, "defaults"))
+    x = struct ("Display", "notify", "FunValCheck", "off",
+                "MaxFunEvals", [], "MaxIter", [],
+                "OutputFcn", [],
+                "TolFun", 1e-4, "TolX", 1e-4);
     return;
   endif
 
-  if (nargin < 2)
-    print_usage ();
+  if (nargin == 1)
+    problem = varargin{1};
+    varargin = {};
+    if (! isstruct (problem))
+      error ("fminsearch: PROBLEM must be a structure");
+    endif
+    fun = problem.objective;
+    x0 = problem.x0;
+    if (! strcmp (problem.solver, "fminsearch"))
+      error ('fminsearch: problem.solver must be set to "fminsearch"');
+    endif
+    if (isfield (problem, "options"))
+      options = problem.options;
+    else
+      options = [];
+    endif
+  elseif (nargin > 1)
+    fun = varargin{1};
+    x0 = varargin{2};
+    if (nargin > 2)
+      options = varargin{3};
+      varargin(1:3) = [];
+    else
+      options = [];
+      varargin = {};
+    endif
   endif
 
-  if (nargin < 3 || isempty (options))
+  if (isempty (options))
     options = struct ();
   endif
 
@@ -154,13 +222,13 @@
   stopit(1) = tol = optimget (options, "TolX", 1e-4);
 
   ## Tolerance for cgce test based on step in function value.
-  tol_f = optimget (options, "TolFun", 1e-7);
+  tol_f = optimget (options, "TolFun", 1e-4);
 
   ## Max number of function evaluations.
-  stopit(2) = optimget (options, "MaxFunEvals", length (x) * 200);
+  stopit(2) = optimget (options, "MaxFunEvals", 200 * length (x));
 
   ## Max number of iterations
-  maxiter = optimget (options, "MaxIter", length (x) * 200);
+  maxiter = optimget (options, "MaxIter", 200 * length (x));
 
   ## Default target for function values.
   stopit(3) = Inf;  # FIXME: expose this parameter to the outside
@@ -209,7 +277,7 @@
   V = [zeros(n,1) eye(n)];
   f = zeros (n+1,1);
   V(:,1) = x0;
-  f(1) = dirn * feval (fun, x, varargin{:});
+  f(1) = dirn * fun (x, varargin{:});
   fmax_old = f(1);
   nf = 1;
 
@@ -269,7 +337,7 @@
     k += 1;
 
     if (k > maxiter)
-      msg = "Exceeded maximum iterations...quitting\n";
+      msg = "Exceeded maximum iterations\n";
       break;
     endif
 
@@ -293,14 +361,15 @@
     ## Stopping Test 1 - f reached target value?
     if (fmax >= stopit(3))
       msg = "Exceeded target...quitting\n";
-      ## FIXME: Add docu when stopit(3) gets exposed to the outside
+      ## FIXME: Add documentation when stopit(3) gets exposed to the outside
       exitflag = -1;
       break;
     endif
 
     ## Stopping Test 2 - too many f-evals?
     if (nf >= stopit(2))
-      msg = "Max no. of function evaluations exceeded...quitting\n";
+      msg = "Exceeded maximum number of function evaluations\n";
+      exitflag = 0;
       break;
     endif
 
@@ -309,8 +378,8 @@
     size_simplex = norm (V(:,2:n+1)-v1(:,ones (1,n)),1) / max (1, norm (v1,1));
     step_f = max (abs (f(1) - f(2:n+1)));
     if (size_simplex <= tol && step_f <= tol_f )
-      msg = sprintf (["Simplex size %9.4e <= %9.4e and ", ...
-                      "step in function value %9.4e <= %9.4e...quitting\n"], ...
+      msg = sprintf (["Algorithm converged.  Simplex size %9.4e <= %9.4e ", ...
+                      "and step in function value %9.4e <= %9.4e\n"], ...
                       size_simplex, tol, step_f, tol_f);
       exitflag = 1;
       break;
@@ -453,6 +522,17 @@
 %! assert (x, 4.7109, 1e-4);
 
 %!test
+%! problem.objective = @sin;
+%! problem.x0 = 3;
+%! problem.solver = "fminsearch";
+%! problem.options = optimset ("MaxIter", 3, "Display", "none");
+%! x = fminsearch (problem);
+%! assert (x, 4.8750, 1e-4);
+%! problem.options = optimset ("MaxFunEvals", 18, "Display", "none");
+%! x = fminsearch (problem);
+%! assert (x, 4.7109, 1e-4);
+
+%!test
 %! c = 1.5;
 %! assert (fminsearch (@(x) x(1).^2 + c*x(2).^2, [1;1]), [0;0], 1e-4);
 
@@ -490,4 +570,3 @@
 ## Test input validation
 %!error fminsearch ()
 %!error fminsearch (1)
-
--- a/scripts/optimization/fminunc.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/fminunc.m	Thu Dec 20 17:18:56 2018 -0500
@@ -33,19 +33,34 @@
 ## @var{x0} determines a starting guess.  The shape of @var{x0} is preserved in
 ## all calls to @var{fcn}, but otherwise is treated as a column vector.
 ##
-## @var{options} is a structure specifying additional options.  Currently,
-## @code{fminunc} recognizes these options:
-## @qcode{"FunValCheck"}, @qcode{"OutputFcn"}, @qcode{"TolX"},
-## @qcode{"TolFun"}, @qcode{"MaxIter"}, @qcode{"MaxFunEvals"},
-## @qcode{"GradObj"}, @qcode{"FinDiffType"}, @qcode{"TypicalX"},
-## @qcode{"AutoScaling"}.
+## @var{options} is a structure specifying additional parameters which
+## control the algorithm.  Currently, @code{fminunc} recognizes these options:
+## @qcode{"AutoScaling"}, @qcode{"FinDiffType"}, @qcode{"FunValCheck"},
+## @qcode{"GradObj"}, @qcode{"MaxFunEvals"}, @qcode{"MaxIter"},
+## @qcode{"OutputFcn"}, @qcode{"TolFun"}, @qcode{"TolX"}, @qcode{"TypicalX"}.
+##
+## If @qcode{"AutoScaling"} is @qcode{"on"}, the variables will be
+## automatically scaled according to the column norms of the (estimated)
+## Jacobian.  As a result, @qcode{"TolFun"} becomes scaling-independent.  By
+## default, this option is @qcode{"off"} because it may sometimes deliver
+## unexpected (though mathematically correct) results.
 ##
-## If @qcode{"GradObj"} is @qcode{"on"}, it specifies that @var{fcn}, when
-## called with two output arguments, also returns the Jacobian matrix of
-## partial first derivatives at the requested point.  @code{TolX} specifies
-## the termination tolerance for the unknown variables @var{x}, while
-## @code{TolFun} is a tolerance for the objective function value @var{fval}.
-##  The default is @code{1e-7} for both options.
+## If @qcode{"GradObj"} is @qcode{"on"}, it specifies that @var{fcn}--when
+## called with two output arguments---also returns the Jacobian matrix of
+## partial first derivatives at the requested point.
+##
+## @qcode{"MaxFunEvals"} proscribes the maximum number of function evaluations
+## before optimization is halted.  The default value is
+## @code{100 * number_of_variables}, i.e., @code{100 * length (@var{x0})}.
+## The value must be a positive integer.
+##
+## @qcode{"MaxIter"} proscribes the maximum number of algorithm iterations
+## before optimization is halted.  The default value is 400.
+## The value must be a positive integer.
+##
+## @qcode{"TolX"} specifies the termination tolerance for the unknown variables
+## @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}.
 ##
@@ -98,11 +113,10 @@
 
   ## Get default options if requested.
   if (nargin == 1 && strcmp (fcn, "defaults"))
-    x = optimset ("MaxIter", 400, "MaxFunEvals", Inf,
-                  "GradObj", "off", "TolX", 1e-7, "TolFun", 1e-7,
-                  "OutputFcn", [], "FunValCheck", "off",
-                  "FinDiffType", "central",
-                  "TypicalX", [], "AutoScaling", "off");
+    x = struct ("AutoScaling", "off", "FunValCheck", "off",
+                "FinDiffType", "forward", "GradObj", "off",
+                "MaxFunEvals", [], "MaxIter", 400, "OutputFcn", [],
+                "TolFun", 1e-6, "TolX", 1e-6, "TypicalX", []);
     return;
   endif
 
@@ -111,16 +125,16 @@
   endif
 
   if (ischar (fcn))
-    fcn = str2func (fcn, "global");
+    fcn = str2func (fcn);
   endif
 
   xsz = size (x0);
   n = numel (x0);
 
   has_grad = strcmpi (optimget (options, "GradObj", "off"), "on");
-  cdif = strcmpi (optimget (options, "FinDiffType", "central"), "central");
+  cdif = strcmpi (optimget (options, "FinDiffType", "forward"), "central");
   maxiter = optimget (options, "MaxIter", 400);
-  maxfev = optimget (options, "MaxFunEvals", Inf);
+  maxfev = optimget (options, "MaxFunEvals", 100*n);
   outfcn = optimget (options, "OutputFcn");
 
   ## Get scaling matrix using the TypicalX option.  If set to "auto", the
@@ -425,7 +439,7 @@
 %! assert (fval, 0, tol);
 
 ## Test FunValCheck works correctly
-%!assert (fminunc (@(x) x^2, 1, optimset ("FunValCheck", "on")), 0, eps)
+%!assert (fminunc (@(x) x^2, 1, optimset ("FunValCheck", "on")), 0, 1e-6)
 %!error <non-real value> fminunc (@(x) x + i, 1, optimset ("FunValCheck", "on"))
 %!error <NaN value> fminunc (@(x) x + NaN, 1, optimset ("FunValCheck", "on"))
 %!error <Inf value> fminunc (@(x) x + Inf, 1, optimset ("FunValCheck", "on"))
--- a/scripts/optimization/fsolve.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/fsolve.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,8 +19,9 @@
 ## Author: Jaroslav Hajek <highegg@gmail.com>
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} fsolve (@var{fcn}, @var{x0}, @var{options})
-## @deftypefnx {} {[@var{x}, @var{fvec}, @var{info}, @var{output}, @var{fjac}] =} fsolve (@var{fcn}, @dots{})
+## @deftypefn  {} {} fsolve (@var{fcn}, @var{x0})
+## @deftypefnx {} {} fsolve (@var{fcn}, @var{x0}, @var{options})
+## @deftypefnx {} {[@var{x}, @var{fval}, @var{info}, @var{output}, @var{fjac}] =} fsolve (@dots{})
 ## Solve a system of nonlinear equations defined by the function @var{fcn}.
 ##
 ## @var{fcn} should accept a vector (array) defining the unknown variables,
@@ -29,65 +30,98 @@
 ## determine a vector @var{x} such that @code{@var{fcn} (@var{x})} gives
 ## (approximately) all zeros.
 ##
-## @var{x0} determines a starting guess.  The shape of @var{x0} is preserved
-## in all calls to @var{fcn}, but otherwise it is treated as a column vector.
-##
-## @var{options} is a structure specifying additional options.  Currently,
-## @code{fsolve} recognizes these options:
-## @qcode{"FunValCheck"}, @qcode{"OutputFcn"}, @qcode{"TolX"},
-## @qcode{"TolFun"}, @qcode{"MaxIter"}, @qcode{"MaxFunEvals"},
-## @qcode{"Jacobian"}, @qcode{"Updating"}, @qcode{"ComplexEqn"}
-## @qcode{"TypicalX"}, @qcode{"AutoScaling"} and @qcode{"FinDiffType"}.
+## @var{x0} is an initial guess for the solution.  The shape of @var{x0} is
+## preserved in all calls to @var{fcn}, but otherwise is treated as a column
+## vector.
 ##
-## If @qcode{"Jacobian"} is @qcode{"on"}, it specifies that @var{fcn}, called
-## with 2 output arguments also returns the Jacobian matrix of right-hand sides
-## at the requested point.  @qcode{"TolX"} specifies the termination tolerance
-## in the unknown variables, while @qcode{"TolFun"} is a tolerance for
-## equations.  Default is @code{1e-7} for both @qcode{"TolX"} and
-## @qcode{"TolFun"}.
+## @var{options} is a structure specifying additional parameters which
+## control the algorithm.  Currently, @code{fsolve} recognizes these options:
+## @qcode{"AutoScaling"}, @qcode{"ComplexEqn"}, @qcode{"FinDiffType"},
+## @qcode{"FunValCheck"}, @qcode{"Jacobian"}, @qcode{"MaxFunEvals"},
+## @qcode{"MaxIter"}, @qcode{"OutputFcn"}, @qcode{"TolFun"}, @qcode{"TolX"},
+## @qcode{"TypicalX"}, and @qcode{"Updating"}.
 ##
-## If @qcode{"AutoScaling"} is on, the variables will be automatically scaled
-## according to the column norms of the (estimated) Jacobian.  As a result,
-## TolF becomes scaling-independent.  By default, this option is off because
-## it may sometimes deliver unexpected (though mathematically correct) results.
+## If @qcode{"AutoScaling"} is @qcode{"on"}, the variables will be
+## automatically scaled according to the column norms of the (estimated)
+## Jacobian.  As a result, @qcode{"TolFun"} becomes scaling-independent.  By
+## default, this option is @qcode{"off"} because it may sometimes deliver
+## unexpected (though mathematically correct) results.
 ##
-## If @qcode{"Updating"} is @qcode{"on"}, the function will attempt to use
-## @nospell{Broyden} updates to update the Jacobian, in order to reduce the
-## amount of Jacobian calculations.  If your user function always calculates
-## the Jacobian (regardless of number of output arguments) then this option
-## provides no advantage and should be set to false.
-##
-## @qcode{"ComplexEqn"} is @qcode{"on"}, @code{fsolve} will attempt to solve
+## If @qcode{"ComplexEqn"} is @qcode{"on"}, @code{fsolve} will attempt to solve
 ## complex equations in complex variables, assuming that the equations possess
 ## a complex derivative (i.e., are holomorphic).  If this is not what you want,
 ## you should unpack the real and imaginary parts of the system to get a real
 ## system.
 ##
-## For description of the other options, see @code{optimset}.
+## If @qcode{"Jacobian"} is @qcode{"on"}, it specifies that @var{fcn}---when
+## called with 2 output arguments---also returns the Jacobian matrix of
+## right-hand sides at the requested point.
+##
+## @qcode{"MaxFunEvals"} proscribes the maximum number of function evaluations
+## before optimization is halted.  The default value is
+## @code{100 * number_of_variables}, i.e., @code{100 * length (@var{x0})}.
+## The value must be a positive integer.
+##
+## If @qcode{"Updating"} is @qcode{"on"}, the function will attempt to use
+## @nospell{Broyden} updates to update the Jacobian, in order to reduce the
+## number of Jacobian calculations.  If your user function always calculates
+## the Jacobian (regardless of number of output arguments) then this option
+## provides no advantage and should be disabled.
 ##
-## On return, @var{fval} contains the value of the function @var{fcn}
-## evaluated at @var{x}.
+## @qcode{"TolX"} specifies the termination tolerance in the unknown variables,
+## while @qcode{"TolFun"} is a tolerance for equations.  Default is @code{1e-6}
+## for both @qcode{"TolX"} and @qcode{"TolFun"}.
 ##
-## @var{info} may be one of the following values:
+## For a description of the other options, see @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}
+## contains the value of the function @var{fcn} evaluated at @var{x} (ideally
+## a vector of all zeros).
+##
+## The third output @var{info} reports whether the algorithm succeeded and may
+## take one of the following values:
 ##
 ## @table @asis
 ## @item 1
 ## Converged to a solution point.  Relative residual error is less than
-## specified by TolFun.
+## specified by @code{TolFun}.
 ##
 ## @item 2
-## Last relative step size was less that TolX.
+## Last relative step size was less than @code{TolX}.
 ##
 ## @item 3
-## Last relative decrease in residual was less than TolF.
+## Last relative decrease in residual was less than @code{TolFun}.
 ##
 ## @item 0
-## Iteration limit exceeded.
+## Iteration limit (either @code{MaxIter} or @code{MaxFunEvals}) exceeded.
+##
+## @item -1
+## Stopped by @code{OutputFcn}.
 ##
 ## @item -3
 ## The trust region radius became excessively small.
 ## @end table
 ##
+## @var{output} is a structure containing runtime information about the
+## @code{fsolve} algorithm.  Fields in the structure are:
+##
+## @table @code
+## @item iterations
+##  Number of iterations through loop.
+##
+## @item successful
+##  Number of successful iterations.
+##
+## @item @nospell{funcCount}
+##  Number of function evaluations.
+##
+## @end table
+##
+## The final output @var{fjac} contains the value of the Jacobian evaluated
+## at @var{x}.
+##
 ## Note: If you only have a single nonlinear equation of one variable, using
 ## @code{fzero} is usually a much better idea.
 ##
@@ -97,21 +131,21 @@
 ## accepted successful step.  Often this will be one of the last two calls, but
 ## not always.  If the savings by reusing intermediate results from residual
 ## calculation in Jacobian calculation are significant, the best strategy is to
-## employ OutputFcn: After a vector is evaluated for residuals, if OutputFcn is
-## called with that vector, then the intermediate results should be saved for
-## future Jacobian evaluation, and should be kept until a Jacobian evaluation
-## is requested or until OutputFcn is called with a different vector, in which
-## case they should be dropped in favor of this most recent vector.  A short
-## example how this can be achieved follows:
+## employ @code{OutputFcn}: After a vector is evaluated for residuals, if
+## @code{OutputFcn} is called with that vector, then the intermediate results
+## should be saved for future Jacobian evaluation, and should be kept until a
+## Jacobian evaluation is requested or until @code{OutputFcn} is called with a
+## different vector, in which case they should be dropped in favor of this most
+## recent vector.  A short example how this can be achieved follows:
 ##
 ## @example
-## function [fvec, fjac] = user_func (x, optimvalues, state)
+## function [fval, fjac] = user_func (x, optimvalues, state)
 ## persistent sav = [], sav0 = [];
 ## if (nargin == 1)
 ##   ## evaluation call
 ##   if (nargout == 1)
 ##     sav0.x = x; # mark saved vector
-##     ## calculate fvec, save results to sav0.
+##     ## calculate fval, save results to sav0.
 ##   elseif (nargout == 2)
 ##     ## calculate fjac using sav.
 ##   endif
@@ -134,15 +168,15 @@
 ## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup.
 ## PKG_ADD: [~] = __all_opts__ ("fsolve");
 
-function [x, fvec, info, output, fjac] = fsolve (fcn, x0, options = struct ())
+function [x, fval, info, output, fjac] = fsolve (fcn, x0, options = struct ())
 
   ## Get default options if requested.
-  if (nargin == 1 && ischar (fcn) && strcmp (fcn, 'defaults'))
-    x = optimset ("MaxIter", 400, "MaxFunEvals", Inf, ...
-    "Jacobian", "off", "TolX", 1e-7, "TolFun", 1e-7,
-    "OutputFcn", [], "Updating", "on", "FunValCheck", "off",
-    "ComplexEqn", "off", "FinDiffType", "central",
-    "TypicalX", [], "AutoScaling", "off");
+  if (nargin == 1 && ischar (fcn) && strcmp (fcn, "defaults"))
+    x = struct ("AutoScaling", "off", "ComplexEqn", "off",
+                "FunValCheck", "off", "FinDiffType", "forward",
+                "Jacobian", "off",  "MaxFunEvals", [], "MaxIter", 400,
+                "OutputFcn", [], "Updating", "off", "TolFun", 1e-6,
+                "TolX", 1e-6, "TypicalX", []);
     return;
   endif
 
@@ -151,7 +185,7 @@
   endif
 
   if (ischar (fcn))
-    fcn = str2func (fcn, "global");
+    fcn = str2func (fcn);
   elseif (iscell (fcn))
     fcn = @(x) make_fcn_jac (x, fcn{1}, fcn{2});
   endif
@@ -160,19 +194,17 @@
   n = numel (x0);
 
   has_jac = strcmpi (optimget (options, "Jacobian", "off"), "on");
-  cdif = strcmpi (optimget (options, "FinDiffType", "central"), "central");
+  cdif = strcmpi (optimget (options, "FinDiffType", "forward"), "central");
   maxiter = optimget (options, "MaxIter", 400);
-  maxfev = optimget (options, "MaxFunEvals", Inf);
+  maxfev = optimget (options, "MaxFunEvals", 100*n);
   outfcn = optimget (options, "OutputFcn");
-  updating = strcmpi (optimget (options, "Updating", "on"), "on");
+  updating = strcmpi (optimget (options, "Updating", "off"), "on");
   complexeqn = strcmpi (optimget (options, "ComplexEqn", "off"), "on");
 
   ## Get scaling matrix using the TypicalX option.  If set to "auto", the
   ## scaling matrix is estimated using the Jacobian.
-  typicalx = optimget (options, "TypicalX");
-  if (isempty (typicalx))
-    typicalx = ones (n, 1);
-  endif
+  typicalx = optimget (options, "TypicalX", ones (n, 1));
+
   autoscale = strcmpi (optimget (options, "AutoScaling", "off"), "on");
   if (! autoscale)
     dg = 1 ./ typicalx;
@@ -188,8 +220,8 @@
   ## These defaults are rather stringent.
   ## Normally user prefers accuracy to performance.
 
-  tolx = optimget (options, "TolX", 1e-7);
-  tolf = optimget (options, "TolFun", 1e-7);
+  tolx = optimget (options, "TolX", 1e-6);
+  tolf = optimget (options, "TolFun", 1e-6);
 
   factor = 1;
 
@@ -201,11 +233,11 @@
 
   ## Initial evaluation.
   ## Handle arbitrary shapes of x and f and remember them.
-  fvec = fcn (reshape (x, xsiz));
-  fsiz = size (fvec);
-  fvec = fvec(:);
-  fn = norm (fvec);
-  m = length (fvec);
+  fval = fcn (reshape (x, xsiz));
+  fsiz = size (fval);
+  fval = fval(:);
+  fn = norm (fval);
+  m = length (fval);
   n = length (x);
 
   if (! isempty (outfcn))
@@ -213,7 +245,7 @@
     optimvalues.funccount = nfev;
     optimvalues.fval = fn;
     optimvalues.searchdirection = zeros (n, 1);
-    state = 'init';
+    state = "init";
     stop = outfcn (x, optimvalues, state);
     if (stop)
       info = -1;
@@ -221,7 +253,7 @@
     endif
   endif
 
-  if (isa (x0, "single") || isa (fvec, "single"))
+  if (isa (x0, "single") || isa (fval, "single"))
     macheps = eps ("single");
   else
     macheps = eps ("double");
@@ -234,7 +266,7 @@
 
     ## Calculate function value and Jacobian (possibly via FD).
     if (has_jac)
-      [fvec, fjac] = fcn (reshape (x, xsiz));
+      [fval, fjac] = fcn (reshape (x, xsiz));
       if (! all (size (fjac) == [m, n]))
         error ("fsolve: Jacobian size should be (%d,%d), not (%d,%d)",
                m, n, rows (fjac), columns (fjac));
@@ -243,16 +275,16 @@
       if (issparse (fjac))
         updating = false;
       endif
-      fvec = fvec(:);
+      fval = fval(:);
       nfev += 1;
     else
-      fjac = __fdjac__ (fcn, reshape (x, xsiz), fvec, typicalx, cdif);
+      fjac = __fdjac__ (fcn, reshape (x, xsiz), fval, typicalx, cdif);
       nfev += (1 + cdif) * length (x);
     endif
 
-    ## For square and overdetermined systems, we update a QR
-    ## factorization of the Jacobian to avoid solving a full system in each
-    ## step.  In this case, we pass a triangular matrix to __dogleg__.
+    ## For square and overdetermined systems, we update a QR factorization of
+    ## the Jacobian to avoid solving a full system in each step.  In this case,
+    ## we pass a triangular matrix to __dogleg__.
     useqr = updating && m >= n && n > 10;
 
     if (useqr)
@@ -266,7 +298,7 @@
 
     if (autoscale)
       ## Get column norms, use them as scaling factors.
-      jcn = norm (fjac, 'columns').';
+      jcn = norm (fjac, "columns").';
       if (niter == 1)
         dg = jcn;
         dg(dg == 0) = 1;
@@ -308,7 +340,7 @@
           info = -2;
           break;
         endif
-        qtf = q'*fvec;
+        qtf = q'*fval;
         s = - __dogleg__ (r, qtf, dg, delta);
         w = qtf + r * s;
       else
@@ -316,8 +348,8 @@
           info = -2;
           break;
         endif
-        s = - __dogleg__ (fjac, fvec, dg, delta);
-        w = fvec + fjac * s;
+        s = - __dogleg__ (fjac, fval, dg, delta);
+        w = fval + fjac * s;
       endif
 
       sn = norm (dg .* s);
@@ -325,8 +357,8 @@
         delta = min (delta, sn);
       endif
 
-      fvec1 = fcn (reshape (x + s, xsiz)) (:);
-      fn1 = norm (fvec1);
+      fval1 = fcn (reshape (x + s, xsiz)) (:);
+      fn1 = norm (fval1);
       nfev += 1;
 
       if (fn1 < fn)
@@ -375,7 +407,7 @@
         ## Successful iteration.
         x += s;
         xn = norm (dg .* x);
-        fvec = fvec1;
+        fval = fval1;
         fn = fn1;
         nsuciter += 1;
       endif
@@ -388,7 +420,7 @@
         optimvalues.funccount = nfev;
         optimvalues.fval = fn;
         optimvalues.searchdirection = s;
-        state = 'iter';
+        state = "iter";
         stop = outfcn (x, optimvalues, state);
         if (stop)
           info = -1;
@@ -431,13 +463,13 @@
 
       ## Compute the scaled Broyden update.
       if (useqr)
-        u = (fvec1 - q*w) / sn;
+        u = (fval1 - q*w) / sn;
         v = dg .* ((dg .* s) / sn);
 
         ## Update the QR factorization.
         [q, r] = qrupdate (q, r, u, v);
       else
-        u = (fvec1 - w);
+        u = (fval1 - w);
         v = dg .* ((dg .* s) / sn);
 
         ## update the Jacobian
@@ -448,7 +480,7 @@
 
   ## Restore original shapes.
   x = reshape (x, xsiz);
-  fvec = reshape (fvec, fsiz);
+  fval = reshape (fval, fsiz);
 
   output.iterations = niter;
   output.successful = nsuciter;
@@ -487,6 +519,48 @@
 
 endfunction
 
+## Solve the double dogleg trust-region least-squares problem:
+## Minimize norm (r*x-b) subject to the constraint norm (d.*x) <= delta,
+## x being a convex combination of the gauss-newton and scaled gradient.
+
+## FIXME: error checks
+## FIXME: handle singularity, or leave it up to mldivide?
+
+function x = __dogleg__ (r, b, d, delta)
+
+  ## Get Gauss-Newton direction.
+  x = r \ b;
+  xn = norm (d .* x);
+  if (xn > delta)
+    ## GN is too big, get scaled gradient.
+    s = (r' * b) ./ d;
+    sn = norm (s);
+    if (sn > 0)
+      ## Normalize and rescale.
+      s = (s / sn) ./ d;
+      ## Get the line minimizer in s direction.
+      tn = norm (r*s);
+      snm = (sn / tn) / tn;
+      if (snm < delta)
+        ## Get the dogleg path minimizer.
+        bn = norm (b);
+        dxn = delta/xn; snmd = snm/delta;
+        t = (bn/sn) * (bn/xn) * snmd;
+        t -= dxn * snmd^2 - sqrt ((t-dxn)^2 + (1-dxn^2)*(1-snmd^2));
+        alpha = dxn*(1-snmd^2) / t;
+      else
+        alpha = 0;
+      endif
+    else
+      alpha = delta / xn;
+      snm = 0;
+    endif
+    ## Form the appropriate convex combination.
+    x = alpha * x + ((1-alpha) * min (snm, delta)) * s;
+  endif
+
+endfunction
+
 
 %!function retval = __f (p)
 %!  x = p(1);
@@ -521,7 +595,7 @@
 %!test
 %! x_opt = [ -0.767297326653401, 0.590671081117440, ...
 %!            1.47190018629642, -1.52719341133957 ];
-%! tol = 1.0e-5;
+%! tol = 1.0e-4;
 %! [x, fval, info] = fsolve (@__f, [-1, 1, 2, -1]);
 %! assert (info > 0);
 %! assert (norm (x - x_opt, Inf) < tol);
@@ -602,55 +676,13 @@
 %! B = @(lam) [C*expm(A(lam)*0); C*expm(A(lam)*1)];
 %! detB = @(lam) det (B(lam));
 %!
-%! [x, fvec, info] = fsolve (detB, 0);
+%! [x, fval, info] = fsolve (detB, 0);
 %! assert (x == 0);
-%! assert (fvec == -1);
+%! assert (fval == -1);
 %! assert (info == -2);
 
 %!test <*53991>
-%! [x, fvec, info] = fsolve (@(x) 5*x, 0);
+%! [x, fval, info] = fsolve (@(x) 5*x, 0);
 %! assert (x == 0);
-%! assert (fvec == 0);
+%! assert (fval == 0);
 %! assert (info == 1);
-
-## Solve the double dogleg trust-region least-squares problem:
-## Minimize norm(r*x-b) subject to the constraint norm(d.*x) <= delta,
-## x being a convex combination of the gauss-newton and scaled gradient.
-
-## FIXME: error checks
-## FIXME: handle singularity, or leave it up to mldivide?
-
-function x = __dogleg__ (r, b, d, delta)
-
-  ## Get Gauss-Newton direction.
-  x = r \ b;
-  xn = norm (d .* x);
-  if (xn > delta)
-    ## GN is too big, get scaled gradient.
-    s = (r' * b) ./ d;
-    sn = norm (s);
-    if (sn > 0)
-      ## Normalize and rescale.
-      s = (s / sn) ./ d;
-      ## Get the line minimizer in s direction.
-      tn = norm (r*s);
-      snm = (sn / tn) / tn;
-      if (snm < delta)
-        ## Get the dogleg path minimizer.
-        bn = norm (b);
-        dxn = delta/xn; snmd = snm/delta;
-        t = (bn/sn) * (bn/xn) * snmd;
-        t -= dxn * snmd^2 - sqrt ((t-dxn)^2 + (1-dxn^2)*(1-snmd^2));
-        alpha = dxn*(1-snmd^2) / t;
-      else
-        alpha = 0;
-      endif
-    else
-      alpha = delta / xn;
-      snm = 0;
-    endif
-    ## Form the appropriate convex combination.
-    x = alpha * x + ((1-alpha) * min (snm, delta)) * s;
-  endif
-
-endfunction
--- a/scripts/optimization/fzero.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/fzero.m	Thu Dec 20 17:18:56 2018 -0500
@@ -42,14 +42,29 @@
 ##
 ## @var{options} is a structure specifying additional options.  Currently,
 ## @code{fzero} recognizes these options:
-## @qcode{"FunValCheck"}, @qcode{"OutputFcn"}, @qcode{"TolX"},
-## @qcode{"MaxIter"}, @qcode{"MaxFunEvals"}.
-## For a description of these options, see @ref{XREFoptimset,,optimset}.
+## @qcode{"FunValCheck"}, @qcode{"MaxFunEvals"}, @qcode{"MaxIter"},
+## @qcode{"OutputFcn"}, and @qcode{"TolX"}.
+##
+## @qcode{"MaxFunEvals"} proscribes the maximum number of function evaluations
+## before the search is halted.  The default value is @code{Inf}.
+## The value must be a positive integer.
+##
+## @qcode{"MaxIter"} proscribes the maximum number of algorithm iterations
+## before the search is halted.  The default value is @code{Inf}.
+## The value must be a positive integer.
 ##
-## On exit, the function returns @var{x}, the approximate zero point and
-## @var{fval}, the function value thereof.
+## @qcode{"TolX"} specifies the termination tolerance for the solution @var{x}.
+## The default value is @code{eps}.
 ##
-## @var{info} is an exit flag that can have these values:
+## For a description of the other options, see @ref{XREFoptimset,,optimset}.
+## To initialize an options structure with default values for @code{fzero} use
+## @code{options = optimset ("fzero")}.
+##
+## On exit, the function returns @var{x}, the approximate zero point, and
+## @var{fval}, the function evaluated at @var{x}.
+##
+## The third output @var{info} reports whether the algorithm succeeded and
+## may take one of the following values:
 ##
 ## @itemize
 ## @item 1
@@ -59,7 +74,7 @@
 ##  Maximum number of iterations or function evaluations has been reached.
 ##
 ## @item -1
-## The algorithm has been terminated from user output function.
+## The algorithm has been terminated by a user @code{OutputFcn}.
 ##
 ## @item -5
 ## The algorithm may have converged to a singular point.
@@ -72,9 +87,12 @@
 ## @item iterations
 ##  Number of iterations through loop.
 ##
-## @item @nospell{nfev}
+## @item @nospell{funcCount}
 ##  Number of function evaluations.
 ##
+## @item algorithm
+##  The string @qcode{"bisection, interpolation"}.
+##
 ## @item bracketx
 ##  A two-element vector with the final bracketing of the zero along the
 ## x-axis.
@@ -104,9 +122,10 @@
 function [x, fval, info, output] = fzero (fun, x0, options = struct ())
 
   ## Get default options if requested.
-  if (nargin == 1 && ischar (fun) && strcmp (fun, 'defaults'))
-    x = optimset ("MaxIter", Inf, "MaxFunEvals", Inf, "TolX", eps,
-                  "OutputFcn", [], "FunValCheck", "off");
+  if (nargin == 1 && ischar (fun) && strcmp (fun, "defaults"))
+    x = struct ("Display", "notify", "FunValCheck", "off",
+                "MaxFunEvals", Inf, "MaxIter", Inf,
+                "OutputFcn", [], "TolX", eps);
     return;
   endif
 
@@ -115,26 +134,25 @@
   endif
 
   if (ischar (fun))
-    fun = str2func (fun, "global");
+    fun = str2func (fun);
   endif
 
-  ## FIXME:
+  ## FIXME: Display is not yet implemented
   ## displev = optimget (options, "Display", "notify");
   funvalchk = strcmpi (optimget (options, "FunValCheck", "off"), "on");
+  maxfev = optimget (options, "MaxFunEvals", Inf);
+  maxiter = optimget (options, "MaxIter", Inf);
   outfcn = optimget (options, "OutputFcn");
   tolx = optimget (options, "TolX", eps);
-  maxiter = optimget (options, "MaxIter", Inf);
-  maxfev = optimget (options, "MaxFunEvals", Inf);
 
-  persistent mu = 0.5;
+  mu = 0.5;
 
   if (funvalchk)
     ## Replace fun with a guarded version.
     fun = @(x) guarded_eval (fun, x);
   endif
 
-  ## The default exit flag if exceeded number of iterations.
-  info = 0;
+  info = 0;  # The default exit flag if number of iterations exceeded.
   niter = 0;
   nfev = 0;
 
@@ -243,7 +261,7 @@
           c = a + q31 + q32 + q33;
         endif
         if (l < 4 || sign (c - a) * sign (c - b) > 0)
-          ## Quadratic interpolation + newton.
+          ## Quadratic interpolation + Newton.
           a0 = fa;
           a1 = (fb - fa)/(b - a);
           a2 = ((fd - fb)/(d - b) - a1) / (d - a);
@@ -356,6 +374,7 @@
 
   output.iterations = niter;
   output.funcCount = nfev;
+  output.algorithm = "bisection, interpolation";
   output.bracketx = [a, b];
   output.brackety = [fa, fb];
 
--- a/scripts/optimization/lsqnonneg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/lsqnonneg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -82,7 +82,7 @@
 
   ## Special case: called to find default optimization options
   if (nargin == 1 && ischar (c) && strcmp (c, "defaults"))
-    x = optimset ("MaxIter", 1e5);
+    x = struct ("MaxIter", 1e5);
     return;
   endif
 
--- a/scripts/optimization/optimset.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/optimset.m	Thu Dec 20 17:18:56 2018 -0500
@@ -118,6 +118,8 @@
   nargs = nargin;
 
   opts = __all_opts__ ();
+  ## Skip validation if we're in the internal query.
+  validation = ! isempty (opts);
 
   if (nargs == 0)
     if (nargout == 0)
@@ -142,47 +144,71 @@
     ## Should we be checking to ensure that the field names are expected?
     old = varargin{1};
     new = varargin{2};
-    fnames = fieldnames (old);
-    ## skip validation if we're in the internal query
-    validation = ! isempty (opts);
-    for [val, key] = new
-      if (validation)
-        ## Case insensitive lookup in all options.
-        i = strncmpi (opts, key, length (key));
-        nmatch = sum (i);
-        ## Validate option.
-        if (nmatch == 1)
-          key = opts{find (i)};
-        elseif (nmatch == 0)
-          warning ("optimset: unrecognized option: %s", key);
-        else
-          fmt = sprintf ("optimset: ambiguous option: %%s (%s%%s)",
-                         repmat ("%s, ", 1, nmatch-1));
-          warning (fmt, key, opts{i});
-        endif
-      endif
-      old.(key) = val;
-    endfor
-    retval = old;
+    useempty = false; # Matlab drops empty new fields, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   elseif (rem (nargs, 2) && isstruct (varargin{1}))
     ## Set values in old from name/value pairs.
+    old = varargin{1};
     pairs = reshape (varargin(2:end), 2, []);
-    retval = optimset (varargin{1}, cell2struct (pairs(2, :), pairs(1, :), 2));
+    new = cell2struct (pairs(2, :), pairs(1, :), 2);
+    useempty = true; # Matlab preserves empty arguments, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   elseif (rem (nargs, 2) == 0)
     ## Create struct.
     ## Default values are replaced by those specified by name/value pairs.
+    old = struct ();
     pairs = reshape (varargin, 2, []);
-    retval = optimset (struct (), cell2struct (pairs(2, :), pairs(1, :), 2));
+    new = cell2struct (pairs(2, :), pairs(1, :), 2);
+    useempty = true; # Matlab preserves empty arguments, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   else
     print_usage ();
   endif
 
 endfunction
 
+function retval = setoptionfields (opts, old, new, validation, useempty)
+
+  for [val, key] = new
+    if (validation)
+      ## Case insensitive lookup in all options.
+      i = strncmpi (opts, key, length (key));
+      nmatch = sum (i);
+      ## Validate option.
+      if (nmatch == 1)
+        key = opts{find (i)};
+      elseif (nmatch == 0)
+        warning ("optimset: unrecognized option: %s", key);
+      else
+        fmt = sprintf ("optimset: ambiguous option: %%s (%s%%s)",
+                       repmat ("%s, ", 1, nmatch-1));
+        warning (fmt, key, opts{i});
+      endif
+    endif
+    if (useempty || ! isempty (val))
+      old.(key) = val;
+    endif
+  endfor
+  retval = old;
+
+endfunction
 
 %!assert (isfield (optimset (), "TolFun"))
 %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun"))
 %!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2)
+%!test
+%! old = optimset ();
+%! old.TolX = 1e-2;
+%! new = optimset ();
+%! new.TolFun = 1e-3;
+%! joint = optimset (old, new);
+%! assert (joint.TolX, 1e-2);
+%! assert (joint.TolFun, 1e-3);
+
+## Test preserving empty values given as arguments
+%!test
+%! opts = optimset ("TypicalX", []);
+%! assert (isempty (opts.TypicalX));
 
 ## Test input validation
 %!error optimset ("1_Parameter")
--- a/scripts/optimization/pqpnonneg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/pqpnonneg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -84,7 +84,7 @@
 
   ## Special case: called to find default optimization options
   if (nargin == 1 && ischar (c) && strcmp (c, "defaults"))
-    x = optimset ("MaxIter", 1e5);
+    x = struct ("MaxIter", 1e5);
     return;
   endif
 
--- a/scripts/optimization/private/__fdjac__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/private/__fdjac__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 
   if (cdif)
     err = (max (eps, err)) ^ (1/3);
-    h = typicalx*err;
+    h = err * max (abs (x), typicalx);
     fjac = zeros (length (fvec), numel (x));
     for i = 1:numel (x)
       x1 = x2 = x;
@@ -35,7 +35,9 @@
     endfor
   else
     err = sqrt (max (eps, err));
-    h = typicalx*err;
+    signp = sign (x);
+    signp(signp == 0) = 1;
+    h = err * signp .* max (abs (x), typicalx);
     fjac = zeros (length (fvec), numel (x));
     for i = 1:numel (x)
       x1 = x;
--- a/scripts/optimization/qp.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/qp.m	Thu Dec 20 17:18:56 2018 -0500
@@ -120,7 +120,7 @@
 function [x, obj, INFO, lambda] = qp (x0, H, varargin)
 
   if (nargin == 1 && ischar (x0) && strcmp (x0, "defaults"))
-    x = optimset ("MaxIter", 200);
+    x = struct ("MaxIter", 200);
     return;
   endif
 
@@ -264,14 +264,18 @@
   endif
 
   ## Validate inequality constraints.
-  if (nargs > 7)
+  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))
     [dimA_in, n1] = size (A_in);
     if (n1 != n)
-      error ("qp: inequality constraint matrix has incorrect column dimension");
+      error ("qp: inequality constraint matrix has incorrect column dimension, expected %i", n1);
     else
       if (! isempty (A_lb))
         if (numel (A_lb) != dimA_in)
-          error ("qp: inequality constraint matrix and lower bound vector are inconsistent");
+          error ("qp: inequality constraint matrix and lower bound vector are inconsistent, %i != %i", dimA_in, numel (A_lb));
         elseif (isempty (A_ub))
           Ain = [Ain; A_in];
           bin = [bin; A_lb];
@@ -279,7 +283,7 @@
       endif
       if (! isempty (A_ub))
         if (numel (A_ub) != dimA_in)
-          error ("qp: inequality constraint matrix and upper bound vector are inconsistent");
+          error ("qp: inequality constraint matrix and upper bound vector are inconsistent, %i != %i", dimA_in, numel (A_ub));
         elseif (isempty (A_lb))
           Ain = [Ain; -A_in];
           bin = [bin; -A_ub];
--- a/scripts/optimization/sqp.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/optimization/sqp.m	Thu Dec 20 17:18:56 2018 -0500
@@ -202,26 +202,29 @@
     x0 = x0';
   endif
 
+  have_grd = 0;
   have_hess = 0;
   if (iscell (objf))
     switch (numel (objf))
       case 1
         obj_fun = objf{1};
-        obj_grd = @(x) fd_obj_grd (x, obj_fun);
+        obj_grd = @(x, obj) fd_obj_grd (x, obj, obj_fun);
       case 2
         obj_fun = objf{1};
         obj_grd = objf{2};
+        have_grd = 1;
       case 3
         obj_fun = objf{1};
         obj_grd = objf{2};
         obj_hess = objf{3};
+        have_grd = 1;
         have_hess = 1;
       otherwise
         error ("sqp: invalid objective function specification");
     endswitch
   else
     obj_fun = objf;   # No cell array, only obj_fun set
-    obj_grd = @(x) fd_obj_grd (x, obj_fun);
+    obj_grd = @(x, obj) fd_obj_grd (x, obj, obj_fun);
   endif
 
   ce_fun = @empty_cf;
@@ -351,7 +354,11 @@
   obj = feval (obj_fun, x0);
   globals.nfun = 1;
 
-  c = feval (obj_grd, x0);
+  if (have_grd)
+    c = feval (obj_grd, x0);
+  else
+    c = feval (obj_grd, x0, obj);
+  endif
 
   ## Choose an initial NxN symmetric positive definite Hessian approximation B.
   n = length (x0);
@@ -433,10 +440,22 @@
     ## merit function phi.
     [x_new, alpha, obj_new, globals] = ...
         linesearch_L1 (x, p, obj_fun, obj_grd, ce_fun, ci_fun, lambda, ...
-                       obj, globals);
+                       obj, c, globals);
+    
+    delx = x_new - x;
+
+    ## Check if step size has become too small (indicates lack of progress).
+    if (norm (delx) < tol * norm (x))
+      info = 104;
+      break;
+    endif
 
     ## Evaluate objective function, constraints, and gradients at x_new.
-    c_new = feval (obj_grd, x_new);
+    if (have_grd)
+      c_new = feval (obj_grd, x_new);
+    else
+      c_new = feval (obj_grd, x_new, obj_new);
+    endif
 
     ce_new = feval (ce_fun, x_new);
     F_new = feval (ce_grd, x_new);
@@ -458,14 +477,6 @@
       y -= t;
     endif
 
-    delx = x_new - x;
-
-    ## Check if step size has become too small (indicates lack of progress).
-    if (norm (delx) < tol * norm (x))
-      info = 104;
-      break;
-    endif
-
     if (have_hess)
 
       B = feval (obj_hess, x);
@@ -556,7 +567,7 @@
 
 
 function [x_new, alpha, obj, globals] = ...
-   linesearch_L1 (x, p, obj_fun, obj_grd, ce_fun, ci_fun, lambda, obj, globals)
+   linesearch_L1 (x, p, obj_fun, obj_grd, ce_fun, ci_fun, lambda, obj, c, globals)
 
   ## Choose parameters
   ##
@@ -576,7 +587,6 @@
 
   alpha = 1;
 
-  c = feval (obj_grd, x);
   ce = feval (ce_fun, x);
 
   [phi_x_mu, obj, globals] = phi_L1 (obj, obj_fun, ce_fun, ci_fun, x, ...
@@ -611,10 +621,9 @@
 endfunction
 
 
-function grd = fdgrd (f, x)
+function grd = fdgrd (f, x, y0)
 
   if (! isempty (f))
-    y0 = feval (f, x);
     nx = length (x);
     grd = zeros (nx, 1);
     deltax = sqrt (eps);
@@ -653,9 +662,9 @@
 endfunction
 
 
-function grd = fd_obj_grd (x, obj_fun)
+function grd = fd_obj_grd (x, obj, obj_fun)
 
-  grd = fdgrd (obj_fun, x);
+  grd = fdgrd (obj_fun, x, obj);
 
 endfunction
 
--- a/scripts/pkg/pkg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/pkg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -102,6 +102,9 @@
 ## pkg update
 ## @end example
 ##
+## @noindent
+## To update a single package use @code{pkg install -forge}
+##
 ## @item uninstall
 ## Uninstall named packages.  For example,
 ##
@@ -309,10 +312,10 @@
 
   confirm_recursive_rmdir (false, "local");
 
-  available_actions = {"list", "install", "uninstall", "load", ...
-                       "unload", "prefix", "local_list", ...
-                       "global_list", "rebuild", "build", ...
-                       "describe", "update"};
+  # valid actions in alphabetical order
+  available_actions = {"build", "describe", "global_list",  "install", ...
+                       "list", "load", "local_list", "prefix", "rebuild", ...
+                       "uninstall", "unload", "update"};
 
   ## Parse input arguments
   if (isempty (varargin) || ! iscellstr (varargin))
@@ -471,25 +474,10 @@
         global_packages = archprefix;
       elseif (numel (files) >= 1 && ischar (files{1}))
         prefix = tilde_expand (files{1});
-        if (! exist (prefix, "dir"))
-          [status, msg] = mkdir (prefix);
-          if (status == 0)
-            error ("pkg: cannot create prefix %s: %s", prefix, msg);
-          endif
-          warning ("pkg: creating the directory %s\n", prefix);
-        endif
-        local_packages = prefix = canonicalize_file_name (prefix);
+        local_packages = prefix = make_absolute_filename (prefix);
         user_prefix = true;
         if (numel (files) >= 2 && ischar (files{2}))
-          archprefix = tilde_expand (files{2});
-          if (! exist (archprefix, "dir"))
-            [status, msg] = mkdir (archprefix);
-            if (status == 0)
-              error ("pkg: cannot create archprefix %s: %s", archprefix, msg);
-            endif
-            warning ("pkg: creating the directory %s\n", archprefix);
-            global_packages = archprefix = canonicalize_file_name (archprefix);
-          endif
+          archprefix = make_absolute_filename (tilde_expand (files{2}));
         endif
       else
         error ("pkg: prefix action requires a directory input, or an output argument");
@@ -571,19 +559,24 @@
 
     case "update"
       installed_pkgs_lst = installed_packages (local_list, global_list);
+
+      ## Explicit list of packages to update, rather than all packages
       if (numel (files) > 0)
-         update_lst = {};
-         installed_names = {installed_pkgs_lst.name}';
-         for i = 1:numel (files)
-           idx = find (strcmp (files{i}, installed_names), 1);
-           if (isempty (idx))
-             warning ("pkg: package %s is not installed - skipping update", files{i});
-           else
-             update_lst = { update_lst, installed_pkgs_lst{idx} };
-           endif
-         endfor
-         installed_pkgs_lst = update_lst;
+        update_lst = {};
+        installed_names = cellfun (@(idx) idx.name, installed_pkgs_lst,
+                                   "UniformOutput", false);
+        for i = 1:numel (files)
+          idx = find (strcmp (files{i}, installed_names), 1);
+          if (isempty (idx))
+            warning ("pkg: package %s is not installed - skipping update",
+                     files{i});
+          else
+            update_lst = [ update_lst, installed_pkgs_lst(idx) ];
+          endif
+        endfor
+        installed_pkgs_lst = update_lst;
       endif
+
       for i = 1:numel (installed_pkgs_lst)
         installed_pkg_name = installed_pkgs_lst{i}.name;
         installed_pkg_version = installed_pkgs_lst{i}.version;
--- a/scripts/pkg/private/build.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/build.m	Thu Dec 20 17:18:56 2018 -0500
@@ -38,7 +38,7 @@
     print_usage ();
   endif
 
-  if (! exist (builddir, "dir"))
+  if (! isfolder (builddir))
     warning ("creating build directory %s", builddir);
     [status, msg] = mkdir (builddir);
     if (status != 1)
@@ -46,7 +46,7 @@
     endif
   endif
 
-  for i = 1:numel(tarballs)
+  for i = 1:numel (tarballs)
     filelist = unpack (tarballs{i}, builddir);
 
     ## We want the path for the package root but we can't assume that
--- a/scripts/pkg/private/configure_make.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/configure_make.m	Thu Dec 20 17:18:56 2018 -0500
@@ -25,7 +25,7 @@
 function configure_make (desc, packdir, verbose)
 
   ## Perform ./configure, make, make install in "src".
-  if (exist (fullfile (packdir, "src"), "dir"))
+  if (isfolder (fullfile (packdir, "src")))
     src = fullfile (packdir, "src");
     octave_bindir = __octave_config_info__ ("bindir");
     ver = version ();
--- a/scripts/pkg/private/dirempty.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/dirempty.m	Thu Dec 20 17:18:56 2018 -0500
@@ -24,7 +24,7 @@
 
 function emp = dirempty (nm, ign)
 
-  if (exist (nm, "dir"))
+  if (isfolder (nm))
     if (nargin < 2)
       ign = {".", ".."};
     else
--- a/scripts/pkg/private/install.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/install.m	Thu Dec 20 17:18:56 2018 -0500
@@ -26,7 +26,7 @@
                   local_list, global_list, global_install)
 
   ## Check that the directory in prefix exist.  If it doesn't: create it!
-  if (! exist (prefix, "dir"))
+  if (! isfolder (prefix))
     warning ("creating installation directory %s", prefix);
     [status, msg] = mkdir (prefix);
     if (status != 1)
@@ -92,11 +92,11 @@
       endif
 
       ## The filename pointed to an uncompressed package to begin with.
-      if (exist (tgz, "dir"))
+      if (isfolder (tgz))
         dirlist = {".", "..", tgz};
       endif
 
-      if (exist (tgz, "file") || exist (tgz, "dir"))
+      if (exist (tgz, "file") || isfolder (tgz))
         ## The two first entries of dirlist are "." and "..".
         if (exist (tgz, "file"))
           packdir = fullfile (tmpdir, dirlist{3});
@@ -278,7 +278,7 @@
   ## All is well, let's clean up.
   for i = 1:length (tmpdirs)
     [status, msg] = rmdir (tmpdirs{i}, "s");
-    if (status != 1 && exist (tmpdirs{i}, "dir"))
+    if (status != 1 && isfolder (tmpdirs{i}))
       warning ("couldn't clean up after my self: %s\n", msg);
     endif
   endfor
@@ -288,7 +288,8 @@
   ## without creating it such as giving an invalid filename for the package
   if (exist ("desc", "var")
       && exist (fullfile (desc.dir, "packinfo", "NEWS"), "file"))
-    printf ("For information about changes from previous versions of the %s package, run 'news %s'.\n",
+    printf (["For information about changes from previous versions " ...
+             "of the %s package, run 'news %s'.\n"],
             desc.name, desc.name);
   endif
 
@@ -348,7 +349,7 @@
 
   ## If the directory "inst" doesn't exist, we create it.
   inst_dir = fullfile (packdir, "inst");
-  if (! exist (inst_dir, "dir"))
+  if (! isfolder (inst_dir))
     [status, msg] = mkdir (inst_dir);
     if (status != 1)
       rmdir (desc.dir, "s");
@@ -363,7 +364,7 @@
 function copy_built_files (desc, packdir, verbose)
 
   src = fullfile (packdir, "src");
-  if (! exist (src, "dir"))
+  if (! isfolder (src))
     return
   endif
 
@@ -414,7 +415,7 @@
 
   ## Copy the files.
   if (! all (isspace ([filenames{:}])))
-      if (! exist (instdir, "dir"))
+      if (! isfolder (instdir))
         mkdir (instdir);
       endif
       if (! all (isspace ([archindependent{:}])))
@@ -435,7 +436,7 @@
           printf (" %s", archdependent{:});
           printf (" %s\n", archdir);
         endif
-        if (! exist (archdir, "dir"))
+        if (! isfolder (archdir))
           mkdir (archdir);
         endif
         [status, output] = copyfile (archdependent, archdir);
@@ -477,7 +478,7 @@
 function copy_files (desc, packdir, global_install)
 
   ## Create the installation directory.
-  if (! exist (desc.dir, "dir"))
+  if (! isfolder (desc.dir))
     [status, output] = mkdir (desc.dir);
     if (status != 1)
       error ("couldn't create installation directory %s : %s",
@@ -495,17 +496,17 @@
       rmdir (desc.dir, "s");
       error ("couldn't copy files to the installation directory");
     endif
-    if (exist (fullfile (desc.dir, getarch ()), "dir")
+    if (isfolder (fullfile (desc.dir, getarch ()))
         && ! strcmp (canonicalize_file_name (fullfile (desc.dir, getarch ())),
                      canonicalize_file_name (octfiledir)))
-      if (! exist (octfiledir, "dir"))
+      if (! isfolder (octfiledir))
         ## Can be required to create up to three levels of dirs.
         octm1 = fileparts (octfiledir);
-        if (! exist (octm1, "dir"))
+        if (! isfolder (octm1))
           octm2 = fileparts (octm1);
-          if (! exist (octm2, "dir"))
+          if (! isfolder (octm2))
             octm3 = fileparts (octm2);
-            if (! exist (octm3, "dir"))
+            if (! isfolder (octm3))
               [status, output] = mkdir (octm3);
               if (status != 1)
                 rmdir (desc.dir, "s");
@@ -583,14 +584,14 @@
 
   ## Is there a doc/ directory that needs to be installed?
   docdir = fullfile (packdir, "doc");
-  if (exist (docdir, "dir") && ! dirempty (docdir))
+  if (isfolder (docdir) && ! dirempty (docdir))
     [status, output] = copyfile (docdir, desc.dir);
   endif
 
   ## Is there a bin/ directory that needs to be installed?
   ## FIXME: Need to treat architecture dependent files in bin/
   bindir = fullfile (packdir, "bin");
-  if (exist (bindir, "dir") && ! dirempty (bindir))
+  if (isfolder (bindir) && ! dirempty (bindir))
     [status, output] = copyfile (bindir, desc.dir);
   endif
 
@@ -631,7 +632,7 @@
   for k = 1:length (class_idx)
     class_name = files {class_idx(k)};
     class_dir = fullfile (dir, class_name);
-    if (exist (class_dir, "dir"))
+    if (isfolder (class_dir))
       [files2, err, msg] = readdir (class_dir);
       if (err)
         error ("couldn't read directory %s: %s", class_dir, msg);
@@ -643,7 +644,7 @@
 
   ## Check for architecture dependent files.
   tmpdir = getarchdir (desc);
-  if (exist (tmpdir, "dir"))
+  if (isfolder (tmpdir))
     [files2, err, msg] = readdir (tmpdir);
     if (err)
       error ("couldn't read directory %s: %s", tmpdir, msg);
@@ -694,7 +695,7 @@
   ## part in the main directory.
   archdir = fullfile (getarchprefix (desc, global_install),
                       [desc.name "-" desc.version], getarch ());
-  if (exist (getarchdir (desc, global_install), "dir"))
+  if (isfolder (getarchdir (desc, global_install)))
     archpkg = fullfile (getarchdir (desc, global_install), nm);
     archfid = fopen (archpkg, "at");
   else
--- a/scripts/pkg/private/load_packages_and_dependencies.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/load_packages_and_dependencies.m	Thu Dec 20 17:18:56 2018 -0500
@@ -28,16 +28,16 @@
   idx = load_package_dirs (idx, [], handle_deps, installed_pkgs_lst);
   dirs = {};
   execpath = EXEC_PATH ();
-  for i = idx;
+  for i = idx
     ndir = installed_pkgs_lst{i}.dir;
     dirs{end+1} = ndir;
-    if (exist (fullfile (dirs{end}, "bin"), "dir"))
+    if (isfolder (fullfile (dirs{end}, "bin")))
       execpath = [execpath pathsep() fullfile(dirs{end}, "bin")];
     endif
     tmpdir = getarchdir (installed_pkgs_lst{i});
-    if (exist (tmpdir, "dir"))
+    if (isfolder (tmpdir))
       dirs{end + 1} = tmpdir;
-      if (exist (fullfile (dirs{end}, "bin"), "dir"))
+      if (isfolder (fullfile (dirs{end}, "bin")))
         execpath = [execpath pathsep() fullfile(dirs{end}, "bin")];
       endif
     endif
--- a/scripts/pkg/private/uninstall.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/uninstall.m	Thu Dec 20 17:18:56 2018 -0500
@@ -110,17 +110,17 @@
       ## Do the actual deletion.
       if (desc.loaded)
         rmpath (desc.dir);
-        if (exist (getarchdir (desc)))
+        if (isfolder (getarchdir (desc)))
           rmpath (getarchdir (desc));
         endif
       endif
-      if (exist (desc.dir, "dir"))
+      if (isfolder (desc.dir))
         [status, msg] = rmdir (desc.dir, "s");
-        if (status != 1 && exist (desc.dir, "dir"))
+        if (status != 1 && isfolder (desc.dir))
           error ("couldn't delete directory %s: %s", desc.dir, msg);
         endif
         [status, msg] = rmdir (getarchdir (desc), "s");
-        if (status != 1 && exist (getarchdir (desc), "dir"))
+        if (status != 1 && isfolder (getarchdir (desc)))
           error ("couldn't delete directory %s: %s", getarchdir (desc), msg);
         endif
         if (dirempty (desc.archprefix))
--- a/scripts/pkg/private/unload_packages.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/pkg/private/unload_packages.m	Thu Dec 20 17:18:56 2018 -0500
@@ -54,7 +54,7 @@
   archdirs = {};
   for i = 1:length (dirs)
     tmpdir = getarchdir (desc{i});
-    if (exist (tmpdir, "dir"))
+    if (isfolder (tmpdir))
       archdirs{end+1} = dirs{i};
       archdirs{end+1} = tmpdir;
     else
--- a/scripts/plot/appearance/datetick.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/appearance/datetick.m	Thu Dec 20 17:18:56 2018 -0500
@@ -205,10 +205,10 @@
     else
       [ymin, mmin, dmin] = datevec (xmin);
       [ymax, mmax, dmax] = datevec (xmax);
-      minyear = ymin + (mmin - 1) / 12 + (dmin - 1) / 12 / 30;
-      maxyear = ymax + (mmax - 1) / 12 + (dmax - 1) / 12 / 30;
-      minmonth = mmin + (dmin - 1) / 30;
-      maxmonth = (ymax  - ymin) * 12 + mmax + (dmax - 1) / 30;
+      minyear = ymin + (mmin - 1) / 12 + (dmin - 1) / 12 / 30.5;
+      maxyear = ymax + (mmax - 1) / 12 + (dmax - 1) / 12 / 30.5;
+      minmonth = mmin + (dmin - 1) / 30.5;
+      maxmonth = (ymax  - ymin) * 12 + mmax + (dmax - 1) / 30.5;
 
       if (maxmonth - minmonth < N)
         sep = __calc_tick_sep__ (xmin, xmax);
--- a/scripts/plot/appearance/hidden.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/appearance/hidden.m	Thu Dec 20 17:18:56 2018 -0500
@@ -51,7 +51,7 @@
     endif
   endif
 
-  for h = (get (gca (), "children")).';
+  for h = (get (gca (), "children")).'
     [htype, htag] = get (h, {"type", "tag"}){:};
     if (strcmp (htype, "surface") || strcmp (htag, "trimesh"))
       fc = get (h, "facecolor");
--- a/scripts/plot/appearance/legend.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/appearance/legend.m	Thu Dec 20 17:18:56 2018 -0500
@@ -237,12 +237,9 @@
   endwhile
 
   ## Validate the orientation
-  switch (orientation)
-    case {"vertical", "horizontal", "default"}
-      ## These are all accepted orientations.
-    otherwise
-      error ("legend: unrecognized legend orientation");
-  endswitch
+  if (! any (strcmp (orientation, {"vertical", "horizontal", "default"})))
+    error ("legend: unrecognized legend orientation");
+  endif
 
   ## Validate the location type
   outside = false;
@@ -257,11 +254,23 @@
   switch (location)
     case {"north", "south", "east", "west", "northeast", "northwest", ...
           "southeast", "southwest", "default"}
+      ## These are all valid locations, do nothing.
+
     case "best"
-      warning ("legend: 'best' not yet implemented for location specifier\n");
-      location = "northeast";
+      if (outside)
+        if (strcmp (orientation, "horizontal"))
+          location = "south";
+        else
+          location = "northeast";
+        endif
+      else
+        warning ("legend: 'best' not yet implemented for location specifier, using 'northeast' instead\n");
+        location = "northeast";
+      endif
+
     case "none"
       ## FIXME: Should there be any more error checking on this?
+
     otherwise
       error ("legend: unrecognized legend location");
   endswitch
@@ -570,8 +579,13 @@
       end_unwind_protect
 
       ## Padding between legend entries horizontally and vertically
-      xpad = 2;
-      ypad = 2;
+      ## measured in points.
+      ## FIXME: 3*xpad must be integer or strange off-by-1 pixel issues
+      ##        with lines in OpenGL.
+      xpad = 2 + 1/3;
+      ypad = 4;
+
+      bpad = 8;  # padding of legend box from surrounding axes
 
       linelength = 15;
 
@@ -673,7 +687,7 @@
           maxwidth = max (maxwidth, extents(3));
           maxheight = max (maxheight, extents(4));
         endfor
-        ## Restore units which were force to points
+        ## Restore units which were forced to points
         set (texthandle, "units", get (0, "DefaultTextUnits"));
 
         num1 = nentries;
@@ -704,6 +718,7 @@
         endif
         num2 = ceil (nentries / num1);
 
+        ## Layout is [xpad, linelength, xpad, maxwidth, xpad]
         xstep = 3 * xpad + (maxwidth + linelength);
         if (strcmp (textpos, "right"))
           xoffset = xpad;
@@ -752,95 +767,98 @@
           case "north"
             if (outside)
               lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
-                      ca_outpos(2) + ca_outpos(4) - lpos(4) - ypad, lpos(3), ...
-                      lpos(4)];
+                      ca_outpos(2) + ca_outpos(4) - lpos(4) - bpad/2, ...
+                      lpos(3), lpos(4)];
 
               new_pos = [ca_pos(1), ca_pos(2), ca_pos(3), ca_pos(4) - lpos(4)];
             else
               lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
-                      ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
+                      ca_pos(2) + ca_pos(4) - lpos(4) - bpad, ...
+                      lpos(3), lpos(4)];
             endif
           case "south"
             if (outside)
               lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
-                      ca_outpos(2) + ypad, lpos(3), lpos(4)];
-              new_pos = [ca_pos(1), lpos(2) + lpos(4) + 2 * ypad ...
-                      + tightinset(2), ca_pos(3), ...
-                         ca_pos(4) - lpos(4)];
+                      ca_outpos(2) + bpad/2, lpos(3), lpos(4)];
+              new_pos = [ca_pos(1), ...
+                         lpos(2) + lpos(4) + bpad/2 + tightinset(2), ...
+                         ca_pos(3), ca_pos(4) - lpos(4)];
             else
               lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
-                      ca_pos(2) + ypad, lpos(3), lpos(4)];
+                      ca_pos(2) + bpad, lpos(3), lpos(4)];
             endif
           case "east"
             if (outside)
-              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - ypad, ...
-                      ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
+              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - bpad/2, ...
+                      ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, ...
+                      lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ...
-                         lpos(1) - 2 * xpad - ca_pos(1) - tightinset(3), ...
+                         lpos(1) - bpad - tightinset(3) - ca_pos(1), ...
                          ca_pos(4)];
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              new_pos(3) += gnuplot_offset;
             else
-              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
+              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - bpad, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
             endif
           case "west"
             if (outside)
-              lpos = [ca_outpos(1) + ypad, ...
+              lpos = [ca_outpos(1) + bpad/2, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, ...
                       lpos(3), lpos(4)];
-              new_pos = [lpos(1) + lpos(3) + 2 * xpad + tightinset(1), ...
-                         ca_pos(2), ca_pos(3) - lpos(3) - 2 * xpad, ca_pos(4)];
-              new_pos(1) = new_pos(1) - gnuplot_offset;
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              new_pos = [lpos(1) + lpos(3) + bpad/2 + tightinset(1), ...
+                         ca_pos(2), ca_pos(3) - lpos(3) - bpad/2, ca_pos(4)];
+              new_pos([1, 3]) += [-gnuplot_offset, gnuplot_offset];
             else
-              lpos = [ca_pos(1) +  ypad, ...
+              lpos = [ca_pos(1) + bpad, ...
                       ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
             endif
           case "northeast"
             if (outside)
-              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - ypad, ...
-                      ca_pos(2) + ca_pos(4) - lpos(4), lpos(3), lpos(4)];
+              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - bpad/2, ...
+                      ca_pos(2) + ca_pos(4) - lpos(4), ...
+                      lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ...
-                         lpos(1) - 2 * xpad - tightinset(3) - ca_pos(1), ...
+                         lpos(1) - bpad - tightinset(3) - ca_pos(1), ...
                          ca_pos(4)];
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              new_pos(3) += gnuplot_offset;
             else
-              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
-                      ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
+              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - bpad, ...
+                      ca_pos(2) + ca_pos(4) - lpos(4) - bpad, ...
+                      lpos(3), lpos(4)];
             endif
           case "northwest"
             if (outside)
-              lpos = [ca_outpos(1) + ypad , ca_pos(2) + ca_pos(4) - lpos(4), ...
+              lpos = [ca_outpos(1) + bpad/2, ...
+                      ca_pos(2) + ca_pos(4) - lpos(4), ...
                       lpos(3), lpos(4)];
-              new_pos = [lpos(1) + lpos(3) + 2 * xpad + tightinset(1), ...
-              ca_pos(2), ca_pos(3) - lpos(3) - 2 * xpad, ca_pos(4)];
-              new_pos(1) = new_pos(1) - gnuplot_offset;
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              new_pos = [lpos(1) + lpos(3) + bpad/2 + tightinset(1), ...
+                         ca_pos(2), ca_pos(3) - lpos(3) - bpad/2, ca_pos(4)];
+              new_pos([1, 3]) += [-gnuplot_offset, gnuplot_offset];
             else
-              lpos = [ca_pos(1) + ypad, ...
-                      ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
+              lpos = [ca_pos(1) + bpad, ...
+                      ca_pos(2) + ca_pos(4) - lpos(4) - bpad, ...
+                      lpos(3), lpos(4)];
             endif
           case "southeast"
             if (outside)
-              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - ypad, ...
+              lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3) - bpad/2, ...
                       ca_pos(2), lpos(3), lpos(4)];
               new_pos = [ca_pos(1), ca_pos(2), ...
-                         lpos(1) - 2 * xpad - ca_pos(1) - tightinset(3), ...
+                         lpos(1) - bpad - ca_pos(1) - tightinset(3), ...
                          ca_pos(4)];
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              new_pos(3) += gnuplot_offset;
             else
-              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
-                      ca_pos(2) + ypad, lpos(3), lpos(4)];
+              lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - bpad, ...
+                      ca_pos(2) + bpad, lpos(3), lpos(4)];
             endif
           case "southwest"
             if (outside)
-              lpos = [ca_outpos(1) + ypad, ca_pos(2), lpos(3), lpos(4)];
-              new_pos = [lpos(1) + lpos(3) + 2 * xpad + tightinset(1), ...
-              ca_pos(2), ca_pos(3) - lpos(3) - 2 * xpad, ca_pos(4)];
-              new_pos(1) = new_pos(1) - gnuplot_offset;
-              new_pos(3) = new_pos(3) + gnuplot_offset;
+              lpos = [ca_outpos(1) + bpad/2, ca_pos(2), lpos(3), lpos(4)];
+              new_pos = [lpos(1) + lpos(3) + bpad/2 + tightinset(1), ...
+                         ca_pos(2), ca_pos(3) - lpos(3) - bpad/2, ca_pos(4)];
+              new_pos([1, 3]) += [-gnuplot_offset, gnuplot_offset];
             else
-              lpos = [ca_pos(1) + ypad, ca_pos(2) + ypad, lpos(3), lpos(4)];
+              lpos = [ca_pos(1) + bpad, ca_pos(2) + bpad, lpos(3), lpos(4)];
             endif
         endswitch
 
@@ -877,22 +895,24 @@
               style = get (hplt, "linestyle");
               lwidth = min (get (hplt, "linewidth"), 5);
               if (! strcmp (style, "none"))
-                l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3),
-                           "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4),
-                           "color", color, "linestyle", style, "linewidth", lwidth,
-                           "marker", "none");
+                l1 = __go_line__ (hlegend, ...
+                       "xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3), ...
+                       "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4), ...
+                       "color", color, "linestyle", style, ...
+                       "linewidth", lwidth, "marker", "none");
                 setappdata (l1, "handle", hplt);
                 hobjects(end+1) = l1;
               endif
               marker = get (hplt, "marker");
               if (! strcmp (marker, "none"))
-                l1 = line ("xdata", (xoffset + 0.5 * linelength  + xk * xstep) / lpos(3),
-                           "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4),
-                           "color", color, "linestyle", "none", "linewidth", lwidth,
-                           "marker", marker,
-                           "markeredgecolor", get (hplt, "markeredgecolor"),
-                           "markerfacecolor", get (hplt, "markerfacecolor"),
-                           "markersize", min (get (hplt, "markersize"),10));
+                l1 = __go_line__ (hlegend, ...
+                       "xdata", (xoffset + 0.5 * linelength  + xk * xstep) / lpos(3), ...
+                       "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4), ...
+                       "color", color, "linestyle", "none", ...
+                       "linewidth", lwidth, "marker", marker, ...
+                       "markeredgecolor", get (hplt, "markeredgecolor"), ...
+                       "markerfacecolor", get (hplt, "markerfacecolor"), ...
+                       "markersize", min (get (hplt, "markersize"),10));
                 setappdata (l1, "handle", hplt);
                 hobjects(end+1) = l1;
               endif
@@ -1310,21 +1330,21 @@
     endif
 
     if (! strcmp (linestyle, "none"))
-      hl = line ("xdata", xpos1, "ydata", ypos1, "color", get (h, "color"),
-                 "linestyle", get (h, "linestyle"),
-                 "linewidth", min (get (h, "linewidth"), 5),
-                 "marker", "none",
-                 "parent", hlegend);
+      hl = __go_line__ (hlegend, "xdata", xpos1, "ydata", ypos1,
+                        "color", get (h, "color"),
+                        "linestyle", get (h, "linestyle"),
+                        "linewidth", min (get (h, "linewidth"), 5),
+                        "marker", "none");
       setappdata (hl, "handle", h);
     endif
     if (! strcmp (marker, "none"))
-      hl = line ("xdata", xpos2, "ydata", ypos2, "color", get (h, "color"),
-                 "marker", marker, "markeredgecolor", get (h, "markeredgecolor"),
-                 "markerfacecolor", get (h, "markerfacecolor"),
-                 "markersize", min (get (h, "markersize"), 10),
-                 "linestyle", "none",
-                 "linewidth", min (get (h, "linewidth"), 5),
-                 "parent", hlegend);
+      hl = __go_line__ (hlegend, "xdata", xpos2, "ydata", ypos2, ...
+                        "color", get (h, "color"), ...
+                        "marker", marker, "markeredgecolor", get (h, "markeredgecolor"), ...
+                        "markerfacecolor", get (h, "markerfacecolor"), ...
+                        "markersize", min (get (h, "markersize"), 10), ...
+                        "linestyle", "none", ...
+                        "linewidth", min (get (h, "linewidth"), 5));
       setappdata (hl, "handle", h);
     endif
   endif
@@ -1806,7 +1826,6 @@
 %! unwind_protect
 %!   plot (1:10);
 %!   fail ("legend ('location','best')", "warning", "'best' not yet implemented");
-%!   fail ("legend ('location','bestoutside')", "warning", "'best' not yet implemented");
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
--- a/scripts/plot/appearance/whitebg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/appearance/whitebg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -119,7 +119,7 @@
       fields = fieldnames (props);
       ## Find all fields with the word color in them and invert.
       idx = find (! cellfun ("isempty", regexp (fields, 'color$')));
-      for field = fields(idx)';
+      for field = fields(idx)'
         c = props.(field{1});
         if (! ischar (c) && columns (c) == 3)
           set (h, field{1}, 1 - c);
@@ -150,7 +150,7 @@
         fields = fieldnames (props);
         ## Find all fields with the word color in them and adjust HSV.
         idx = find (! cellfun ("isempty", regexp (fields, 'color$')));
-        for field = fields(idx)';
+        for field = fields(idx)'
           c = props.(field{1});
           if (! ischar (c) && columns (c) == 3)
             set (h, field{1}, calc_contrast_color (bg, c));
--- a/scripts/plot/draw/area.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/area.m	Thu Dec 20 17:18:56 2018 -0500
@@ -137,7 +137,7 @@
   y0 = bv * ones (1, rows (y));
   y0 = zeros (1, rows (y));
   retval = [];
-  for i = 1: columns (y);
+  for i = 1: columns (y)
 
     lc = __next_line_color__ ();
 
--- a/scripts/plot/draw/camlight.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/camlight.m	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,7 @@
 ## @deftypefnx {} {} camlight (@var{az}, @var{el})
 ## @deftypefnx {} {} camlight (@dots{}, @var{style})
 ## @deftypefnx {} {} camlight (@var{hl}, @dots{})
+## @deftypefnx {} {} camlight (@var{hax}, @dots{})
 ## @deftypefnx {} {@var{h} =} camlight (@dots{})
 ## Add a light object to a figure using a simple interface.
 ##
@@ -45,6 +46,9 @@
 ## If the first argument @var{hl} is a handle to a light object, then act on
 ## this light object rather than creating a new object.
 ##
+## If the first argument @var{hax} is an axes handle, then create a new light
+## object in this axes, rather than the current axes returned by @code{gca}.
+##
 ## The optional return value @var{h} is a graphics handle to the light object.
 ## This can be used to move or further change properties of the light object.
 ##
@@ -100,14 +104,21 @@
   ## We don't worry about that.
   if (numel (varargin) > 0 && numel (varargin{1}) == 1
       && ishghandle (varargin{1}))
-    hl = varargin{1};
-    if (! isgraphics (hl, "light"))
-      error ("camlight: HL must be a handle to a light object");
+    typ = get (varargin{1}, "type");
+    if (strcmp (typ, "light"))
+      hl  = varargin{1};
+      hax = get (hl, "parent");
+    elseif (strcmp (typ, "axes"))
+      hax = varargin{1};
+      hl  = [];
+    else
+      error ("camlight: HL must be a handle to an axes or light object");
     endif
     varargin(1) = [];
     nargin = nargin - 1;
   else
-    hl = [];
+    hl  = [];
+    hax = [];
   endif
 
   style = "local";
@@ -168,9 +179,12 @@
     endswitch
   endif
 
-  cam_up = get (gca (), "cameraupvector");
-  cam_pos = get (gca (), "cameraposition");
-  cam_target = get (gca (), "cameratarget");
+  if (isempty (hax))
+    hax = gca ();
+  endif
+  cam_up = get (hax, "cameraupvector");
+  cam_pos = get (hax, "cameraposition");
+  cam_target = get (hax, "cameratarget");
 
   view_ax = cam_target - cam_pos;
   view_ax /= norm (view_ax);
@@ -186,7 +200,7 @@
   pos = [pos{:}];
 
   if (isempty (hl))
-    hl = light ("Position", pos, "style", style);
+    hl = light (hax, "Position", pos, "style", style);
   else
     set (hl, "Position", pos, "style", style);
   endif
@@ -296,9 +310,23 @@
 %!   close (hf);
 %! end_unwind_protect
 
+## Test an axes handle as first argument
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hax1 = subplot (1, 2, 1);
+%!   hax2 = subplot (1, 2, 2);
+%!   hl1  = camlight ();
+%!   hl2  = camlight (hax1);
+%!   assert (get (hl1, "Parent"), hax2);
+%!   assert (get (hl2, "Parent"), hax1);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
 ## Test input validation
 %!error camlight (1,2,3,4,5)
-%!error <HL must be a handle to a light object> camlight (0, "left")
+%!error <HL must be a handle to an axes or light object> camlight (0, "left")
 %!error <Invalid call> camlight ({1}, {2})
 %!error <Invalid call> camlight (rand (), 1, 2, 3)
 %!error <invalid light position 'foobar'> camlight ("foobar")
--- a/scripts/plot/draw/comet.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/comet.m	Thu Dec 20 17:18:56 2018 -0500
@@ -73,7 +73,7 @@
                x(1), y(1), "color", "b", "marker", "o");
     axis (limits);  # set manual limits to speed up plotting
 
-    for n = 2:(num+dn);
+    for n = 2:(num+dn)
       m = n - dn;
       m = max ([m, 1]);
       k = min ([n, num]);
--- a/scripts/plot/draw/comet3.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/comet3.m	Thu Dec 20 17:18:56 2018 -0500
@@ -76,7 +76,7 @@
                 x(1), y(1), z(1), "color", "b", "marker", "o");
     axis (limits);  # set manual limits to speed up plotting
 
-    for n = 2:(num+dn);
+    for n = 2:(num+dn)
       m = n - dn;
       m = max ([m, 1]);
       k = min ([n, num]);
--- a/scripts/plot/draw/fplot.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/fplot.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,10 +17,13 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} fplot (@var{fn}, @var{limits})
+## @deftypefn  {} {} fplot (@var{fn})
+## @deftypefnx {} {} fplot (@var{fn}, @var{limits})
 ## @deftypefnx {} {} fplot (@dots{}, @var{tol})
 ## @deftypefnx {} {} fplot (@dots{}, @var{n})
 ## @deftypefnx {} {} fplot (@dots{}, @var{fmt})
+## @deftypefnx {} {} fplot (@dots{}, @var{property}, @var{value}, @dots{})
+## @deftypefnx {} {} fplot (@var{hax}, @dots{})
 ## @deftypefnx {} {[@var{x}, @var{y}] =} fplot (@dots{})
 ## Plot a function @var{fn} within the range defined by @var{limits}.
 ##
@@ -28,7 +31,8 @@
 ## name of the function to evaluate.
 ##
 ## The limits of the plot are of the form @w{@code{[@var{xlo}, @var{xhi}]}} or
-## @w{@code{[@var{xlo}, @var{xhi}, @var{ylo}, @var{yhi}]}}.
+## @w{@code{[@var{xlo}, @var{xhi}, @var{ylo}, @var{yhi}]}}.  If no limits
+## are specified the default is @code{[-5, 5]}.
 ##
 ## The next three arguments are all optional and any number of them may be
 ## given in any order.
@@ -44,11 +48,15 @@
 ## The @var{fmt} argument specifies the linestyle to be used by the plot
 ## command.
 ##
+## Multiple property-value pairs may also be specified, but they must appear
+## in pairs.  These arguments are applied to the line objects drawn by
+## @code{plot}.
+##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
-## With no output arguments the results are immediately plotted.  With two
-## output arguments the 2-D plot data is returned.  The data can subsequently
+## With no output arguments, the results are immediately plotted.  With two
+## output arguments, the 2-D plot data is returned.  The data can subsequently
 ## be plotted manually with @code{plot (@var{x}, @var{y})}.
 ##
 ## Example:
@@ -75,24 +83,19 @@
 ## @seealso{ezplot, plot, vectorize}
 ## @end deftypefn
 
-## Author: Paul Kienzle <pkienzle@users.sf.net>
-
 function [X, Y] = fplot (varargin)
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("fplot", varargin{:});
 
-  if (nargin < 2 || nargin > 5)
+  if (nargin < 1 || nargin > 5)
     print_usage ();
   endif
 
   fn = varargin{1};
-  limits = varargin{2};
-  varargin = varargin(3:end);
-
   if (strcmp (typeinfo (fn), "inline function"))
     fn = vectorize (fn);
     nam = formula (fn);
-  elseif (isa (fn, "function_handle"))
+  elseif (is_function_handle (fn))
     nam = func2str (fn);
   elseif (all (isalnum (fn)))
     nam = fn;
@@ -103,17 +106,33 @@
     error ("fplot: FN must be a function handle, inline function, or string");
   endif
 
-  if (iscomplex (limits) || (numel (limits) != 2 && numel (limits) != 4))
-    error ("fplot: LIMITS must be a real vector with 2 or 4 elements");
+  if (nargin > 1 && isnumeric (varargin{2}))
+    limits = varargin{2};
+    if (iscomplex (limits) || (numel (limits) != 2 && numel (limits) != 4))
+      error ("fplot: LIMITS must be a real vector with 2 or 4 elements");
+    endif
+    i = 3;
+  else
+    limits = [-5, 5];
+    i = 2;
   endif
 
   n = 5;
   tol = 2e-3;
-  fmt = "";
-  for i = 1:numel (varargin)
+  fmt = {};
+  while (i <= numel (varargin))
     arg = varargin{i};
     if (ischar (arg))
-      fmt = arg;
+      [~, valid_fmt] = __pltopt__ ("fplot", arg, false); 
+      if (valid_fmt)
+        fmt(end+1) = arg;
+      else
+        if (i == numel (varargin))
+          error ("fplot: bad input in position %d", i);
+        endif
+        fmt(end+(1:2)) = varargin([i, i+1]); 
+        i++;  # Skip PROPERTY.
+      endif
     elseif (isnumeric (arg) && isscalar (arg) && arg > 0)
       if (arg == fix (arg))
         n = arg;
@@ -121,30 +140,35 @@
         tol = arg;
       endif
     else
-      error ("fplot: bad input in position %d", i+2);
+      error ("fplot: bad input in position %d", i);
     endif
-  endfor
+    i++;
+  endwhile
 
   if (n != 5)
     ## n was specified
     x0 = linspace (limits(1), limits(2), n/2 + 1)';
-    y0 = feval (fn, x0);
-    x = linspace (limits(1), limits(2), n)';
-    y = feval (fn, x);
   else
     x0 = linspace (limits(1), limits(2), 5)';
-    y0 = feval (fn, x0);
     n = 8;
-    x = linspace (limits(1), limits(2), n)';
-    y = feval (fn, x);
   endif
 
-  if (isscalar (y0))
-    warning ("fplot: FN is not a vectorized function which reduces performance");
+  try
+    y0 = feval (fn, x0);
+    if (isscalar (y0))
+      warning ("fplot: FN is not a vectorized function which reduces performance");
+      fn = @(x) arrayfun (fn, x);  # Create a new fn that accepts vectors
+      y0 = feval (fn, x0);
+    endif
+  catch
+    ## feval failed, maybe it is because the function is not vectorized?
     fn = @(x) arrayfun (fn, x);  # Create a new fn that accepts vectors
     y0 = feval (fn, x0);
-    y = feval (fn, x);
-  endif
+    warning ("fplot: FN is not a vectorized function which reduces performance");
+  end_try_catch
+
+  x = linspace (limits(1), limits(2), n)';
+  y = feval (fn, x);
 
   if (rows (x0) == rows (y0))
     fcn_transpose = false;
@@ -193,8 +217,10 @@
     if (isempty (hax))
       hax = gca ();
     endif
-    plot (hax, x, y, fmt);
+    plot (hax, x, y, fmt{:});
     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
@@ -248,16 +274,17 @@
 %! assert (y, repmat ([0], size (x)));
 
 ## Test input validation
-%!error fplot (1)
+%!error fplot ()
 %!error 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])
 %!error <LIMITS must be a real vector with 2 or 4> fplot (@cos, [1 2 3])
-%!error <bad input in position 3> fplot (@cos,[-1,1], {1})
+%!error <bad input in position 2> fplot (@cos, "linewidth")
+%!error <bad input in position 3> fplot (@cos, [-1,1], {1})
+%!warning <FN is not a vectorized function>
+%! fn = @(x) 0;
+%! [x,y] = fplot (fn, [-1,1]);
 %!error <invalid function FN>
 %! fn = @(x) [x;x];
 %! fplot (fn, [-1,1]);
-%!warning <FN is not a vectorized function>
-%! fn = @(x) 0;
-%! [x,y] = fplot (fn, [-1,1]);
--- a/scripts/plot/draw/light.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/light.m	Thu Dec 20 17:18:56 2018 -0500
@@ -1,4 +1,4 @@
-## Copyright (C) 2016-2018 Markus Muetzel
+## Copyright (C) 2016-2018 Markus Mützel
 ##
 ## This file is part of Octave.
 ##
@@ -26,13 +26,15 @@
 ## When a light object is present in an axes object, and the properties
 ## @qcode{"EdgeLighting"} or @qcode{"FaceLighting"} of a @code{patch} or
 ## @code{surface} object are set to a value other than @qcode{"none"}, these
-## objects are drawn with light and shadow effects.  Supported values for
-## Lighting properties are @qcode{"none"} (no lighting effects), @qcode{"flat"}
-## (faceted look of the objects), and @qcode{"gouraud"} (linear interpolation
-## of the lighting effects between the vertices).  For @code{patch} objects,
-## the normals must be set manually (property @qcode{"VertexNormals"}).
+## objects are drawn with lighting effects.  Supported values for Lighting
+## properties are @qcode{"none"} (no lighting effects), @qcode{"flat"} (faceted
+## look of the objects), and @qcode{"gouraud"} (linear interpolation of the
+## lighting effects between the vertices).  If the lighting mode is set to
+## @qcode{"flat"}, the @qcode{"FaceNormals"} property is used for lighting.
+## For @qcode{"gouraud"}, the @qcode{"VertexNormals"} property is used.
 ##
-## Up to eight light objects are supported per axes.
+## Up to eight light objects are supported per axes.  (Implementation
+## dependent)
 ##
 ## Lighting is only supported for OpenGL graphic toolkits (i.e., @qcode{"fltk"}
 ## and @qcode{"qt"}).
@@ -126,7 +128,7 @@
 %!  title ("Surface without lighting");
 
 %!demo
-%! ## Lighting modes
+%! ## Lighting modes on patches
 %! clf;
 %! [x,y,z] = meshgrid (-.2:0.05:.2, -.2:0.05:.2, -.2:0.05:.2);
 %! val = (x.^2 + y.^2 + z.^2);
@@ -135,20 +137,36 @@
 %! fv = isosurface (x, y, z, val, .039);
 %! h_patch = patch (fv, "FaceColor", "r", "EdgeColor", "none", ...
 %!                      "FaceLighting", "none");
-%! isonormals (x, y, z, val, h_patch);
 %! fv = isosurface (x+.5, y, z, val, .039);
 %! h_patch = patch (fv, "FaceColor", "r", "EdgeColor", "none", ...
 %!                      "FaceLighting", "flat");
-%! isonormals (x+.5, y, z, val, h_patch)
 %! fv = isosurface (x+1, y, z, val, .039);
 %! h_patch = patch (fv, "FaceColor", "r", "EdgeColor", "none", ...
 %!                      "FaceLighting", "Gouraud");
-%! isonormals (x+1, y, z, val, h_patch);
 %! axis tight
 %! axis equal
 %! view (2);
 %! light ("Position", [-1 1 1]);
-%! title ({"FaceLighting", "none - flat - gouraud"});
+%! title ({"FaceLighting on patches", "none - flat - gouraud"});
+
+%!demo
+%! ## Lighting modes on surfaces
+%! clf;
+%! Z = peaks ();
+%! [X, Y] = meshgrid (1:size (Z, 2), 1:size (Z, 1));
+%!
+%! 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", ...
+%!       "FaceLighting", "flat");
+%! surf (X + round(2.4 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
+%!       "FaceLighting", "gouraud");
+%! axis tight
+%! axis equal
+%! view (2);
+%! light ("Position", [-1 1 1]);
+%! title ({"FaceLighting on surfaces", "none - flat - gouraud"});
 
 %!demo
 %! ## multiple lights
--- a/scripts/plot/draw/line.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/line.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,18 +19,32 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} line ()
 ## @deftypefnx {} {} line (@var{x}, @var{y})
-## @deftypefnx {} {} line (@var{x}, @var{y}, @var{property}, @var{value}, @dots{})
 ## @deftypefnx {} {} line (@var{x}, @var{y}, @var{z})
-## @deftypefnx {} {} line (@var{x}, @var{y}, @var{z}, @var{property}, @var{value}, @dots{})
-## @deftypefnx {} {} line (@var{property}, @var{value}, @dots{})
+## @deftypefnx {} {} line ("xdata", @var{x}, "ydata", @var{y})
+## @deftypefnx {} {} line ("xdata", @var{x}, "ydata", @var{y}, "zdata", @var{z})
+## @deftypefnx {} {} line (@dots{}, @var{property}, @var{value})
 ## @deftypefnx {} {} line (@var{hax}, @dots{})
 ## @deftypefnx {} {@var{h} =} line (@dots{})
-## Create line object from @var{x} and @var{y} (and possibly @var{z}) and
-## insert in the current axes.
+## Create a line object from @var{x} and @var{y} (and possibly @var{z}) and
+## insert it in the current axes.
+##
+## In the standard calling form the data @var{x}, @var{y}, and @var{z} may be
+## scalars, vectors, or matrices.  In the case of matrix inputs, @code{line}
+## will attempt to orient scalars and vectors so the results can be plotted.
+## This requires that one of the dimensions of the vector match either the
+## number of rows or the number of columns of the matrix.
+## 
+## In the low-level calling form (50% higher performance) where the data is
+## specified by name (@code{line ("xdata", @var{x}, @dots{})}) the data must be
+## vectors.  If no data is specified (@code{line ()}) then
+## @w{@code{@var{x} == @var{y} = [0, 1]}}.
 ##
 ## Multiple property-value pairs may be specified for the line object, but they
 ## must appear in pairs.
 ##
+## If called with only @var{property}/@var{value} pairs then any unspecified
+## properties use their default values as specified on the root object.
+##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
@@ -39,6 +53,9 @@
 ##
 ## Programming Note: The full list of properties is documented at
 ## @ref{Line Properties,,Line Properties}.
+##
+## The function @code{line} differs from @code{plot} in that line objects are
+## inserted in to the current axes without first clearing the plot.
 ## @seealso{image, patch, rectangle, surface, text}
 ## @end deftypefn
 
--- a/scripts/plot/draw/patch.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/patch.m	Thu Dec 20 17:18:56 2018 -0500
@@ -252,6 +252,25 @@
 %! p = patch (x, y, [1 32]);
 %! title ("Autoscaling of colors: Red UL and Blue LR triangles");
 
+%!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;
+%! 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")
+
+
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
@@ -263,12 +282,22 @@
 %!   assert (isempty (get (h, "cdata")));
 %!   assert (get (h, "faces"), [1, 2, 3], eps);
 %!   assert (get (h, "vertices"), [0 1; 1 1; 0 0], eps);
+%!   assert (get (h, "facenormalsmode"), "auto");
+%!   assert (get (h, "facenormals"), get (0, "defaultpatchfacenormals"));
+%!   assert (get (h, "vertexnormalsmode"), "auto");
+%!   assert (get (h, "vertexnormals"), get (0, "defaultpatchvertexnormals"));
 %!   assert (get (h, "type"), "patch");
 %!   assert (get (h, "facecolor"), [0 0 0]);
 %!   assert (get (h, "linestyle"), get (0, "defaultpatchlinestyle"));
 %!   assert (get (h, "linewidth"), get (0, "defaultpatchlinewidth"), eps);
 %!   assert (get (h, "marker"), get (0, "defaultpatchmarker"));
 %!   assert (get (h, "markersize"), get (0, "defaultpatchmarkersize"));
+%!   hl = light;
+%!   assert (get (h, "facelighting"), "flat");
+%!   assert (get (h, "facenormals"), [0 0 1], eps);
+%!   assert (get (h, "vertexnormals"), []);
+%!   set (h, "facelighting", "gouraud")
+%!   assert (get (h, "vertexnormals"), [0 0 1; 0 0 1; 0 0 1], eps);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
--- a/scripts/plot/draw/pie.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/pie.m	Thu Dec 20 17:18:56 2018 -0500
@@ -60,6 +60,10 @@
     print_usage ();
   endif
 
+  if (! all (isfinite (varargin{1})))
+    error ("pie: all data in X must be finite");
+  endif
+
   oldfig = [];
   if (! isempty (hax))
     oldfig = get (0, "currentfigure");
@@ -100,3 +104,8 @@
 %! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]);
 %! axis ([-2,2,-2,2]);
 %! title ("pie() with missing slice");
+
+## Test input validation
+%!error 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	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/pie3.m	Thu Dec 20 17:18:56 2018 -0500
@@ -61,6 +61,10 @@
     print_usage ();
   endif
 
+  if (! all (isfinite (varargin{1})))
+    error ("pie3: all data in X must be finite");
+  endif
+
   oldfig = [];
   if (! isempty (hax))
     oldfig = get (0, "currentfigure");
@@ -100,3 +104,8 @@
 %! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]);
 %! axis ([-2,2,-2,2]);
 %! title ("pie3() with missing slice");
+
+## Test input validation
+%!error 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/plot3.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/plot3.m	Thu Dec 20 17:18:56 2018 -0500
@@ -213,9 +213,10 @@
             color = __next_line_color__ ();
           endif
 
-          htmp(++idx) = line (x(:, i), y(:, i), z(:, i),
-                              "color", color, "linestyle", linestyle,
-                              "marker", marker, properties{:});
+          htmp(++idx) = __go_line__ (hax, "xdata", x(:, i), "ydata", y(:, i),
+                                     "zdata", z(:, i),
+                                     "color", color, "linestyle", linestyle,
+                                     "marker", marker, properties{:});
           key = options.key;
           if (! isempty (key))
             hlgnd = [hlgnd, htmp(idx)];
@@ -268,9 +269,10 @@
             color = __next_line_color__ ();
           endif
 
-          htmp(++idx) = line (x(:, i), y(:, i), z(:, i),
-                              "color", color, "linestyle", linestyle,
-                              "marker", marker, properties{:});
+          htmp(++idx) = __go_line__ (hax, "xdata", x(:, i), "ydata", y(:, i),
+                                     "zdata", z(:, i),
+                                     "color", color, "linestyle", linestyle,
+                                     "marker", marker, properties{:});
           key = options.key;
           if (! isempty (key))
             hlgnd = [hlgnd, htmp(idx)];
@@ -343,9 +345,10 @@
           color = __next_line_color__ ();
         endif
 
-        htmp(++idx) = line (x(:, i), y(:, i), z(:, i),
-                            "color", color, "linestyle", linestyle,
-                            "marker", marker, properties{:});
+        htmp(++idx) = __go_line__ (hax, "xdata", x(:, i), "ydata", y(:, i),
+                                   "zdata", z(:, i),
+                                   "color", color, "linestyle", linestyle,
+                                   "marker", marker, properties{:});
         key = options.key;
         if (! isempty (key))
           hlgnd = [hlgnd, htmp(idx)];
--- a/scripts/plot/draw/private/__bar__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__bar__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -282,8 +282,9 @@
     if (i == 1)
       ## Add baseline object the first time through loop
       x_axis_range = get (hax, "xlim");
-      h_baseline = line (hax, x_axis_range, [base_value, base_value],
-                             "color", [0, 0, 0]);
+      h_baseline = __go_line__ (hax, "xdata", x_axis_range,
+                                     "ydata", [base_value, base_value],
+                                     "color", [0, 0, 0]);
       set (h_baseline, "handlevisibility", "off", "xliminclude", "off");
       set (h_baseline, "parent", get (hg, "parent"));
     endif
--- a/scripts/plot/draw/private/__ezplot__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__ezplot__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -103,7 +103,7 @@
       xarg = argids{1};
       yarg = argids{2};
     endif
-  elseif (isa (fun, "function_handle"))
+  elseif (is_function_handle (fun))
     fstr = func2str (fun);
     idx = index (fstr, ')');
     if (idx != 0)
@@ -165,7 +165,7 @@
       endif
       funy = vectorize (funy);
       fstry = formula (funy);
-    elseif (isa (funy, "function_handle"))
+    elseif (is_function_handle (funy))
       parametric = true;
       fstry = func2str (funy);
       idx = index (fstry, ')');
@@ -209,7 +209,7 @@
         endif
         funz = vectorize (funz);
         fstrz = formula (funz);
-      elseif (isa (funz, "function_handle"))
+      elseif (is_function_handle (funz))
         fstrz = func2str (funz);
         idx = index (fstrz, ')');
         if (idx != 0)
--- a/scripts/plot/draw/private/__line__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__line__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,20 +17,22 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{h} =} __line__ (@var{p}, @dots{})
-## Undocumented internal function.
+## @deftypefn {} {@var{h} =} __line__ (@var{parent}, @dots{})
+## Create line object with parent @var{parent}.
+##
+## Return handle @var{h} to created line objects.
 ## @end deftypefn
 
-## __line__ (p, x, y, z)
+## __line__ (hp, x, y, z)
 ## Create line object from x, y, and z with parent p.
 ## Return handle to line object.
 
 ## Author: jwe
 
-function h = __line__ (p, varargin)
+function h = __line__ (hp, varargin)
 
-  nvargs = numel (varargin);
-
+  nvargs = nargin - 1;     # remove argument 'hp'
+  have_data_prop = false;
   if (nvargs > 1 && ! ischar (varargin{1}) && ! ischar (varargin{2}))
     if (nvargs > 2 && ! ischar (varargin{3}))
       num_data_args = 3;
@@ -39,19 +41,9 @@
     endif
   else
     num_data_args = 0;
-  endif
-
-  if (num_data_args > 0 && ! size_equal (varargin{1:num_data_args}))
-    n = 1:num_data_args;
-    m = cellfun (@numel, varargin(1:num_data_args));
-    [~, m] = max (m);
-    b = ones (size (varargin{m(1)}));
-    try
-      varargin(n) = cellfun (@(x) bsxfun (@times, b, x), varargin(n),
-                             "uniformoutput", false);
-    catch
-      error ("line: number of X, Y, and Z points must be equal");
-    end_try_catch
+    if (any (strcmpi ("xdata", varargin(1:2:end))))
+      have_data_prop = true;
+    endif
   endif
 
   if (rem (nvargs - num_data_args, 2) != 0)
@@ -63,64 +55,103 @@
     other_args = varargin(num_data_args+1:end);
   endif
 
-  nlines = 0;
-  nvecpts = 0;
-  ismat = false (1, 3);
-  for i = 1:num_data_args
-    tmp = varargin{i}(:,:);
-    if (isvector (tmp))
-      nlines = max (1, nlines);
-      if (! isscalar (tmp))
-        if (nvecpts == 0)
-          nvecpts = numel (tmp);
-        elseif (nvecpts != numel (tmp))
-          error ("line: data size mismatch");
+  if (num_data_args == 0)
+    if (have_data_prop)
+      ## Low-level calling form with a single line
+      handles(1) = __go_line__ (hp, other_args{:});
+    else
+      ## line called without any data, use default data.
+      handles(1) = __go_line__ (hp, "xdata", [0, 1], "ydata", [0, 1],
+                                    other_args{:});
+    endif
+  else
+    ## Normal case, extract and validate input data args
+    ismat = false (1,3);
+
+    ## Initialize loop variables
+    tmpdata = varargin{1}(:,:);  # N-D arrays -> 2-D arrays
+    if (isvector (tmpdata))
+      tmpdata = tmpdata(:);      # Use column vectors by default
+    else
+      ismat(1) = true;
+    endif
+    [nr, nc] = size (tmpdata);
+    if (islogical (tmpdata))
+      tmpdata = uint8 (tmpdata);
+    elseif (iscomplex (tmpdata))
+      tmpdata = real (tmpdata);
+    endif
+    varargin{1} = tmpdata;
+    reorient_done = false;
+
+    for i = 2:num_data_args
+      tmpdata = varargin{i}(:,:);  # N-D arrays -> 2-D arrays
+
+      if (isvector (tmpdata))
+        tmpdata = tmpdata(:);      # Use column vectors by default
+        [r, c] = size (tmpdata);
+        if (nr == r)
+          ## Do nothing, properly oriented
+        elseif (nc == r && nc > 1 && ! reorient_done)
+          ## Re-orient first matrix
+          varargin{i-1} = varargin{i-1}.';
+          [nr, nc] = deal (nc, nr);  # swap rows and columns.
+          reorient_done = true;
+        else
+          error ("line: number of X, Y, and Z points must be equal");
+        endif
+      else
+        ismat(i) = true;
+        [r, c] = size (tmpdata);
+        if (nr == r && (nc == c || nc == 1))
+          ## Do nothing, properly oriented
+          nc = max (nc, c);
+        elseif (nr == c)
+          tmpdata = tmpdata.';
+          [nr, nc] = deal (c, r);  # swap rows and columns.
+        else
+          error ("line: number of X, Y, and Z points must be equal");
         endif
       endif
-    else
-      ismat(i) = true;
-      nlines = max (columns (tmp), nlines);
-    endif
-    varargin{i} = tmp;
-  endfor
+
+      ## Convert logical or complex inputs
+    if (islogical (tmpdata))
+        tmpdata = uint8 (tmpdata);
+      elseif (iscomplex (tmpdata))
+        tmpdata = real (tmpdata);
+      endif
+      varargin{i} = tmpdata;
 
-  if (num_data_args == 0)
-    varargin = {[0, 1], [0, 1]};
-    num_data_args = 2;
-    nlines = 1;
-  endif
+    endfor
+
+    nlines = nc;
+
+    data = cell (1, 3);
+    data(1:num_data_args) = varargin(1:num_data_args);
+    data_args = {"xdata", data{1}, "ydata", data{2}, "zdata", data{3}};
+    mask = [false, ismat(1), false, ismat(2), false, ismat(3)];
 
-  handles = zeros (nlines, 1);
-
-  data = cell (1, 3);
+    handles = zeros (nlines, 1);
+    for i = 1:nlines
+      data_args(mask) = cellindexmat (data(ismat), ":", i);
 
-  if (num_data_args > 1)
-    data(1:num_data_args) = varargin(1:num_data_args);
-    for i = 1:num_data_args
-      if (islogical (data{i}))
-        data(i) = double (data{i});
-      elseif (iscomplex (data{i}))
-        data(i) = real (data{i});
+      ## FIXME: Technically, it may not be the right thing to do to rotate
+      ##        the style if the options in other_args specify a color
+      ##        or linestyle.  The plot will be made correctly, but the next
+      ##        call to line may not use the correct value.
+      [linestyle, marker] = __next_line_style__ ();
+      if (nr == 1)
+        ## Marker for a single point is always '.' (bug #38825).
+        marker = '.';
       endif
+      color = __next_line_color__ ();
+
+      handles(i) = __go_line__ (hp, data_args{:},
+                                "color", color, "linestyle", linestyle,
+                                "marker", marker, other_args{:});
     endfor
   endif
 
-  data_args = reshape ({"xdata", "ydata", "zdata"; data{:}}, [1, 6]);
-  mask = reshape ([false(1,3); ismat], [1, 6]);
-
-  for i = 1:nlines
-    tmp = data(ismat);
-    if (! size_equal (tmp)
-        || (nvecpts != 0 && any (nvecpts != cellfun ("size", tmp, 1))))
-      error ("line: data size_mismatch");
-    endif
-    data_args(mask) = cellfun (@(x) x(:,i), data(ismat),
-                               "uniformoutput", false);
-
-    handles(i) = __go_line__ (p, data_args{:}, other_args{:});
-
-  endfor
-
   if (nargout > 0)
     h = handles;
   endif
--- a/scripts/plot/draw/private/__pie__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__pie__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -131,8 +131,10 @@
     elseif (strcmp (caller, "pie"))
       if (xt > 0)
         align = "left";
+      elseif (xt < 0)
+        align = "right";
       else
-        align = "right";
+        align = "center";
       endif
 
       hlist = [hlist; patch(xoff + [0, -sind(xn)], yoff + [0, cosd(xn)], i);
--- a/scripts/plot/draw/private/__plt__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__plt__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,13 +17,13 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {} __plt__ (@var{caller}, @var{h}, @var{varargin})
+## @deftypefn {} {} __plt__ (@var{caller}, @var{hparent}, @var{varargin})
 ## Undocumented internal function.
 ## @end deftypefn
 
 ## Author: jwe
 
-function retval = __plt__ (caller, h, varargin)
+function retval = __plt__ (caller, hp, varargin)
 
   persistent warned_callers = {};
   nargs = nargin - 2;
@@ -39,7 +39,7 @@
 
     ## Find any legend associated with this axes
     try
-      hlegend = get (h, "__legend_handle__");
+      hlegend = get (hp, "__legend_handle__");
     catch
       hlegend = [];
     end_try_catch
@@ -104,17 +104,17 @@
             endwhile
           endif
           if (y_set)
-            tmp = __plt2__ (h, x, y, options, properties);
+            htmp = __plt2__ (hp, x, y, options, properties);
             [hlgnd, tlgnd, setlgnd] = ...
-              __plt_key__ (tmp, options, hlgnd, tlgnd, setlgnd);
+              __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
             properties = {};
-            retval = [retval; tmp];
+            retval = [retval; htmp];
           else
-            tmp = __plt1__ (h, x, options, properties);
+            htmp = __plt1__ (hp, x, options, properties);
             [hlgnd, tlgnd, setlgnd] = ...
-               __plt_key__ (tmp, options, hlgnd, tlgnd, setlgnd);
+               __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
             properties = {};
-            retval = [retval; tmp];
+            retval = [retval; htmp];
           endif
           x_set = false;
           y_set = false;
@@ -124,10 +124,10 @@
       elseif (x_set)
         if (y_set)
           options = __pltopt__ (caller, {""});
-          tmp = __plt2__ (h, x, y, options, properties);
+          htmp = __plt2__ (hp, x, y, options, properties);
           [hlgnd, tlgnd, setlgnd] = ...
-            __plt_key__ (tmp, options, hlgnd, tlgnd, setlgnd);
-          retval = [retval; tmp];
+            __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+          retval = [retval; htmp];
           x = next_arg;
           y_set = false;
           properties = {};
@@ -151,9 +151,9 @@
 
 endfunction
 
-function [hlgnd, tlgnd, setlgnd] = __plt_key__ (h, options,
+function [hlgnd, tlgnd, setlgnd] = __plt_key__ (hp, options,
                                                 hlgnd, tlgnd, setlgnd)
-  n = numel (h);
+  n = numel (hp);
   if (numel (options) == 1)
     options = repmat (options(:), n, 1);
   endif
@@ -161,7 +161,7 @@
   for i = 1 : n
     key = options(i).key;
     if (! isempty (key))
-      hlgnd = [hlgnd(:); h(i)];
+      hlgnd = [hlgnd(:); hp(i)];
       tlgnd = {tlgnd{:}, key};
       setlgnd = true;
     endif
@@ -169,7 +169,7 @@
 
 endfunction
 
-function retval = __plt1__ (h, x1, options, properties = {})
+function retval = __plt1__ (hp, x1, options, properties = {})
 
   if (nargin < 3 || isempty (options))
     options = __default_plot_options__ ();
@@ -198,11 +198,11 @@
     x1 = (1:nr)';
   endif
 
-  retval = __plt2__ (h, x1, x2, options, properties);
+  retval = __plt2__ (hp, x1, x2, options, properties);
 
 endfunction
 
-function retval = __plt2__ (h, x1, x2, options, properties = {})
+function retval = __plt2__ (hp, x1, x2, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -229,27 +229,27 @@
     retval = zeros (0, 1);
   elseif (isscalar (x1))
     if (isscalar (x2))
-      retval = __plt2ss__ (h, x1, x2, options, properties);
+      retval = __plt2ss__ (hp, x1, x2, options, properties);
     elseif (isvector (x2))
-      retval = __plt2sv__ (h, x1, x2, options, properties);
+      retval = __plt2sv__ (hp, x1, x2, options, properties);
     else
       error ("__plt2__: invalid data for plotting");
     endif
   elseif (isvector (x1))
     if (isscalar (x2))
-      retval = __plt2vs__ (h, x1, x2, options, properties);
+      retval = __plt2vs__ (hp, x1, x2, options, properties);
     elseif (isvector (x2))
-      retval = __plt2vv__ (h, x1, x2, options, properties);
+      retval = __plt2vv__ (hp, x1, x2, options, properties);
     elseif (ismatrix (x2))
-      retval = __plt2vm__ (h, x1, x2, options, properties);
+      retval = __plt2vm__ (hp, x1, x2, options, properties);
     else
       error ("__plt2__: invalid data for plotting");
     endif
   elseif (ismatrix (x1))
     if (isvector (x2))
-      retval = __plt2mv__ (h, x1, x2, options, properties);
+      retval = __plt2mv__ (hp, x1, x2, options, properties);
     elseif (ismatrix (x2))
-      retval = __plt2mm__ (h, x1, x2, options, properties);
+      retval = __plt2mm__ (hp, x1, x2, options, properties);
     else
       error ("__plt2__: invalid data for plotting");
     endif
@@ -259,7 +259,7 @@
 
 endfunction
 
-function retval = __plt2mm__ (h, x, y, options, properties = {})
+function retval = __plt2mm__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -287,14 +287,14 @@
       color = __next_line_color__ ();
     endif
 
-    retval(i) = line (x(:,i), y(:,i), "color", color,
-                      "linestyle", linestyle,
-                      "marker", marker, properties{:});
+    retval(i) = __go_line__ (hp, "xdata", x(:,i), "ydata", y(:,i),
+                             "color", color, "linestyle", linestyle,
+                             "marker", marker, properties{:});
   endfor
 
 endfunction
 
-function retval = __plt2mv__ (h, x, y, options, properties = {})
+function retval = __plt2mv__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -328,14 +328,14 @@
       color = __next_line_color__ ();
     endif
 
-    retval(i) = line (x(:,i), y, "color", color,
-                      "linestyle", linestyle,
-                      "marker", marker, properties{:});
+    retval(i) = __go_line__ (hp, "xdata", x(:,i), "ydata", y,
+                             "color", color, "linestyle", linestyle,
+                             "marker", marker, properties{:});
   endfor
 
 endfunction
 
-function retval = __plt2ss__ (h, x, y, options, properties = {})
+function retval = __plt2ss__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -357,13 +357,12 @@
     color = __next_line_color__ ();
   endif
 
-  retval = line (x, y, "color", color,
-                 "linestyle", linestyle,
-                 "marker", marker, properties{:});
-
+  retval = __go_line__ (hp, "xdata", x, "ydata", y,
+                        "color", color, "linestyle", linestyle,
+                        "marker", marker, properties{:});
 endfunction
 
-function retval = __plt2sv__ (h, x, y, options, properties = {})
+function retval = __plt2sv__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -387,14 +386,14 @@
       color = __next_line_color__ ();
     endif
 
-    retval(i) = line (x, y(i), "color", color,
-                      "linestyle", linestyle,
-                      "marker", marker, properties{:});
+    retval(i) = __go_line__ (hp, "xdata", x, "ydata", y(i),
+                             "color", color, "linestyle", linestyle,
+                             "marker", marker, properties{:});
   endfor
 
 endfunction
 
-function retval = __plt2vm__ (h, x, y, options, properties = {})
+function retval = __plt2vm__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -428,14 +427,14 @@
       color = __next_line_color__ ();
     endif
 
-    retval(i) = line (x, y(:,i), "color", color,
-                      "linestyle", linestyle,
-                      "marker", marker, properties{:});
+    retval(i) = __go_line__ (hp, "xdata", x, "ydata", y(:,i),
+                             "color", color, "linestyle", linestyle,
+                             "marker", marker, properties{:});
   endfor
 
 endfunction
 
-function retval = __plt2vs__ (h, x, y, options, properties = {})
+function retval = __plt2vs__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -459,14 +458,14 @@
       color = __next_line_color__ ();
     endif
 
-    retval(i) = line (x(i), y, "color", color,
-                      "linestyle", linestyle,
-                      "marker", marker, properties{:});
+    retval(i) = __go_line__ (hp, "xdata", x(i), "ydata", y,
+                             "color", color, "linestyle", linestyle,
+                             "marker", marker, properties{:});
   endfor
 
 endfunction
 
-function retval = __plt2vv__ (h, x, y, options, properties = {})
+function retval = __plt2vv__ (hp, x, y, options, properties = {})
 
   if (nargin < 4 || isempty (options))
     options = __default_plot_options__ ();
@@ -493,8 +492,8 @@
     color = __next_line_color__ ();
   endif
 
-  retval = line (x, y, "color", color,
-                 "linestyle", linestyle,
-                 "marker", marker, properties{:});
+  retval = __go_line__ (hp, "xdata", x, "ydata", y,
+                        "color", color, "linestyle", linestyle,
+                        "marker", marker, properties{:});
 
 endfunction
--- a/scripts/plot/draw/private/__scatter__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__scatter__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -36,6 +36,25 @@
     istart = 7;
   endif
 
+  ## Force mixtures of int and float data to be float (Bug #4116).
+  if (xor (isfloat (x), isfloat (y)))
+    if (isfloat (x))
+      y = cast (y, class (x));
+    else
+      x = cast (x, class (y));
+    endif
+  endif
+  if (nd != 2)
+    if (xor (isfloat (x), isfloat (z)))
+      if (isfloat (x))
+        z = cast (z, class (x));
+      else
+        x = cast (x, class (z));
+        y = cast (y, class (z));
+      endif
+    endif
+  endif
+
   if (istart <= nargin)
     s = varargin{istart}(:);
     if (isempty (s) || ischar (s))
--- a/scripts/plot/draw/private/__stem__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/private/__stem__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -99,7 +99,9 @@
 
         x_axis_range = get (hax, "xlim");
         if (isempty (h_baseline))
-          h_baseline = line (hax, x_axis_range, [0, 0], "color", [0, 0, 0]);
+          h_baseline = __go_line__ (hax, "xdata", x_axis_range,
+                                         "ydata", [0, 0],
+                                         "color", [0, 0, 0]);
           set (h_baseline, "handlevisibility", "off", "xliminclude", "off");
           addproperty ("basevalue", h_baseline, "data", 0);
         else
@@ -445,7 +447,7 @@
     x = x(1:sz(1),1:sz(2));
     y = y(1:sz(1),1:sz(2));
     z = z(1:sz(1),1:sz(2));
-  elseif (numel (x) != numel (y));
+  elseif (numel (x) != numel (y))
     sz = min ([size(x); size(y)]);
     x = x(1:sz(1),1:sz(2));
     y = y(1:sz(1),1:sz(2));
--- a/scripts/plot/draw/stemleaf.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/stemleaf.m	Thu Dec 20 17:18:56 2018 -0500
@@ -155,12 +155,11 @@
   if (nargin == 2)
     stem_step = 10;
   else
-    if (isscalar (stem_sz) && stem_sz >= 0 && isreal (stem_sz))
-      stem_sz = fix (stem_sz);
-      stem_step = 10^(stem_sz+1);
-    else
+    if (! (isscalar (stem_sz) && stem_sz >= 0 && isreal (stem_sz)))
       error ("stemleaf: STEM_SZ must be a real integer >= 0");
     endif
+    stem_sz = fix (stem_sz);
+    stem_step = 10^(stem_sz+1);
   endif
 
   ## Note that IEEE 754 states that -+ 0 should compare equal.  This has
@@ -246,7 +245,7 @@
   ## Vectorized version provided by Rik Wehbring (rik@octave.org)
   ## Determine leaves for each stem:
   new_line = 1;
-  for kx = 2: numel (stems)
+  for kx = 2 : numel (stems)
 
     stem_sign = signbit (stems(kx));
     if (stems(kx) <= 0)
--- a/scripts/plot/draw/surfl.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/draw/surfl.m	Thu Dec 20 17:18:56 2018 -0500
@@ -38,13 +38,14 @@
 ##
 ## The default lighting mode @qcode{"cdata"}, changes the cdata property of the
 ## surface object to give the impression of a lighted surface.
-## @strong{Warning:} The alternative mode @qcode{"light"} mode which creates a
-## light object to illuminate the surface is not implemented (yet).
+##
+## The alternate mode @qcode{"light"} creates a light object to illuminate the
+## surface.
 ##
-## The light source location can be specified using @var{lsrc}.  It can be
-## given as a 2-element vector [azimuth, elevation] in degrees, or as a
-## 3-element vector [lx, ly, lz].  The default value is rotated 45 degrees
-## counterclockwise to the current view.
+## The light source location may be specified using @var{lsrc} which can be
+## a 2-element vector [azimuth, elevation] in degrees, or a 3-element vector
+## [lx, ly, lz].  The default value is rotated 45 degrees counterclockwise to
+## the current view.
 ##
 ## The material properties of the surface can specified using a 4-element
 ## vector @var{P} = [@var{AM} @var{D} @var{SP} @var{exp}] which defaults to
@@ -93,8 +94,6 @@
   if (ischar (varargin{end}))
     switch (tolower (varargin{end}))
       case "light"
-        warning ("surfl: light method not supported (yet), using cdata method instead");
-        ## This can be implemented when light objects are supported.
         use_cdata = false;
       case "cdata"
         use_cdata = true;
@@ -110,7 +109,8 @@
   ##      diffuse reflection strength,
   ##      specular reflection strength,
   ##      specular shine]
-  if (isnumeric (varargin{end}) && length (varargin{end}) == 4)
+  if (isnumeric (varargin{end}) && isvector (varargin{end})
+      && (numel (varargin{end}) == 4))
     r = varargin{end};
     varargin(end) = [];
   else
@@ -120,7 +120,7 @@
 
   ## Check for light vector (lv) argument.
   have_lv = false;
-  if (isnumeric (varargin{end}))
+  if (isnumeric (varargin{end}) && isvector (varargin{end}))
     len = numel (varargin{end});
     lastarg = varargin{end};
     if (len == 3)
@@ -146,7 +146,7 @@
     htmp = surface (varargin{:});
     if (! ishold ())
       set (hax, "view", [-37.5, 30],
-                "xgrid", "on", "ygrid", "on", "zgrid", "on", "clim", [0 1]);
+                "xgrid", "on", "ygrid", "on", "zgrid", "on");
     endif
 
     ## Get view vector (vv).
@@ -162,23 +162,32 @@
       lv = (R * vv.').';
     endif
 
-    vn = get (htmp, "vertexnormals");
-    dar = get (hax, "dataaspectratio");
-    vn(:,:,1) *= dar(1);
-    vn(:,:,2) *= dar(2);
-    vn(:,:,3) *= dar(3);
+    if (use_cdata)
+      set (hax, "clim", [0 1]);
+
+      __update_normals__ (htmp);
+      vn = get (htmp, "vertexnormals");
+      dar = get (hax, "dataaspectratio");
+      vn(:,:,1) *= dar(1);
+      vn(:,:,2) *= dar(2);
+      vn(:,:,3) *= dar(3);
 
-    ## Normalize vn.
-    vn ./= repmat (sqrt (sumsq (vn, 3)), [1, 1, 3]);
-    [nr, nc] = size (get (htmp, "zdata"));
+      ## Normalize vn.
+      vn ./= repmat (sqrt (sumsq (vn, 3)), [1, 1, 3]);
+      [nr, nc] = size (get (htmp, "zdata"));
 
-    ## Ambient, diffuse, and specular term.
-    cdata = (  r(1) * ones (nr, nc)
-             + r(2) * diffuse  (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv)
-             + r(3) * specular (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv, vv, r(4)));
-    cdata ./= sum (r(1:3));
+      ## Ambient, diffuse, and specular term.
+      cdata = (  r(1) * ones (nr, nc)
+               + r(2) * diffuse  (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv)
+               + r(3) * specular (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv, vv, r(4)));
+      cdata ./= sum (r(1:3));
 
-    set (htmp, "cdata", cdata);
+      set (htmp, "cdata", cdata);
+    else
+      light (hax, "position", lv);
+      set (htmp, "ambientstrength", r(1), "diffusestrength", r(2), ...
+                 "specularstrength", r(3), "specularexponent", r(4));
+    endif
 
   unwind_protect_cleanup
     if (! isempty (oldfig))
@@ -208,3 +217,11 @@
 %! surfl (X,Y,Z, [62.50,30], [0.2 0.6 0.4 25]);
 %! shading interp;
 %! title ("surfl() with lighting vector and material properties");
+
+%!demo
+%! clf;
+%! [X, Y] = meshgrid (-3:1/8:3);
+%! Z = peaks (X, Y);
+%! surfl (X, Y, Z, "light");
+%! shading interp;
+%! title ("surfl() with light object");
--- a/scripts/plot/util/__actual_axis_position__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/__actual_axis_position__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -68,7 +68,7 @@
     orig_aspect_ratio_2d = pos_in_pixels(3:4);
     rel_aspect_ratio_2d = aspect_ratio_2d ./ orig_aspect_ratio_2d;
     rel_aspect_ratio_2d ./= max (rel_aspect_ratio_2d);
-    if (rel_aspect_ratio_2d(1) < rel_aspect_ratio_2d(2));
+    if (rel_aspect_ratio_2d(1) < rel_aspect_ratio_2d(2))
       dx = (1.0 - rel_aspect_ratio_2d(1)) * pos_in_pixels(3);
       pos_in_pixels += dx*[0.5, 0.0, -1.0, 0.0];
     elseif (rel_aspect_ratio_2d(1) > rel_aspect_ratio_2d(2))
--- a/scripts/plot/util/__gnuplot_drawnow__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/__gnuplot_drawnow__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -146,15 +146,15 @@
       if (output_to_screen (term) && ! strcmp (term, "dumb"))
         fig.numbertitle = get (h, "numbertitle");
         fig.name = strrep (get (h, "name"), '"', '\"');
-        if (strcmp (get (h, "numbertitle"), "on"))
+        if (! isempty (get (h, "number")) && strcmp (get (h, "numbertitle"), "on"))
           title_str = sprintf ("Figure %d", h);
+          if (! isempty (fig.name))
+            title_str = sprintf ("%s: %s", title_str, fig.name);
+          endif
+        elseif (! isempty (fig.name))
+          title_str = fig.name;
         else
-          title_str = "";
-        endif
-        if (! isempty (fig.name) && ! isempty (title_str))
-          title_str = sprintf ("%s: %s", title_str, fig.name);
-        elseif (! isempty (fig.name) && isempty (title_str))
-          title_str = fig.name;
+          title_str = " ";
         endif
         if (! isempty (title_str))
           title_str = sprintf ('title "%s"', title_str);
--- a/scripts/plot/util/__pltopt__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/__pltopt__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -63,7 +63,7 @@
 ## @item ";title;"
 ## Here @code{"title"} is the label for the key.
 ##
-## @item "+"
+## @item  "+"
 ## @itemx "o"
 ## @itemx "*"
 ## @itemx "."
--- a/scripts/plot/util/allchild.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/allchild.m	Thu Dec 20 17:18:56 2018 -0500
@@ -54,7 +54,7 @@
 %! unwind_protect
 %!   l = line;
 %!   kids = allchild (hf);
-%!   assert (get (kids, "type"), {"axes"; "uimenu"; "uimenu"});
+%!   assert (get (kids, "type"), {"axes"; "uimenu"; "uimenu"; "uimenu"});
 %! unwind_protect_cleanup
 %!   close (hf);
 %!   graphics_toolkit (toolkit);
--- a/scripts/plot/util/axes.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/axes.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,13 +19,16 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} axes ()
 ## @deftypefnx {} {} axes (@var{property}, @var{value}, @dots{})
+## @deftypefnx {} {} axes (@var{hpar}, @var{property}, @var{value}, @dots{})
 ## @deftypefnx {} {} axes (@var{hax})
 ## @deftypefnx {} {@var{h} =} axes (@dots{})
 ## Create a Cartesian axes object and return a handle to it, or set the current
 ## axes to @var{hax}.
 ##
 ## Called without any arguments, or with @var{property}/@var{value} pairs,
-## construct a new axes.
+## construct a new axes.  The optional argument @var{hpar} is a graphics handle
+## specifying the parent for the new axes and may be a figure, uipanel, or
+## uitab.
 ##
 ## Called with a single axes handle argument @var{hax}, the function makes
 ## @var{hax} the current axes (as returned by @code{gca}).  It also makes
@@ -41,12 +44,42 @@
 ## @seealso{gca, set, get}
 ## @end deftypefn
 
-## Author: jwe
-
 function h = axes (varargin)
 
-  if (nargin == 0 || nargin > 1)
-    ## Parent handle
+  htmp = hpar = [];
+  if (nargin > 0)
+    if (ishghandle (varargin{1}(1)))
+      htmp = varargin{1};
+      if (! isscalar (htmp))
+        error ("axes: H must be a scalar handle");
+      endif
+      typ = get (htmp, "type");
+      if (strcmp (typ, "axes") && nargin == 1)
+        cf = ancestor (htmp, "figure");
+        if (__is_handle_visible__ (htmp))
+          set (0, "currentfigure", cf);
+          set (cf, "currentaxes", htmp);
+        endif
+        restack_axes (htmp, get (htmp, "parent"));
+
+        if (nargout > 0)
+          h = htmp;
+        endif
+        return;
+
+      elseif (any (strcmp (typ, {"figure", "uipanel", "uitab"})))
+        hpar = htmp;
+        htmp = [];
+        varargin(1) = [];
+
+      else
+        error ("axes: H must be a handle to an axes or container");
+      endif
+    endif
+  endif
+
+  if (isempty (hpar))
+    ## Find a parent if not given as first argument.
     idx = find (strcmpi (varargin(1:2:end), "parent"), 1, "first");
     if (! isempty (idx) && numel (varargin) >= 2*idx)
       hpar = varargin{2*idx};
@@ -54,49 +87,34 @@
     else
       hpar = gcf ();
     endif
+  endif
 
-    ## If there is an annotation axes currently on top of the children stack,
-    ## then it must be placed back on top.
-    ## FIXME: It may be necessary to keep uiXXX objects above all axes objects
-    ##        including even the transparent scribe axes layer.
-    ch = allchild (hpar);
-    h_annotation = ch(strcmp (get (ch, "tag"), "scribeoverlay"));
-
-    ## Create an axes object.
-    htmp = __go_axes__ (hpar, varargin{:});
-    if (__is_handle_visible__ (htmp))
-      set (ancestor (hpar, "figure"), "currentaxes", htmp);
-    endif
+  ## If there is an annotation axes currently on top of the children stack,
+  ## then it must be placed back on top.
+  ## FIXME: It may be necessary to keep uiXXX objects above all axes objects
+  ##        including even the transparent scribe axes layer.
+  ch = allchild (hpar);
+  h_annotation = ch(strcmp (get (ch, "tag"), "scribeoverlay"));
 
-    ## Restack annotation object if necessary
-    if (! isempty (h_annotation))
-      ## FIXME: This will put annotation layer first, above even uicontrol
-      ## objects.  May need to keep annotation layer above all axes only.
-      shh = get (0, "ShowHiddenHandles");
-      unwind_protect
-        set (0, "ShowHiddenHandles", "on");
-        ch(ch == h_annotation) = htmp;
-        ch = [h_annotation; ch];
-        set (hpar, "children", ch);
-      unwind_protect_cleanup
-        set (0, "ShowHiddenHandles", shh);
-      end_unwind_protect
-    endif
+  ## Create an axes object.
+  htmp = __go_axes__ (hpar, varargin{:});
+  if (__is_handle_visible__ (htmp))
+    set (ancestor (hpar, "figure"), "currentaxes", htmp);
+  endif
 
-  else
-    ## ARG is axes handle.
-    htmp = varargin{1};
-    if (! isscalar (htmp) || ! isaxes (htmp))
-      error ("axes: H must be a scalar axes handle");
-    endif
-
-    cf = ancestor (htmp, "figure");
-    if (__is_handle_visible__ (htmp))
-      set (0, "currentfigure", cf);
-      set (cf, "currentaxes", htmp);
-    endif
-
-    restack_axes (htmp, get (htmp, "parent"));
+  ## Restack annotation object if necessary
+  if (! isempty (h_annotation))
+    ## FIXME: This will put annotation layer first, above even uicontrol
+    ## objects.  May need to keep annotation layer above all axes only.
+    shh = get (0, "ShowHiddenHandles");
+    unwind_protect
+      set (0, "ShowHiddenHandles", "on");
+      ch(ch == h_annotation) = htmp;
+      ch = [h_annotation; ch];
+      set (hpar, "children", ch);
+    unwind_protect_cleanup
+      set (0, "ShowHiddenHandles", shh);
+    end_unwind_protect
   endif
 
   if (nargout > 0)
@@ -292,3 +310,6 @@
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
+
+%!error <H must be a scalar handle> axes ([0, 0])
+%!error <H must be a handle to an axes or container> axes (0)
--- a/scripts/plot/util/clf.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/clf.m	Thu Dec 20 17:18:56 2018 -0500
@@ -70,10 +70,17 @@
   endif
 
   if (do_reset)
-    ## Select all the children, including the one with hidden handles.
-    delete (allchild (hfig));
+    ## Delete all the children, including the ones with hidden handles,
+    ## except default menus.
+    kids = allchild (hfig);
+    ismenu = cellfun (@(s) strncmp (s, "__default_menu_", 15), ...
+                      get (kids, "tag"));
+    delete (kids(! ismenu));
     reset (hfig);
-    __add_default_menu__ (hfig);
+
+    ## Recover figure listeners which have been deleted
+    __add_default_menu__ (hfig, kids(ismenu));
+
     __set_default_mouse_modes__ (hfig);
   else
     ## Select only the chilren with visible handles.
--- a/scripts/plot/util/copyobj.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/copyobj.m	Thu Dec 20 17:18:56 2018 -0500
@@ -41,7 +41,7 @@
 function hnew = copyobj (horig, hparent = 0)
 
   partypes = {"root", "figure", "axes", "hggroup"};
-  othertypes = {"line", "patch", "surface", "image", "text"};
+  othertypes = {"line", "patch", "surface", "image", "text", "uicontrol"};
   alltypes = [partypes othertypes];
 
   if (! ishghandle (horig) || nargin > 2)
--- a/scripts/plot/util/figure.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/figure.m	Thu Dec 20 17:18:56 2018 -0500
@@ -39,7 +39,7 @@
 ##
 ## Programming Note: The full list of properties is documented at
 ## @ref{Figure Properties,,Figure Properties}.
-## @seealso{axes, gcf, clf, close}
+## @seealso{axes, gcf, shg, clf, close}
 ## @end deftypefn
 
 ## Author: jwe, Bill Denney
@@ -48,33 +48,35 @@
 
   nargs = nargin;
 
-  if (mod (nargs, 2) == 0)
+  init_new_figure = true;
+  if (nargs == 0)
     f = NaN;
-    init_new_figure = true;
   else
     arg = varargin{1};
-    if (ischar (arg))
+    if (nargs == 1 && ischar (arg))
       arg = str2double (arg);
+      if (isnan (arg))
+        arg = varargin{1};
+      endif
     endif
-    if (isscalar (arg) && isfigure (arg))
-      f = arg;
-      init_new_figure = false;
-      varargin(1) = [];
-      nargs -= 1;
-    elseif (isscalar (arg) && isnumeric (arg) && arg > 0 && arg == fix (arg))
-      f = arg;
-      init_new_figure = true;
-      varargin(1) = [];
-      nargs -= 1;
+    if (isscalar (arg) && isnumeric (arg))
+      if (isfigure (arg))
+        f = arg;
+        init_new_figure = false;
+        varargin(1) = [];
+        nargs -= 1;
+      elseif (arg > 0 && arg == fix (arg))
+        f = arg;
+        varargin(1) = [];
+        nargs -= 1;
+      else
+        error ("figure: N must be figure handle or figure number");
+      endif
     else
-      error ("figure: N must be figure handle or figure number");
+      f = NaN;
     endif
   endif
 
-  if (rem (nargs, 2) == 1)
-    error ("figure: PROPERTY/VALUE arguments must be in pairs");
-  endif
-
   ## 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.
@@ -102,6 +104,7 @@
   if (! init_new_figure && ! any (strcmpi (varargin(1:2:end), "visible")
                                   && strcmpi (varargin(2:2:end), "off")))
     set (f, "visible", "on");
+    __show_figure__ (f);
   endif
 
   if (nargout > 0)
@@ -125,7 +128,5 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error <N must be figure handle or figure number> figure ({1})
-%!error <N must be figure handle or figure number> figure ([1 2])
 %!error <N must be figure handle or figure number> figure (-1)
 %!error <N must be figure handle or figure number> figure (1.5)
--- a/scripts/plot/util/findall.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/findall.m	Thu Dec 20 17:18:56 2018 -0500
@@ -56,7 +56,7 @@
 %! unwind_protect
 %!   h = findall (hf);
 %!   all_handles(1) = {"figure"};
-%!   all_handles(2:18,1) = {"uimenu"};
+%!   all_handles(2:24,1) = {"uimenu"};
 %!   assert (get (h, "type"), all_handles);
 %! unwind_protect_cleanup
 %!   close (hf);
--- a/scripts/plot/util/ginput.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/ginput.m	Thu Dec 20 17:18:56 2018 -0500
@@ -71,6 +71,7 @@
   orig_windowbuttondownfcn = get (fig, "windowbuttondownfcn");
   orig_keypressfcn = get (fig, "keypressfcn");
   orig_closerequestfcn = get (fig, "closerequestfcn");
+  orig_mousemode = get (fig, "__mouse_mode__");
 
   unwind_protect
 
@@ -78,6 +79,7 @@
     set (fig, "keypressfcn", @ginput_keypressfcn);
     set (fig, "closerequestfcn", {@ginput_closerequestfcn,
                                   orig_closerequestfcn});
+    set (fig, "__mouse_mode__", "none");
 
     do
       if (strcmp (toolkit, "fltk"))
@@ -103,6 +105,7 @@
       set (fig, "windowbuttondownfcn", orig_windowbuttondownfcn);
       set (fig, "keypressfcn", orig_keypressfcn);
       set (fig, "closerequestfcn", orig_closerequestfcn);
+      set (fig, "__mouse_mode__", orig_mousemode);
     endif
   end_unwind_protect
 
--- a/scripts/plot/util/gnuplot_binary.in.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/gnuplot_binary.in.m	Thu Dec 20 17:18:56 2018 -0500
@@ -61,16 +61,15 @@
 
 
 %!test
-%! try
-%!   [orig_val, orig_args] = gnuplot_binary ();
+%! [orig_val, orig_args] = gnuplot_binary ();
+%! unwind_protect
 %!   [old_val, old_args] = gnuplot_binary ("__foobar__", "-opt1");
 %!   assert (orig_val, old_val);
 %!   assert (orig_args, old_args);
 %!   assert (gnuplot_binary (), "__foobar__");
 %!   [~, new_args] = gnuplot_binary ();
 %!   assert (new_args, {"-opt1"});
+%! unwind_protect_cleanup
 %!   gnuplot_binary (orig_val, orig_args{:});
-%!   assert (gnuplot_binary (), orig_val);
-%! catch
-%!   gnuplot_binary (orig_val, orig_args{:});
-%! end_try_catch
+%! end_unwind_protect
+%! assert (gnuplot_binary (), orig_val);
--- a/scripts/plot/util/hdl2struct.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/hdl2struct.m	Thu Dec 20 17:18:56 2018 -0500
@@ -135,15 +135,12 @@
   persistent excluded;
 
   if (isempty (excluded))
-    excluded = cell2struct (repmat ({[]}, 1, 21),
+    excluded = cell2struct (repmat ({[]}, 1, 15),
                             {"beingdeleted", "busyaction", "buttondownfcn", ...
                              "children", "clipping", "createfcn", ...
                              "deletefcn", "handlevisibility", "hittest", ...
                              "interruptible", "parent", "selected" , ...
-                             "selectionhighlight", "type", "uicontextmenu", ...
-                             "currentaxes", "currentcharacter", ...
-                             "currentobject", "tightinset", "currentpoint", ...
-                             "extent"}, 2);
+                             "selectionhighlight", "type", "uicontextmenu"}, 2);
   endif
 
   obj = get (h);
--- a/scripts/plot/util/hgload.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/hgload.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,23 +17,36 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{h} =} hgload (@var{filename})
-## Load the graphics object in @var{filename} into the graphics handle @var{h}.
+## @deftypefn  {} {@var{h} =} hgload (@var{filename})
+## @deftypefnx {} {[@var{h}, @var{old_prop}] =} hgload (@var{filename}, @var{prop_struct})
+## Load the graphics objects in @var{filename} into a vector of graphics
+## handles @var{h}.
 ##
 ## If @var{filename} has no extension, Octave will try to find the file with
-## and without the standard extension of @file{.ofig}.
-## @seealso{hgsave, struct2hdl}
+## and without the default extension @file{.ofig}.
+##
+## If provided, the elements of structure @var{prop_struct} will be used to
+## override the properties of top-level objects stored in @var{filename}, and
+## the saved values from @var{filename} will be stored in @var{old_prop}.
+## @var{old_prop} is a cell array matching the size of @var{h}; each cell
+## contains a structure of the existing property names and values before being
+## overridden.
+##
+## @seealso{openfig, hgsave, struct2hdl}
 ## @end deftypefn
 
-## Author: Massimiliano Fasi
-
-function h = hgload (filename)
+function [h, old_prop] = hgload (filename, prop_struct = struct ())
 
-  ## Check input arguments
-  if (nargin != 1)
+  ## Check number of input arguments
+  if (nargin == 0 || nargin > 2)
     print_usage ();
   endif
 
+  ## Check type of second input argument
+  if (! isstruct (prop_struct))
+    error ("hgload: PROP_STRUCT must be a struct");
+  endif
+
   ## Check file existence
   [~, ~, ext] = fileparts (filename);
   if (isempty (ext))
@@ -48,21 +61,74 @@
     endif
   endif
 
-  ## Load the handle
-  try
-    stmp = load (filename, "s_oct40");
-  catch
+  ## Load the handle structure
+  hgs = {"s_oct40", "hgS_050200", "hgS_070000"};
+  hg = load (filename);
+  i = isfield (hg, hgs);
+  if (nnz (i) == 1)
+    hg = hg.(hgs{i});
+  else
     error ("hgload: could not load hgsave-formatted object in file %s", filename);
-  end_try_catch
+  endif
 
-  h = struct2hdl (stmp.s_oct40);
+  ## Override properties of top-level objects
+  calc_old_prop = false;
+  if (isargout (2))
+    calc_old_prop = true;
+    old_prop = repmat ({[]}, 1, numel (hg));
+  endif
+  fn_new = fieldnames (prop_struct);
+  if (! isempty (fn_new))
+    for i = 1:numel (hg)
+      fn_old = fieldnames (hg(i).properties);
+      for j = 1:numel (fn_new)
+        idx = ismember (tolower (fn_old), tolower (fn_new{j}));
+        if (any (idx))
+          if (calc_old_prop)
+            old_prop{i}.(fn_new{j}) = hg(i).properties.(fn_old{idx});
+          endif
+          hg(i).properties.(fn_old{idx}) = prop_struct.(fn_new{j});
+        endif
+      endfor
+    endfor
+  endif
+
+  ## Build the graphics handle object
+  h = zeros (1, numel (hg));
+  for i = 1:numel (hg)
+    h(i) = struct2hdl (hg(i));
+  endfor
 
 endfunction
 
 
 ## Functional test for hgload/hgsave pair is in hgsave.m
 
+## Test overriding saved properties with second input
+%!test
+%! unwind_protect
+%!   h1 = figure ("visible", "off");
+%!   col = get (h1, "color");
+%!   ftmp = [tempname() ".ofig"];
+%!   hgsave (h1, ftmp);
+%!   close (h1);
+%!   [h2, old] = hgload (ftmp);
+%!   assert (old, {[]});
+%!   [h3, old] = hgload (ftmp, struct ("color", [1 0 0]));
+%!   assert (get (h3, "color"), [1 0 0]);
+%!   assert (iscell (old) && numel (old) == 1);
+%!   assert (isstruct (old{1}) && isfield (old{1}, "color"));
+%!   assert (old{1}.color, col);
+%! unwind_protect_cleanup
+%!   unlink (ftmp);
+%!   try, close (h1); end_try_catch
+%!   try, close (h2); end_try_catch
+%!   try, close (h3); end_try_catch
+%! end_unwind_protect
+
 ## Test input validation
 %!error hgload ()
-%!error hgload (1, 2)
+%!error hgload (1, 2, 3)
+%!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	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/hgsave.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,7 +20,7 @@
 ## @deftypefn  {} {} hgsave (@var{filename})
 ## @deftypefnx {} {} hgsave (@var{h}, @var{filename})
 ## @deftypefnx {} {} hgsave (@var{h}, @var{filename}, @var{fmt})
-## Save the graphics handle @var{h} to the file @var{filename} in the format
+## Save the graphics handle(s) @var{h} to the file @var{filename} in the format
 ## @var{fmt}.
 ##
 ## If unspecified, @var{h} is the current figure as returned by @code{gcf}.
@@ -28,7 +28,7 @@
 ## When @var{filename} does not have an extension the default filename
 ## extension @file{.ofig} will be appended.
 ##
-## If present, @var{fmt} should be one of the following:
+## If present, @var{fmt} must be one of the following:
 ##
 ## @itemize @bullet
 ## @item @option{-binary}, @option{-float-binary}
@@ -44,14 +44,14 @@
 ## @item @option{-zip}, @option{-z}
 ## @end itemize
 ##
-## When producing graphics for final publication use @code{print} or
-## @code{saveas}.  When it is important to be able to continue to edit a
-## figure as an Octave object, use @code{hgsave}/@code{hgload}.
-## @seealso{hgload, hdl2struct, saveas, print}
+## The default format is @option{-binary} to minimize storage.
+##
+## Programming Note: When producing graphics for final publication use
+## @code{print} or @code{saveas}.  When it is important to be able to continue
+## to edit a figure as an Octave object, use @code{hgsave}/@code{hgload}.
+## @seealso{hgload, hdl2struct, savefig, saveas, print}
 ## @end deftypefn
 
-## Author: Massimiliano Fasi
-
 function hgsave (h, filename, fmt = "-binary")
 
   if (nargin < 1 || nargin > 3)
@@ -63,9 +63,9 @@
     filename = h;
     h = get (0, "currentfigure");
     if (isempty (h))
-      error ("hgsave: No current figure to save");
+      error ("hgsave: no current figure to save");
     endif
-  elseif (! (ishghandle (h) && ischar (filename)))
+  elseif (! (all (ishghandle (h)) && ischar (filename)))
     print_usage ();
   endif
 
@@ -75,12 +75,15 @@
     filename = [filename ".ofig"];
   endif
 
-  s_oct40 = hdl2struct (h);
+  for i = 1:numel (h)
+    s_oct40(i) = hdl2struct (h(i));
+  endfor
   save (fmt, filename, "s_oct40");
 
 endfunction
 
 
+## FIXME: Have to use gnuplot for printing figs that have never been visible.
 %!testif HAVE_MAGICK; any (strcmp ("gnuplot", available_graphics_toolkits ()))
 %! toolkit = graphics_toolkit ();
 %! graphics_toolkit ("gnuplot");
@@ -126,4 +129,13 @@
 ## Test input validation
 %!error hgsave ()
 %!error hgsave (1, 2, 3, 4)
-%!error hgsave ("abc", "def")
+%!error <no current figure to save>
+%! unwind_protect
+%!  old_fig = get (0, "currentfigure");
+%!  set (0, "currentfigure", []);
+%!  hgsave ("foobar");
+%! unwind_protect_cleanup
+%!  set (0, "currentfigure", old_fig);
+%! end_unwind_protect
+%!error hgsave ([0, -1], "foobar")
+%!error hgsave (0, { "foobar" })
--- a/scripts/plot/util/hgtransform.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/hgtransform.m	Thu Dec 20 17:18:56 2018 -0500
@@ -81,9 +81,9 @@
 
   for hk = hlist.'
 
-    ## FIXME: Add support for light, rectangle, and text objects
+    ## FIXME: Add support for light and rectangle objects
     type = get (hk, "type");
-    if (! any (strcmp (type, {"line", "patch", "surface", "image"})))
+    if (! any (strcmp (type, {"line", "patch", "surface", "image", "text"})))
       continue;  # Unsupported type.  Silently skip.
     endif
 
@@ -93,40 +93,47 @@
       continue;
     endif
 
-    ## FIXME: Rotations for "image" objects are not handled correctly.
-
-    xd = double (orig_data(idx).xdata);
-    xsz = size (xd);
-
-    yd = double (orig_data(idx).ydata);
-    ysz = size (yd);
+    if (strcmp (type, "text"))
+      pos = orig_data(idx).position;
+      xd = pos(1);
+      yd = pos(2);
+      zd = pos(3);
+    else
+      ## FIXME: Rotations for "image" objects are not handled correctly.
+      xd = double (orig_data(idx).xdata);
+      xsz = size (xd);
 
-    if (strcmp (type, "image"))
-      zd = [];
-    else
-      zd = double (orig_data(idx).zdata);
-      zsz = size (zd);
-    endif
-    z_empty = isempty (zd);
+      yd = double (orig_data(idx).ydata);
+      ysz = size (yd);
+
+      if (strcmp (type, "image"))
+        zd = [];
+      else
+        zd = double (orig_data(idx).zdata);
+        zsz = size (zd);
+      endif
+      z_empty = isempty (zd);
 
-    if (isempty (zd))
-      ## Common case of 2-D data.
-      zd = zeros (1, numel (xd));
-    elseif (isvector (xd) && isvector (yd))
-      ## Handle surface data which may be a vector/matrix combination
-      if (isvector (zd))
-        ## Do nothing.  All data will be forced to row vectors below
-      elseif (length (xd) == rows (zd) && length (yd) == columns (zd))
-        [xd, yd] = meshgrid (xd, yd);
-        xsz = size (xd);
-        ysz = size (yd);
+      if (z_empty)
+        ## Common case of 2-D data.
+        zd = zeros (numel (xd), 1);
+      elseif (isvector (xd) && isvector (yd))
+        ## Handle surface data which may be a vector/matrix combination
+        if (isvector (zd))
+          ## Do nothing.  All data will be forced to row vectors below
+        elseif (length (xd) == rows (zd) && length (yd) == columns (zd))
+          [xd, yd] = meshgrid (xd, yd);
+          xsz = size (xd);
+          ysz = size (yd);
+        endif
       endif
-    endif
 
-    ## Force row vectors for later concatenation
-    xd = xd(:).';
-    yd = yd(:).';
-    zd = zd(:).';
+      ## Force row vectors for later concatenation
+      xd = xd(:).';
+      yd = yd(:).';
+      zd = zd(:).';
+
+    endif
 
     ## FIXME: To minimize memory, better to construct data matrix in-place?
     data = [xd; yd; zd; ones(1, columns(xd))];
@@ -135,11 +142,16 @@
     ## Need to trim or rotations which produce values near 0 will be strange.
     data(abs (data) < tol) = 0;
 
-    set (hk, "xdata", reshape (data(1,:), xsz));
-    set (hk, "ydata", reshape (data(2,:), ysz));
-    if (! z_empty)
-      set (hk, "zdata", reshape (data(3,:), zsz));
+    if (strcmp (type, "text"))
+      set (hk, "position", [data(1), data(2), data(3)]);
+    else
+      set (hk, "xdata", reshape (data(1,:), xsz));
+      set (hk, "ydata", reshape (data(2,:), ysz));
+      if (! z_empty)
+        set (hk, "zdata", reshape (data(3,:), zsz));
+      endif
     endif
+
   endfor
 
 endfunction
@@ -164,10 +176,13 @@
             set (hk, "ydata", orig_data(idx).ydata);
             set (hk, "zdata", orig_data(idx).zdata);
 
-          case {"image"}
+          case "image"
             set (hk, "xdata", orig_data(idx).xdata);
             set (hk, "ydata", orig_data(idx).ydata);
 
+          case "text"
+            set (hk, "position", orig_data(idx).position);
+
           otherwise
             ## Unsupported type.  No data was saved.
 
@@ -193,14 +208,17 @@
         orig_data(end).ydata = get (hk, "ydata");
         orig_data(end).zdata = get (hk, "zdata");
 
-      case {"image"}
+      case "image"
         orig_data(end).xdata = get (hk, "xdata");
         orig_data(end).ydata = get (hk, "ydata");
 
-      case {"light",  "text"}
+      case "text"
+        orig_data(end).position = get (hk, "position");
+
+      case "light"
         warning ("hgtransform: %s objects are not yet supported", type);
 
-      case {"hggroup"}
+      case "hggroup"
         try
           get (hk, "curvature");
           is_rectangle = true;
--- a/scripts/plot/util/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -70,6 +70,7 @@
   %reldir%/meshgrid.m \
   %reldir%/ndgrid.m \
   %reldir%/newplot.m \
+  %reldir%/openfig.m \
   %reldir%/pan.m \
   %reldir%/print.m \
   %reldir%/printd.m \
@@ -78,6 +79,7 @@
   %reldir%/rotate.m \
   %reldir%/rotate3d.m \
   %reldir%/saveas.m \
+  %reldir%/savefig.m \
   %reldir%/shg.m \
   %reldir%/struct2hdl.m \
   %reldir%/subplot.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/util/openfig.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,162 @@
+## Copyright (C) 2018 Guillaume Flandin
+##
+## This filename 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.
+## 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 filename COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} openfig
+## @deftypefnx {} {} openfig (@var{filename})
+## @deftypefnx {} {} openfig (@dots{}, @var{copies})
+## @deftypefnx {} {} openfig (@dots{}, @var{visibility})
+## @deftypefnx {} {@var{h} =} openfig (@dots{})
+## Read saved figure window(s) from @var{filename} and return graphics
+## handle(s) @var{h}.
+##
+## By default, @var{filename} is @qcode{"Untitled.fig"}.  If a full path is not
+## specified, the file opened will be the first one encountered in the load
+## path.  If @var{filename} is not found and does not have an extension, a
+## search will take place for the first file in the load path with extension
+## @qcode{".fig"} or @qcode{".ofig"}, in that order.
+##
+## @var{copies} is an optional input indicating whether a new figure should
+## be created (@qcode{"new"}) or whether an existing figure may be reused
+## (@qcode{"reuse"}).  An existing figure may be reused if the
+## @qcode{"FileName"} property matches the specified input @var{filename}.
+## When a figure is reused it becomes the active figure and is shown on top
+## of other figures.  If the figure was offscreen, it is re-positioned to be
+## onscreen.  The default value for @var{copies} is @qcode{"new"}.
+##
+## @var{visibility} is an optional input indicating whether to show the figure
+## (@qcode{"visible"}) or not (@qcode{"invisible"}).  When @var{visibility} is
+## specified as an input to @code{openfig} it overrides the visibility setting
+## stored in @var{filename}.
+##
+## @seealso{open, hgload, savefig, struct2hdl}
+## @end deftypefn
+
+function h = openfig (filename = "Untitled.fig", varargin)
+
+  if (nargin > 3)
+    print_usage ();
+  endif
+
+  ## Check input filename
+  if (isempty (file_in_loadpath (filename)))
+    [d,n,ext] = fileparts (filename);
+    if (isempty (ext))
+      filename = fullfile (d, [n ".fig"]);
+      if (isempty (file_in_loadpath (filename)))
+        filename = fullfile (d, [n ".ofig"]);
+        if (isempty (file_in_loadpath (filename)))
+          error ("openfig: cannot find file '%s'", filename);
+        endif
+      endif
+    else
+      error ("openfig: cannot find file '%s'", filename);
+    endif
+  endif
+  filename = file_in_loadpath (filename);
+
+  ## Process optional arguments
+  copies = true;
+  visibility = {};
+  for i = 1:numel (varargin)
+    if (! ischar (varargin{i}))
+      error ("openfig: input argument %d must be a string", i+1);
+    endif
+    switch (tolower (varargin{i}))
+      case "reuse"
+        copies = false;
+      case "new"
+        copies = true;
+      case "visible"
+        visibility = {"visible", "on"};
+      case "invisible"
+        visibility = {"visible", "off"};
+      otherwise
+        error ("openfig: unknown option '%s'", varargin{i});
+    endswitch
+  endfor
+
+  ## Reuse an existing figure?
+  if (! copies)
+    htmp = findobj (allchild (0), "type", "figure", "FileName", filename);
+    if (! isempty (htmp))
+      htmp = htmp(end);
+      if (! isempty (visibility))
+        set (htmp, visibility{:});
+      endif
+      movegui (htmp, "onscreen");
+      if (nargout > 0)
+        h = htmp;
+      endif
+      return;
+    endif
+  endif
+
+  ## Load graphics objects from file
+  prop_struct = cell2struct (visibility(2:2:end), visibility(1:2:end), 2);
+  htmp = hgload (filename, prop_struct);
+  set (htmp, "FileName", filename);
+
+  if (nargout > 0)
+    h = htmp;
+  endif
+
+endfunction
+
+
+%!test
+%! unwind_protect
+%!   h1 = figure ("visible", "off");
+%!   ftmp = [tempname() ".ofig"];
+%!   hgsave (h1, ftmp);
+%!   close (h1);
+%!   h2 = openfig (ftmp, "new", "invisible");
+%!   h3 = openfig (ftmp, "reuse");
+%!   assert (h2 == h3);
+%!   close (h2);
+%! unwind_protect_cleanup
+%!   unlink (ftmp);
+%!   try, close (h1); end_try_catch
+%!   try, close (h2); end_try_catch
+%!   try, close (h3); end_try_catch
+%! end_unwind_protect
+
+%!error openfig (1, 2, 3, 4)
+%!error <cannot find file> openfig ("%%_A_REALLY_UNLIKELY_FILENAME_%%")
+%!error <cannot find file> openfig ("%%_A_REALLY_UNLIKELY_FILENAME_%%.fig")
+%!error <input argument 3 must be a string>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   ftmp = [tempname() ".ofig"];
+%!   hgsave (h, ftmp);
+%!   openfig (ftmp, "new", [1, 2, 3]); 
+%! unwind_protect_cleanup
+%!   unlink (ftmp);
+%!   close (h);
+%! end_unwind_protect
+%!error <unknown option 'foobar'>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   ftmp = [tempname() ".ofig"];
+%!   hgsave (h, ftmp);
+%!   openfig (ftmp, "foobar"); 
+%! unwind_protect_cleanup
+%!   unlink (ftmp);
+%!   close (h);
+%! end_unwind_protect
--- a/scripts/plot/util/print.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/print.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,51 +20,116 @@
 ## @deftypefn  {} {} print ()
 ## @deftypefnx {} {} print (@var{options})
 ## @deftypefnx {} {} print (@var{filename}, @var{options})
-## @deftypefnx {} {} print (@var{h}, @var{filename}, @var{options})
-## Print a plot, or save it to a file.
-##
-## Both output formatted for printing (PDF and PostScript), and many bitmapped
-## and vector image formats are supported.
+## @deftypefnx {} {} print (@var{hfig}, @dots{})
+## @deftypefnx {} {@var{rgb} =} print (@qcode{"-RGBImage"}, @dots{})
+## Format a figure for printing and either save it to a file, send it to a
+## printer, or return an RGB image.
 ##
 ## @var{filename} defines the name of the output file.  If the filename has
-## no suffix, one is inferred from the specified device and appended to the
-## filename.  If no filename is specified, the output is sent to the
-## printer.
+## no suffix then one is inferred from the specified device and appended to the
+## filename.  When neither a filename nor the @qcode{"-RGBImage"} option is
+## present, the output is sent to the printer.  The various options and
+## filename arguments may be given in any order, except for the figure handle
+## argument @var{hfig} which must be first if it is present.
 ##
-## @var{h} specifies the handle of the figure to print.  If no handle is
-## specified the current figure is used.
+## Example: Print to a file using PDF and JPEG formats.
 ##
-## For output to a printer, PostScript file, or PDF file, the paper size is
-## specified by the figure's @code{papersize} property.  The location and
-## size of the image on the page are specified by the figure's
-## @code{paperposition} property.  The orientation of the page is specified
-## by the figure's @code{paperorientation} property.
+## @example
+## @group
+## figure (1);
+## clf ();
+## surf (peaks);
+## print figure1.pdf    # The extension specifies the format
+## print -djpg figure1  # Will produce "figure1.jpg" file
+## @end group
+## @end example
 ##
-## The width and height of images are specified by the figure's
-## @code{paperposition(3:4)} property values.
+## If the first argument is a handle @var{hfig} to a figure object then it
+## specifies the figure to print.  By default, the current figure returned
+## by @code{gcf} is printed.
+##
+## For outputs to paged formats, for example, PostScript and PDF, the page size
+## is specified by the figure's @code{papersize} property together with the
+## @code{paperunits} property.  The location and size of the plot on the page
+## are specified by the figure's @code{paperposition} property.  The
+## orientation of the page is specified by the figure's @code{paperorientation}
+## property.
+##
+## For non-page formats---for example, image formats like JPEG---the width and
+## height of the output are specified by the figure's @code{paperposition(3:4)}
+## property values.
 ##
 ## The @code{print} command supports many @var{options}:
 ##
 ## @table @code
 ## @item -f@var{h}
-##   Specify the handle, @var{h}, of the figure to be printed.  The default
-## is the current figure.
+##   Specify the handle, @var{h}, of the figure to be printed.
+##
+## Example: Print figure 1.
+##
+## @example
+## @group
+## figure (1);
+## clf ();
+## surf (peaks);
+## figure (2);
+## print -f1 figure1.pdf
+## ## Equivalent functional form:
+## print (1, "figure1.pdf")
+## @end group
+## @end example
 ##
 ## @item -P@var{printer}
-##   Set the @var{printer} name to which the plot is sent if no
-## @var{filename} is specified.
+##   Set the @var{printer} name to which the plot is sent if no @var{filename}
+## is specified.
+##
+## Example: Print to printer named PS_printer using PostScript format.
 ##
-## @item -G@var{ghostscript_command}
-##   Specify the command for calling Ghostscript.  For Unix and Windows the
-## defaults are @qcode{"gs"} and @qcode{"gswin32c"}, respectively.
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## print -dpswrite -PPS_printer
+## @end group
+## @end example
+##
+## @item -RGBImage
+##   Return an M-by-N-by-3 RGB image of the figure.  The size of the image
+## depends on the formatting options.  This is similar to taking a screen
+## capture of the plot, but formatting options may be changed such as the
+## resolution or monochrome/color.
+##
+## Example: Get the pixels of a figure image.
 ##
-## @item  -color
-## @itemx -mono
-##   Color or monochrome output.
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## @var{rgb} = print ("-RGBImage");
+## @end group
+## @end example
 ##
-## @item  -solid
-## @itemx -dashed
-##   Force all lines to be solid or dashed, respectively.
+## @item  -opengl
+## @itemx -painters
+##   Specifies whether the opengl (pixel-based) or painters (vector-based)
+## renderer is used.  This is equivalent to changing the figure's
+## @qcode{"Renderer"} property.  When the figure @code{RendererMode} property
+## is @qcode{"auto"} Octave will use the @qcode{"opengl"} renderer for raster
+## formats (e.g., JPEG) and @qcode{"painters"} for vector formats (e.g., PDF).
+##
+## @item -svgconvert
+##   For OpenGL-based graphic toolkits, this enables a different backend
+## toolchain with enhanced characteristics.  The toolchain adds support for
+## printing arbitrary characters and fonts in PDF outputs; it avoids some
+## anti-aliasing artifacts in the rendering of patch and surface objects
+## (particularly for 2-D scenes); and it supports transparency of line, patch,
+## and surface objects.
+##
+## This option only affects PDF outputs, unless it is combined with
+## @option{-painters} option, in which case raster outputs are also affected.
+##
+## Caution: @option{-svgconvert} may lead to inaccurate rendering of image
+## objects.
 ##
 ## @item  -portrait
 ## @itemx -landscape
@@ -74,32 +139,121 @@
 ## orientation specified.  This option is equivalent to changing the figure's
 ## @qcode{"paperorientation"} property.
 ##
-## @item  -TextAlphaBits=@var{n}
-## @itemx -GraphicsAlphaBits=@var{n}
-##   Octave is able to produce output for various printers, bitmaps, and
-## vector formats by using Ghostscript.  For bitmap and printer output
-## anti-aliasing is applied using Ghostscript's TextAlphaBits and
-## GraphicsAlphaBits options.  The default number of bits are 4 and 1
-## respectively.  Allowed values for @var{N} are 1, 2, or 4.
+## @item  -fillpage
+## @itemx -bestfit
+##   When using a page-based format (PDF, PostScript, printer) ignore the
+## @qcode{"paperposition"} property and have the plot occupy the entire page.
+## The option @option{-fillpage} will stretch the plot to occupy the page with
+## 0.25 inch margins all around.  The option @option{-bestfit} will expand the
+## plot to take up as much room as possible on the page @strong{without}
+## distorting the original aspect ratio of the plot.
+##
+## @item  -color
+## @itemx -mono
+##   Color or monochrome output.
+##
+## @item  -solid
+## @itemx -dashed
+##   Force all lines to be solid or dashed, respectively.
+##
+## @item -noui
+##   Don't print uicontrol objects such as pushbuttons which may overlay the
+## plot.  This is the default behavior and it is not possible to include
+## uicontrol objects in the output without using an external screen capture
+## tool.
+##
+## @item -r@var{NUM}
+##   Resolution of bitmaps in dots per inch (DPI).  For both metafiles and SVG
+## the default is the screen resolution; for other formats the default is 150
+## DPI@.  To specify screen resolution, use @qcode{"-r0"}.
+##
+## Example: high resolution raster output.
+##
+## @example
+## @group
+## clf ();
+## surf (peaks (), "facelighting", "gouraud");
+## light ();
+## print ("-r600", "lit_peaks.png");
+## @end group
+## @end example
+##
+## @item -S@var{xsize},@var{ysize}
+##   Plot size in pixels for raster formats including PNG, JPEG, PNG, and
+## (unusually (SVG))@.  For all vector formats, including PDF, PS, and EPS, the
+## plot size is specified in points.  This option is equivalent to changing the
+## width and height of the output by setting the figure property
+## @code{paperposition(3:4)}.  When using the command form of the print
+## function you must quote the @var{xsize},@var{ysize} option to prevent the
+## Octave interpreter from recognizing the embedded comma (',').  For example,
+## by writing @w{"-S640,480"}.
+##
+## @item  -tight
+## @itemx -loose
+##   Force a tight or loose bounding box for EPS files.  The default is tight.
+##
+## @item -@var{preview}
+##   Add a preview to EPS files.  Supported formats are:
+##
+##   @table @code
+##   @item -interchange
+##     Provide an interchange preview.
+##
+##   @item -metafile
+##     Provide a metafile preview.
+##
+##   @item -pict
+##     Provide a pict preview.
+##
+##   @item -tiff
+##     Provide a TIFF preview.
+##   @end table
+##
+## @item -append
+##   Append PostScript or PDF output to an existing file of the same type.
+##
+## @item  -F@var{fontname}
+## @itemx -F@var{fontname}:@var{size}
+## @itemx -F:@var{size}
+##   Use @var{fontname} and/or @var{fontsize} for all text.
+## @var{fontname} is ignored for some devices: dxf, fig, hpgl, etc.
 ##
 ## @item -d@var{device}
 ##   The available output format is specified by the option @var{device}, and
-## is one of:
+## is one of the following (devices marked with a "*" are only available with
+## the Gnuplot toolkit):
+##
+## Vector Formats
 ##
 ##   @table @code
+##   @item  pdf
+##   @itemx pdfcrop
+##     Portable Document Format.  The @code{pdfcrop} device removes the default
+## surrounding page.
+##
+## The OpenGL-based graphics toolkits have limited support for text.
+## Limitations include using only ASCII characters (e.g., no Greek letters)
+## and support for just three base PostScript fonts: Helvetica (the default),
+## Times, or Courier.  Any other font will be replaced by Helvetica.
+##
+## For an enhanced output with complete text support and basic transparency,
+## use the @option{-svgconvert} option.
+##
 ##   @item  ps
 ##   @itemx ps2
 ##   @itemx psc
 ##   @itemx psc2
-##     PostScript (level 1 and 2, mono and color).  The OpenGL-based toolkits
-## always generate PostScript level 3.0.
+##     PostScript (level 1 and 2, mono and color).  The OpenGL-based graphics
+## toolkits always generate PostScript level 3.0 and have limited support for
+## text.
 ##
 ##   @item  eps
 ##   @itemx eps2
 ##   @itemx epsc
 ##   @itemx epsc2
 ##     Encapsulated PostScript (level 1 and 2, mono and color).  The
-## OpenGL-based toolkits always generate PostScript level 3.0.
+## OpenGL-based toolkits always generate PostScript level 3.0 and have
+## limited support for text.
 ##
 ##   @item  pslatex
 ##   @itemx epslatex
@@ -107,53 +261,49 @@
 ##   @itemx pslatexstandalone
 ##   @itemx epslatexstandalone
 ##   @itemx pdflatexstandalone
-##     Generate a @LaTeX{} file @file{@var{filename}.tex} for the text
-## portions of a plot and a file @file{@var{filename}.(ps|eps|pdf)} for the
-## remaining graphics.  The graphics file suffix .ps|eps|pdf is determined
-## by the specified device type.  The @LaTeX{} file produced by the
-## @samp{standalone} option can be processed directly by @LaTeX{}.  The file
-## generated without the @samp{standalone} option is intended to be included
-## from another @LaTeX{} document.  In either case, the @LaTeX{} file
-## contains an @code{\includegraphics} command so that the generated graphics
-## file is automatically included when the @LaTeX{} file is processed.  The
-## text that is written to the @LaTeX{} file contains the strings
-## @strong{exactly} as they were specified in the plot.  If any special
-## characters of the @TeX{} mode interpreter were used, the file must be
-## edited before @LaTeX{} processing.  Specifically, the special characters
-## must be enclosed with dollar signs (@code{$ @dots{} $}), and other
-## characters that are recognized by @LaTeX{} may also need editing (.e.g.,
-## braces).  The @samp{pdflatex} device, and any of the @samp{standalone}
-## formats, are not available with the Gnuplot toolkit.
+##     Generate a @LaTeX{} file @file{@var{filename}.tex} for the text portions
+## of a plot and a file @file{@var{filename}.(ps|eps|pdf)} for the remaining
+## graphics.  The graphics file suffix .ps|eps|pdf is determined by the
+## specified device type.  The @LaTeX{} file produced by the @samp{standalone}
+## option can be processed directly by @LaTeX{}.  The file generated without
+## the @samp{standalone} option is intended to be included from another
+## @LaTeX{} document.  In either case, the @LaTeX{} file contains an
+## @code{\includegraphics} command so that the generated graphics file is
+## automatically included when the @LaTeX{} file is processed.  The text that
+## is written to the @LaTeX{} file contains the strings @strong{exactly} as
+## they were specified in the plot.  If any special characters of the @TeX{}
+## mode interpreter were used, the file must be edited before @LaTeX{}
+## processing.  Specifically, the special characters must be enclosed with
+## dollar signs @w{(@code{$ @dots{} $})}, and other characters that are
+## recognized by @LaTeX{} may also need editing (e.g., braces).  The
+## @samp{pdflatex} device, and any of the @samp{standalone} formats, are not
+## available with the Gnuplot toolkit.
 ##
-##   @item  epscairo
-##   @itemx pdfcairo
-##   @itemx epscairolatex
-##   @itemx pdfcairolatex
-##   @itemx epscairolatexstandalone
-##   @itemx pdfcairolatexstandalone
-##     Generate Cairo based output when using the Gnuplot graphics toolkit.
-## The @samp{epscairo} and @samp{pdfcairo} devices are synonymous with
-## the @samp{epsc} device.  The @LaTeX{} variants generate a @LaTeX{} file,
-## @file{@var{filename}.tex}, for the text portions of a plot, and an image
-## file, @file{@var{filename}.(eps|pdf)}, for the graph portion of the plot.
-## The @samp{standalone} variants behave as described for
-## @samp{epslatexstandalone} above.
+##   @item  epscairo*
+##   @itemx pdfcairo*
+##   @itemx epscairolatex*
+##   @itemx pdfcairolatex*
+##   @itemx epscairolatexstandalone*
+##   @itemx pdfcairolatexstandalone*
+##     Generate output with Cairo renderer.  The devices @samp{epscairo} and
+## @samp{pdfcairo} are synonymous with the @samp{epsc} device.  The @LaTeX{}
+## variants generate a @LaTeX{} file, @file{@var{filename}.tex}, for the text
+## portions of a plot, and an image file, @file{@var{filename}.(eps|pdf)}, for
+## the graph portion of the plot.  The @samp{standalone} variants behave as
+## described for @samp{epslatexstandalone} above.
 ##
-##   @item  ill
-##   @itemx @nospell{aifm}
-##     Adobe Illustrator (Obsolete for Gnuplot versions > 4.2)
+##   @item svg
+##     Scalable Vector Graphics
 ##
-##   @item canvas
-##     Javascript-based drawing on HTML5 canvas viewable in a web browser
-## (only available for the Gnuplot graphics toolkit).
+##   @item canvas*
+##     Javascript-based drawing on an HTML5 canvas viewable in a web browser.
 ##
-##   @item  cdr
-##   @itemx @nospell{corel}
-##     @nospell{CorelDraw}
+##   @item  cdr*
+##   @itemx @nospell{corel*}
+##     CorelDraw
 ##
-##   @item cgm
+##   @item cgm*
 ##     Computer Graphics Metafile, Version 1, ANSI X3.122-1986
-## (only available for the Gnuplot graphics toolkit).
 ##
 ##   @item dxf
 ##     AutoCAD
@@ -168,57 +318,64 @@
 ## whether the special flag should be set for the text in the figure.
 ## (default is @option{-textnormal})
 ##
-##   @item gif
-##     GIF image
-## (only available for the Gnuplot graphics toolkit).
-##
 ##   @item hpgl
 ##     HP plotter language
 ##
+##   @item  ill
+##   @itemx @nospell{aifm}
+##     Adobe Illustrator (obsolete for Gnuplot versions > 4.2)
+##
+##   @item  latex*
+##   @itemx eepic*
+##     @LaTeX{} picture environment and extended picture environment.
+##
+##   @item mf*
+##     Metafont
+##
+##   @item  tikz
+##   @itemx tikzstandalone*
+##     Generate a @LaTeX{} file using PGF/TikZ format.  The OpenGL-based
+## toolkits create a PGF file while Gnuplot creates a TikZ file.  The
+## @samp{tikzstandalone} device produces a @LaTeX{} document which includes the
+## TikZ file.
+##
+##   @end table
+##
+## Raster Formats
+##
+##   @table @code
+##   @item png
+##     Portable Network Graphics
+##
 ##   @item  jpg
 ##   @itemx jpeg
 ##     JPEG image
 ##
-##   @item latex
-##   @itemx eepic
-##     @LaTeX{} picture environment and extended picture environment
-## (only available for the Gnuplot graphics toolkit).
+##   @item  tif
+##   @itemx tiff
+##   @itemx tiffn
+##     TIFF image with LZW compression (@nospell{tif}, tiff) or uncompressed
+## (@nospell{tiffn}).
 ##
-##   @item mf
-##     Metafont
-##
-##   @item png
-##     Portable network graphics
+##   @item gif
+##     GIF image
 ##
 ##   @item pbm
 ##     PBMplus
 ##
-##   @item pdf
-##     Portable document format
-##
-##   @item svg
-##     Scalable vector graphics
+##   @item dumb*
+##     ASCII art
 ##
-##   @item  tikz
-##   @itemx tikzstandalone
-##     Generate a @LaTeX{} file using PGF/TikZ format.  The OpenGL-based
-## toolkits create a PGF file while Gnuplot creates a TikZ file.  The
-## @samp{tikzstandalone} device produces a @LaTeX{} document which includes the
-## TikZ file (@samp{tikzstandalone} and is only available for the Gnuplot
-## graphics toolkit).
 ##   @end table
 ##
 ##   If the device is omitted, it is inferred from the file extension,
-## or if there is no filename it is sent to the printer as PostScript.
+## or if there is no filename then it is sent to the printer as PostScript.
 ##
 ## @item -d@var{ghostscript_device}
 ##   Additional devices are supported by Ghostscript.
-## Some examples are;
+## Some examples are:
 ##
 ##   @table @code
-##   @item pdfwrite
-##     Produces pdf output from eps
-##
 ##   @item ljet2p
 ##     HP LaserJet @nospell{IIP}
 ##
@@ -229,112 +386,50 @@
 ##     Portable Pixel Map file format
 ##   @end table
 ##
-##   For a complete list, type @code{system ("gs -h")} to see what formats
-## and devices are available.
+##   For a complete list of available formats and devices type
+## @code{system ("gs -h")}.
 ##
 ##   When Ghostscript output is sent to a printer the size is determined by
 ## the figure's @qcode{"papersize"} property.  When the output is sent to a
 ## file the size is determined by the plot box defined by the figure's
 ## @qcode{"paperposition"} property.
 ##
-## @item -append
-##   Append PostScript or PDF output to a pre-existing file of the same type.
-##
-## @item -r@var{NUM}
-##   Resolution of bitmaps in pixels per inch.  For both metafiles and SVG
-## the default is the screen resolution; for other formats it is 150 dpi.  To
-## specify screen resolution, use @qcode{"-r0"}.
-##
-## @item  -loose
-## @itemx -tight
-##   Force a tight or loose bounding box for eps files.  The default is loose.
-##
-## @item -@var{preview}
-##   Add a preview to eps files.  Supported formats are:
-##
-##   @table @code
-##   @item -interchange
-##     Provide an interchange preview.
+## @item -G@var{ghostscript_command}
+##   Specify the command for calling Ghostscript.  For Unix the default is
+## @qcode{"gs"} and for Windows it is @qcode{"gswin32c"}.
 ##
-##   @item -metafile
-##     Provide a metafile preview.
-##
-##   @item -pict
-##     Provide pict preview.
-##
-##   @item -tiff
-##     Provide a tiff preview.
-##   @end table
-##
-## @item -S@var{xsize},@var{ysize}
-##   Plot size in pixels for EMF, GIF, JPEG, PBM, PNG, and SVG@.
-## For PS, EPS, PDF, and other vector formats the plot size is in points.
-## This option is equivalent to changing the size of the plot box associated
-## with the @qcode{"paperposition"} property.  When using the command form of
-## the print function you must quote the @var{xsize},@var{ysize} option.  For
-## example, by writing @w{"-S640,480"}.
-##
-## @item  -F@var{fontname}
-## @itemx -F@var{fontname}:@var{size}
-## @itemx -F:@var{size}
-##   Use @var{fontname} and/or @var{fontsize} for all text.
-## @var{fontname} is ignored for some devices: dxf, fig, hpgl, etc.
+## @item  -TextAlphaBits=@var{n}
+## @itemx -GraphicsAlphaBits=@var{n}
+##   Octave is able to produce output for various printers, bitmaps, and
+## vector formats by using Ghostscript.  For bitmap and printer output
+## anti-aliasing is applied using Ghostscript's TextAlphaBits and
+## GraphicsAlphaBits options.  The default number of bits are 4 and 1
+## respectively.  Allowed values for @var{N} are 1, 2, or 4.
 ## @end table
 ##
-## The filename and options can be given in any order.
-##
-## Example: Print to a file using the pdf device.
-##
-## @example
-## @group
-## figure (1);
-## clf ();
-## surf (peaks);
-## print figure1.pdf
-## @end group
-## @end example
-##
-## Example: Print to a file using jpg device.
-##
-## @example
-## @group
-## clf ();
-## surf (peaks);
-## print -djpg figure2.jpg
-## @end group
-## @end example
-##
-## Example: Print to printer named PS_printer using ps format.
-##
-## @example
-## @group
-## clf ();
-## surf (peaks);
-## print -dpswrite -PPS_printer
-## @end group
-## @end example
-##
-## @seealso{saveas, hgsave, orient, figure}
+## @seealso{saveas, hgsave, getframe, orient, figure}
 ## @end deftypefn
 
-function print (varargin)
+function rgbout = print (varargin)
 
   opts = __print_parse_opts__ (varargin{:});
 
-  folder = fileparts (opts.name);
-  if (! isempty (folder) && ! exist (folder, "dir"))
-    error ("print: directory %s does not exist", folder);
-  endif
+  ## Check the requested file is writable
+  if (! opts.rgb_output)
+    folder = fileparts (opts.name);
+    if (! isempty (folder) && ! isfolder (folder))
+      error ("print: directory %s does not exist", folder);
+    endif
 
-  ## Check the requested file is writable
-  do_unlink = (exist (opts.name, "file") != 2);
-  fid = fopen (opts.name, "a");
-  if (fid == -1)
-    error ("print: cannot open file %s for writing", opts.name);
-  endif
-  fclose (fid);
-  if (do_unlink)
-    unlink (opts.name);
+    do_unlink = (exist (opts.name, "file") != 2);
+    fid = fopen (opts.name, "a");
+    if (fid == -1)
+      error ("print: cannot open file %s for writing", opts.name);
+    endif
+    fclose (fid);
+    if (do_unlink)
+      unlink (opts.name);
+    endif
   endif
 
   opts.pstoedit_cmd = @pstoedit;
@@ -342,6 +437,7 @@
   opts.latex_standalone = @latex_standalone;
   opts.lpr_cmd = @lpr;
   opts.epstool_cmd = @epstool;
+  opts.svgconvert_cmd = @svgconvert;
 
   if (isempty (opts.figure) || ! isfigure (opts.figure))
     error ("print: no figure to print");
@@ -382,6 +478,25 @@
       nfig += 1;
     endfor
 
+    if (strcmp (opts.renderer, "opengl"))
+      ## Scale the figure to reach the required resolution
+      scale = opts.ghostscript.resolution / 72;
+      if (scale != 1)
+        props(end+1).h = opts.figure;
+        props(end).name = "__device_pixel_ratio__";
+        props(end).value{1} = get (opts.figure, "__device_pixel_ratio__");
+        set (opts.figure, "__device_pixel_ratio__", scale);
+        nfig += 1;
+      endif
+    elseif (strcmp (tk, "qt"))
+      ## Don't account for the actual pixel density
+      props(end+1).h = opts.figure;
+      props(end).name = "__device_pixel_ratio__";
+      props(end).value = {get(opts.figure, "__device_pixel_ratio__")};
+      set (opts.figure, "__device_pixel_ratio__", 1);
+      nfig += 1;
+    endif
+
     ## print() requires axes units = "normalized"
     hax = findall (opts.figure, "-depth", 1, "type", "axes", ...
       "-not", "units", "normalized");
@@ -393,11 +508,14 @@
       nfig += 1;
     endfor
 
-    ## FIXME: line transparency is only handled for svg output when
-    ## using gl2ps. For other formats, switch grid lines to light gray
-    ## so that the image output approximately matches on-screen experience.
+    ## With the -painters (gl2ps) renderer, line transparency is only
+    ## handled for svg and pdf outputs using svgconvert.
+    ## Otherwise, switch grid lines color to light gray so that the image
+    ## output approximately matches on-screen experience.
     hax = findall (opts.figure, "type", "axes");
-    if (! strcmp (tk, "gnuplot") && ! strcmp (opts.devopt, "svg"))
+    if (! strcmp (tk, "gnuplot") && ! strcmp (opts.renderer, "opengl")
+        && ! (opts.svgconvert && strcmp (opts.devopt, "pdfwrite"))
+        && ! strcmp (opts.devopt, "svg"))
       for n = 1:numel (hax)
         if (strcmp (get (hax(n), "gridcolormode"), "auto"))
           props(end+1).h = hax(n);
@@ -553,12 +671,43 @@
       endif
     endif
 
+    ## When exporting latex files use "latex" for the ticklabelinterpreter.
+    ## It will format tick labels in log axes correctly
+    if (strfind (opts.devopt, "latex"))
+      h = findall (opts.figure, "type", "axes");
+      for n = 1:numel (h)
+        if (ishghandle (h(n)))
+          props(end+1).h = h(n);
+          props(end).name = "ticklabelinterpreter";
+          props(end).value = {get(h(n), "ticklabelinterpreter")};
+          set (h(n), "ticklabelinterpreter", "latex");
+        endif
+      endfor
+    endif
+
     ## call the graphics toolkit print script
     switch (tk)
       case "gnuplot"
         opts = __gnuplot_print__ (opts);
       otherwise
-        opts = __opengl_print__ (opts);
+        if (strcmp (opts.renderer, "opengl"))
+          if (opts.rgb_output)
+            rgbout = __get_frame__ (opts.figure);
+          else
+            compression = "none";
+
+            if (strcmp (opts.devopt, "tiff"))
+              compression = "lzw";
+            elseif (strcmp (opts.devopt, "tiffn"))
+              opts.devopt = "tiff";
+            endif
+
+            imwrite (__get_frame__ (opts.figure), opts.name, ...
+                     opts.devopt, "Compression", compression);
+          endif
+        else
+          opts = __opengl_print__ (opts);
+        endif
     endswitch
 
   unwind_protect_cleanup
@@ -581,7 +730,8 @@
     for n = 1:numel (opts.unlink)
       [status, output] = unlink (opts.unlink{n});
       if (status != 0)
-        warning ("print.m: %s, '%s'", output, opts.unlink{n});
+        warning ("octave:print:unlinkerror", ...
+                 "print.m: %s, '%s'", output, opts.unlink{n});
       endif
     endfor
   end_unwind_protect
@@ -648,17 +798,17 @@
     fileout = ["'" strtrim(fileout) "'"];
   endif
 
-  if (! isempty (opts.preview) && opts.tight_flag)
-    warning ("print:previewandtight",
+  if (! isempty (opts.preview) && opts.tight)
+    warning ("octave:print:previewandtight",
              "print.m: eps preview may not be combined with -tight");
   endif
-  if (! isempty (opts.preview) || opts.tight_flag)
+  if (! isempty (opts.preview) || opts.tight)
 
     if (isempty (opts.epstool_binary))
       error ("print:noepstool", "print.m: 'epstool' is required for specified output format, but binary is not available in PATH");
     endif
 
-    if (opts.tight_flag)
+    if (opts.tight)
       cmd = "--copy --bbox";
     elseif (! isempty (opts.preview))
       switch (opts.preview)
@@ -886,3 +1036,33 @@
   endif
 
 endfunction
+
+function cmd = svgconvert (opts, devopt)
+
+  cmd = "";
+
+  if (nargin < 2)
+    devopt = opts.devopt;
+  endif
+
+  if (isempty (opts.svgconvert_binary))
+    warning ("octave:print:nosvgconvert", ...
+             ["print.m: unale to find octave-svgconvert, ", ...
+              "falling back to eps convertion"]);
+  else
+    fontdir = getenv ("OCTAVE_FONTS_DIR");
+
+    if (isempty (fontdir))
+      fontdir = __octave_config_info__ ("octfontsdir");
+    endif
+
+    cmd = sprintf ("%s - %%s %3.2f %s %d %%s", opts.svgconvert_binary, ...
+                   get (0, "screenpixelsperinch"), ...
+                   fullfile (fontdir, "FreeSans.otf"), 1);
+
+    if (opts.debug)
+      fprintf ("svgconvert command: '%s'\n", cmd);
+    endif
+  endif
+
+endfunction
--- a/scripts/plot/util/private/__add_default_menu__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__add_default_menu__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,8 +17,10 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {} __add_default_menu__ (@var{fig})
-## Add default menu to figure.
+## @deftypefn  {} {} __add_default_menu__ (@var{hfig})
+## @deftypefnx {} {} __add_default_menu__ (@var{hfig}, @var{hmenu})
+## Add default menu and listeners to figure.
+##
 ##
 ## All uimenu handles have their @qcode{"HandleVisibility"} property set to
 ## @qcode{"off"}.
@@ -26,40 +28,89 @@
 
 ## Author: Kai Habel
 
-function __add_default_menu__ (fig)
+function __add_default_menu__ (hf, hmenu = [])
+
+  ## Create
+  if (isempty (hmenu))
+    ## File menu
+    hui = uimenu (hf, "label", "&File", "handlevisibility", "off", ...
+                  "tag", "__default_menu__File");
+    uimenu (hui, "label", "&Open", "callback", @open_cb, ...
+            "accelerator", "o");
+    uimenu (hui, "label", "&Save", "callback", @save_cb, ...
+            "accelerator", "s");
+    uimenu (hui, "label", "Save &As", "callback", @save_cb, ...
+            "accelerator", "S");
+    uimenu (hui, "label", "&Close", "callback", @close_cb, ...
+            "accelerator", "w", "separator", "on");
+    hmenu(1) = hui;
 
-  ## Only FLTK toolkit currently provides menubar
-  if (! strcmp (get (fig, "__graphics_toolkit__"), "fltk"))
-    return;
+    ## Edit menu
+    hui = uimenu (hf, "label", "&Edit", "handlevisibility", "off", ...
+                  "tag", "__default_menu__Edit");
+    uimenu (hui, "label", "&New Figure", "callback", "figure ();", ...
+            "accelerator", "n");
+    uimenu (hui, "label", "&Duplicate Figure",
+            "callback", "copyobj (gcbf (), groot ());", ...
+            "accelerator", "d");
+    uimenu (hui, "label", "Clea&r Figure",
+            "callback", "clf (gcbf ());");
+    uimenu (hui, "label", "Reset Figure",
+            "callback", "reset (gcbf ());");
+    hmenu(2) = hui;
+
+    ## Tools menu
+    hui = uimenu (hf, "label", "&Tools", "handlevisibility", "off", ...
+                  "tag", "__default_menu__Tools");
+    uimenu (hui, "label", "Toggle &grid on all axes", "tag", "toggle", ...
+            "callback", @grid_cb);
+    uimenu (hui, "label", "Show grid on all axes", "tag", "on", ...
+            "callback", @grid_cb);
+    uimenu (hui, "label", "Hide grid on all axes", "tag", "off", ...
+            "callback", @grid_cb);
+    uimenu (hui, "label", "Auto&scale all axes", "callback", @autoscale_cb);
+
+    hui2 = uimenu (hui, "label", "GUI &Mode (on all axes)");
+    uimenu (hui2, "label", "Pan x and y", "tag", "pan_on", ...
+            "callback", @guimode_cb);
+    uimenu (hui2, "label", "Pan x only", "tag", "pan_xon", ...
+            "callback", @guimode_cb);
+    uimenu (hui2, "label", "Pan y only", "tag", "pan_yon", ...
+            "callback", @guimode_cb);
+    uimenu (hui2, "label", "Disable pan and rotate", "tag", ...
+            "no_pan_rotate", "callback", @guimode_cb);
+    uimenu (hui2, "label", "Rotate on", "tag", "rotate3d", ...
+            "callback", @guimode_cb);
+    uimenu (hui2, "label", "Enable mousezoom", "tag", "zoom_on", ...
+            "callback", @guimode_cb);
+    uimenu (hui2, "label", "Disable mousezoom", "tag", "zoom_off", ...
+            "callback", @guimode_cb);
+    hmenu(3) = hui;
   endif
 
-  obj = findall (fig, "-depth", 1, "tag", "__default_menu__", "label", "&File");
-  if (isempty (obj))
-    __f = uimenu (fig, "label", "&File", "handlevisibility", "off",
-                       "tag", "__default_menu__");
-      uimenu (__f, "label", "&Save", "callback", @save_cb);
-      uimenu (__f, "label", "Save &As", "callback", @save_cb);
-      uimenu (__f, "label", "&Close", "callback", @close_cb);
-
-    __e = uimenu (fig, "label", "&Edit", "handlevisibility", "off",
-                       "tag", "__default_menu__");
-      uimenu (__e, "label", "Toggle &grid on all axes", "tag", "toggle", "callback", @grid_cb);
-      uimenu (__e, "label", "Show grid on all axes", "tag", "on", "callback", @grid_cb);
-      uimenu (__e, "label", "Hide grid on all axes", "tag", "off", "callback", @grid_cb);
-      uimenu (__e, "label", "Auto&scale all axes", "callback", @autoscale_cb);
-      gm = uimenu (__e, "label", "GUI &Mode (on all axes)");
-        uimenu (gm, "label", "Pan x and y", "tag", "pan_on", "callback", @guimode_cb);
-        uimenu (gm, "label", "Pan x only", "tag", "pan_xon", "callback", @guimode_cb);
-        uimenu (gm, "label", "Pan y only", "tag", "pan_yon", "callback", @guimode_cb);
-        uimenu (gm, "label", "Disable pan and rotate", "tag", "no_pan_rotate", "callback", @guimode_cb);
-        uimenu (gm, "label", "Rotate on", "tag", "rotate3d", "callback", @guimode_cb);
-        uimenu (gm, "label", "Enable mousezoom", "tag", "zoom_on", "callback", @guimode_cb);
-        uimenu (gm, "label", "Disable mousezoom", "tag", "zoom_off", "callback", @guimode_cb);
-
-  endif
+  ## Figure listeners
+  toggle_visibility_cb (hf, [], hmenu);
+  addlistener (hf, "menubar", {@toggle_visibility_cb, hmenu});
 
 endfunction
 
+function toggle_visibility_cb (hf, ~, hmenu)
+  if (strcmp (get (hf, "menubar"), "none"))
+    set (hmenu, "visible", "off")
+  else
+    set (hmenu, "visible", "on")
+  endif
+endfunction
+
+function open_cb (h, e)
+  [filename, filedir] = uigetfile ({"*.ofig", "Octave Figure File"}, ...
+                                   "Open Figure");
+  if (filename != 0)
+    fname = fullfile (filedir, filename);
+    tmphf = hgload (fname);
+    set (tmphf, "filename", fname);
+  endif
+endfunction
 
 function save_cb (h, e)
   [hcbo, hfig] = gcbo ();
@@ -77,7 +128,7 @@
 endfunction
 
 
-function __save_as__ (caller)
+function __save_as__ (hf)
   [filename, filedir] = uiputfile ...
     ({"*.ofig", "Octave Figure File";
       "*.eps;*.epsc;*.pdf;*.svg;*.ps;*.tikz", "Vector Image Formats";
@@ -89,9 +140,9 @@
     set (gcbf, "filename", fname);
     flen = numel (fname);
     if (flen > 5 && strcmp (fname(flen-4:end), ".ofig"))
-      hgsave (caller, fname);
+      hgsave (hf, fname);
     else
-      saveas (caller, fname);
+      saveas (hf, fname);
     endif
   endif
 endfunction
--- a/scripts/plot/util/private/__ghostscript__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__ghostscript__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -76,6 +76,10 @@
     gs_opts = sprintf ("%s -dLanguageLevel=%d", gs_opts, opts.level);
   endif
 
+  if (strfind (opts.device, "tiffscaled"))
+    gs_opts = [gs_opts " -sCompression=lzw"];
+  endif
+
   if (opts.antialiasing && isempty (strfind (opts.device, "write")))
     ## Apply anti-aliasing to all bitmap formats/devices
     gs_opts = sprintf ("%s -dTextAlphaBits=%d -dGraphicsAlphaBits=%d",
--- a/scripts/plot/util/private/__gnuplot_draw_axes__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__gnuplot_draw_axes__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -247,8 +247,7 @@
   else
     xaxisloc = "x";
     xaxisloc_using = "x1";
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-    if (any (strcmp (axis_obj.xaxislocation, {"origin", "zero"})))
+    if (strcmp (axis_obj.xaxislocation, "origin"))
       fputs (plot_stream, "set xzeroaxis;\n");
     endif
   endif
@@ -258,8 +257,7 @@
   else
     yaxisloc = "y";
     yaxisloc_using = "y1";
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-    if (any (strcmp (axis_obj.yaxislocation, {"origin", "zero"})))
+    if (strcmp (axis_obj.yaxislocation, "origin"))
       fputs (plot_stream, "set yzeroaxis;\n");
     endif
   endif
@@ -1500,13 +1498,13 @@
         if (isempty (axis_obj.xtick))
         elseif (strcmp (axis_obj.xaxislocation, "top"))
           fprintf (plot_stream, "set x2tics %s nomirror\n", axis_obj.tickdir);
-        else # xaxislocation == "bottom", "origin" or "zero"
+        else # xaxislocation == "bottom" or "origin"
           fprintf (plot_stream, "set xtics %s nomirror\n", axis_obj.tickdir);
         endif
         if (isempty (axis_obj.ytick))
         elseif (strcmp (axis_obj.yaxislocation, "right"))
           fprintf (plot_stream, "set y2tics %s nomirror\n", axis_obj.tickdir);
-        else # yaxislocation == "left", "origin" or "zero"
+        else # yaxislocation == "left" or "origin"
           fprintf (plot_stream, "set ytics %s nomirror\n",  axis_obj.tickdir);
         endif
       endif
@@ -1811,12 +1809,10 @@
     arrow (4, obj.ycolor, obj.linewidth, [1,0,0], [1,1,0]);
   endif
 
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-  if (any (strcmp (obj.xaxislocation, {"origin", "zero"})))
+  if (strcmp (obj.xaxislocation, "origin"))
     idx = zeroaxis (idx, obj.xcolor, "x");
   endif
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-  if (any (strcmp (obj.yaxislocation, {"origin", "zero"})))
+  if (strcmp (obj.yaxislocation, "origin"))
     idx = zeroaxis (idx, obj.ycolor, "y");
   endif
 
@@ -1854,7 +1850,7 @@
   tick ('y', obj.ycolor, obj.tickdir, mirrorstr);
   tick ('z', obj.zcolor, obj.tickdir, mirrorstr);
 
-  function tick (axischar, color, tickdir, mirrorstr);
+  function tick (axischar, color, tickdir, mirrorstr)
     if (isnumeric (color))
       if (length (color) == 3)
         colorspec = sprintf ('rgb "#%02x%02x%02x"', round (255*color));
@@ -2182,8 +2178,7 @@
                obj.xcolor, "x", plot_stream, true, "border",
                "", "", fontname, fontspec, obj.ticklabelinterpreter,
                obj.xscale, obj.xsgn, gnuplot_term);
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-  elseif (any (strcmp (obj.xaxislocation, {"origin", "zero"})))
+  elseif (strcmp (obj.xaxislocation, "origin"))
     do_tics_1 (obj.xtickmode, obj.xtick, obj.xminortick, obj.xticklabelmode,
                obj.xticklabel, obj.xcolor, "x", plot_stream, true,
                "axis", obj.tickdir, ticklength, fontname, fontspec,
@@ -2211,8 +2206,7 @@
                obj.ycolor, "y", plot_stream, ymirror, "border",
                "", "", fontname, fontspec, obj.ticklabelinterpreter,
                obj.yscale, obj.ysgn, gnuplot_term);
-### FIXME: DEPRECATED: Remove "zero" in version 5.
-  elseif (any (strcmp (obj.yaxislocation, {"origin", "zero"})))
+  elseif (strcmp (obj.yaxislocation, "origin"))
     do_tics_1 (obj.ytickmode, obj.ytick, obj.yminortick, obj.yticklabelmode,
                obj.yticklabel, obj.ycolor, "y", plot_stream, ymirror,
                "axis", obj.tickdir, ticklength, fontname, fontspec,
@@ -2281,28 +2275,15 @@
   endif
   colorspec = get_text_colorspec (color);
   fprintf (plot_stream, ['set format %s "%s";' "\n"], ax, fmt);
-  if (strcmp (ticmode, "manual"))
-    if (isempty (tics))
-      fprintf (plot_stream, "unset %stics;\nunset m%stics;\n", ax, ax);
-      return
-    endif
-    fprintf (plot_stream, "set %stics %s %s %s %s (", ax, tickdir,
-             ticklength, axispos, mirror);
-    fprintf (plot_stream, "%.15g", tics(1));
-    if (numel (tics) > 1)
-      fprintf (plot_stream, ",%.15g", tics(2:end));
-    endif
-    fprintf (plot_stream, ") %s;\n", fontspec);
+  if (strcmp (ticmode, "manual") && isempty (tics))
+    fprintf (plot_stream, "unset %stics;\nunset m%stics;\n", ax, ax);
+    return
   else
-    fprintf (plot_stream, "set %stics %s %s %s %s %s %s;\n", ax,
-             tickdir, ticklength, axispos, mirror, colorspec, fontspec);
-  endif
-  if (strcmp (labelmode, "manual"))
     k = 1;
     ntics = numel (tics);
     labels(end+1:1) = {""};
     labels = repmat (labels(:), ceil (ntics/numel (labels)), 1);
-    fprintf (plot_stream, "set %stics add %s %s %s %s (", ax,
+    fprintf (plot_stream, "set %stics %s %s %s %s (", ax,
              tickdir, ticklength, axispos, mirror);
     labels = strrep (labels, "%", "%%");
     for i = 1:ntics
--- a/scripts/plot/util/private/__gnuplot_print__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__gnuplot_print__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -63,7 +63,7 @@
       if (any (strcmp (opts.devopt, {"eps", "epsc"})))
         gp_opts = [gp_opts " level1"];
       endif
-      if (opts.tight_flag || ! isempty (opts.preview))
+      if (opts.tight || ! isempty (opts.preview))
         tmp_file = [tempname() ".eps"];
         eps_drawnow (opts, tmp_file, gp_opts);
         if (dos_shell)
@@ -156,6 +156,8 @@
                "print.m: '%s' output is not available for gnuplot-%s",
                upper (opts.devopt), __gnuplot_version__ ());
       endif
+    case "dumb"
+      local_drawnow ("dumb size 72,24", opts.name, opts);
     case opts.ghostscript.device
       gp_opts = font_spec (opts, "devopt", "eps");
       opts.ghostscript.output = opts.name;
--- a/scripts/plot/util/private/__opengl_print__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__opengl_print__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -78,7 +78,15 @@
     case "svg"
       ## format GL2PS_SVG
       gl2ps_device = {"svg"};
-      pipeline = {sprintf("cat > %s", opts.name)};
+      svgcmd = "";
+      if (opts.svgconvert)
+        svgcmd = opts.svgconvert_cmd (opts, opts.ghostscript.device);
+      endif
+      if (! isempty (svgcmd))
+        pipeline = {sprintf(svgcmd, "svg", opts.name)};
+      else
+        pipeline = {sprintf("cat > %s", opts.name)};
+      endif
     case fig2dev_devices
       cmd_pstoedit = opts.pstoedit_cmd (opts, "fig");
       cmd_fig2dev = opts.fig2dev_cmd (opts, opts.devopt);
@@ -110,36 +118,63 @@
       pipeline = {sprintf("%s > %s", cmd, opts.name)};
     case {"corel", "gif"}
       error ("print:unsupporteddevice",
-             "print.m: %s output is not available for the FLTK graphics toolkit",
+             "print.m: %s output is not available for OpenGL graphics toolkits",
              upper (opts.devopt));
     case opts.ghostscript.device
-      opts.ghostscript.source = "-";
+      ## Except for postscript, use svg format and first convert to pdf
+      ## before going through ghostscript for final adjusments
+      svgcmd = "";
+      if (opts.svgconvert)
+        svgcmd = opts.svgconvert_cmd (opts, opts.ghostscript.device);
+      endif
+      dosvg = ! (strcmp (opts.devopt, "ps2write") || isempty (svgcmd));
+      if (! dosvg)
+        opts.ghostscript.source = "-";
+      else
+        tmp = tempname ();
+        opts.ghostscript.source = tmp;
+        opts.unlink = [opts.unlink tmp];
+        svgcmd = sprintf (svgcmd, "pdf", tmp);
+      endif
+
       opts.ghostscript.output = opts.name;
       if (opts.send_to_printer)
         opts.unlink(strcmp (opts.unlink, opts.ghostscript.output)) = [];
         opts.ghostscript.output = "-";
       endif
+
       [cmd_gs, cmd_cleanup] = __ghostscript__ (opts.ghostscript);
       if (opts.send_to_printer || isempty (opts.name))
         cmd_lpr = opts.lpr_cmd (opts);
         cmd = sprintf ("%s | %s", cmd_gs, cmd_lpr);
+      elseif (dosvg)
+        if (dos_shell)
+          cmd = sprintf ("%s & %s", svgcmd, cmd_gs);
+        else
+          cmd = sprintf ("%s ; %s", svgcmd, cmd_gs);
+        endif
       else
         cmd = sprintf ("%s", cmd_gs);
       endif
+
+      if (dosvg)
+        gl2ps_device = {"svg"};
+      else
+        gl2ps_device = {"eps"};
+      endif
+
       if (! isempty (cmd_cleanup))
-        gl2ps_device = {"eps"};
         if (dos_shell)
           pipeline = {sprintf("%s & %s", cmd, cmd_cleanup)};
         else
           pipeline = {sprintf("%s ; %s", cmd, cmd_cleanup)};
         endif
       else
-        gl2ps_device = {"eps"};
         pipeline = {cmd};
       endif
     otherwise
       error (sprintf ("print:no%soutput", opts.devopt),
-             "print.m: %s output is not available for GL2PS output",
+             "print.m: %s output is not available for OpenGL toolkits",
              upper (opts.devopt));
   endswitch
 
@@ -157,8 +192,7 @@
       ## Use toolkits "print_figure" method
       drawnow (gl2ps_device{n}, ['|' pipeline{n}]);
     else
-      ## Use OpenGL offscreen rendering with OSMesa
-      __osmesa_print__ (opts.figure, ['|' pipeline{n}], gl2ps_device{n});
+      error ("print: figure must be visible or qt toolkit must be used with __gl_window__ property 'on' or QT_OFFSCREEN feature available");
     endif
   endfor
 
--- a/scripts/plot/util/private/__print_parse_opts__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -45,22 +45,26 @@
   arg_st.ghostscript.epscrop = true;
   arg_st.ghostscript.level = 2;
   arg_st.ghostscript.output = "";
-  arg_st.ghostscript.papersize = "";
+  arg_st.ghostscript.papersize = "letter";
   arg_st.ghostscript.pageoffset = [];
   arg_st.ghostscript.resolution = 150;
   arg_st.ghostscript.antialiasing = false;
   arg_st.ghostscript.antialiasing_textalphabits = 4;
   arg_st.ghostscript.antialiasing_graphicsalphabits = 1;
-  arg_st.loose = false;
   arg_st.lpr_binary = __quote_path__ (__find_binary__ ("lpr"));
   arg_st.name = "";
   arg_st.orientation = "";
   arg_st.pstoedit_binary = __quote_path__ (__find_binary__ ("pstoedit"));
   arg_st.preview = "";
   arg_st.printer = "";
+  arg_st.renderer = "auto";
+  arg_st.resize_flag = "";
+  arg_st.rgb_output = false;
   arg_st.send_to_printer = false;
   arg_st.special_flag = "textnormal";
-  arg_st.tight_flag = false;
+  arg_st.svgconvert = false;
+  arg_st.svgconvert_binary = __quote_path__ (__svgconv_binary__ ());
+  arg_st.tight = true;
   arg_st.use_color = 0; # 0=default, -1=mono, +1=color
 
   if (isunix ())
@@ -90,18 +94,27 @@
         arg_st.force_solid = 1;
       elseif (strcmp (arg, "-dashed"))
         arg_st.force_solid = -1;
+      elseif (any (strcmp (arg, {"-opengl", "-painters"})))
+        arg_st.renderer = arg(2:end);
+      elseif (strcmp (arg, "-RGBImage"))
+        arg_st.rgb_output = true;
+        arg_st.renderer = "opengl";
       elseif (strncmp (arg, "-portrait", length (arg)))
         arg_st.orientation = "portrait";
       elseif (strncmp (arg, "-landscape", length (arg)))
         arg_st.orientation = "landscape";
       elseif (strcmp (arg, "-loose"))
-        arg_st.loose = true;
-        arg_st.tight_flag = false;
+        arg_st.tight = false;
       elseif (strcmp (arg, "-tight"))
-        arg_st.loose = false;
-        arg_st.tight_flag = true;
+        arg_st.tight = true;
+      elseif (strcmp (arg, "-svgconvert"))
+        arg_st.svgconvert = true;
       elseif (strcmp (arg, "-textspecial"))
         arg_st.special_flag = "textspecial";
+      elseif (strcmp (arg, "-fillpage"))
+        arg_st.resize_flag = "fillpage";
+      elseif (strcmp (arg, "-bestfit"))
+        arg_st.resize_flag = "bestfit";
       elseif (any (strcmp (arg,
                            {"-interchange", "-metafile", "-pict", "-tiff"})))
         arg_st.preview = arg(2:end);
@@ -154,10 +167,9 @@
         arg_st.ghostscript.resolution = str2double (arg(3:end));
       elseif (length (arg) > 2 && arg(1:2) == "-f")
         arg_st.figure = str2double (arg(3:end));
-      elseif (any (strcmp (arg, {"-painters", "-opengl"})))
-        warning ("print: '%s' accepted for Matlab compatibility, but is ignored", arg);
       elseif (strcmp (arg, "-noui"))
-        warning ("print: option '-noui' not yet implemented");
+        ## Accepted, but nothing needs to be done since Octave already
+        ## excludes uicontrol objects when printing.
       elseif (length (arg) >= 1 && arg(1) == "-")
         error ("print: unknown option '%s'", arg);
       elseif (length (arg) > 0)
@@ -170,11 +182,13 @@
     endif
   endfor
 
+  ## Resolution
   if (arg_st.ghostscript.resolution == 0)
     ## Do as Matlab does.
     arg_st.ghostscript.resolution = get (0, "screenpixelsperinch");
   endif
 
+  ## Orientation
   if (isempty (arg_st.orientation))
     if (isfigure (arg_st.figure))
       arg_st.orientation = get (arg_st.figure, "paperorientation");
@@ -184,15 +198,48 @@
     endif
   endif
 
+  ## The device is infered from extension if not provided
   dot = rindex (arg_st.name, ".");
   if (isempty (arg_st.devopt))
-    if (dot == 0)
+    if (arg_st.rgb_output)
+      arg_st.devopt = "png";
+    elseif (dot == 0)
       arg_st.devopt = "psc";
     else
       arg_st.devopt = tolower (arg_st.name(dot+1:end));
     endif
   endif
 
+  ## By default, postprocess svg files using svgconvert.
+  if (strcmp (arg_st.devopt, "svg"))
+    arg_st.svgconvert = true;
+  endif
+
+  ## By default, use the "opengl" renderer for all raster outputs
+  ## supported by "imwrite".
+  fmts = imformats ();
+  persistent gl_devlist = [fmts(! cellfun (@isempty, {fmts.write})).ext, ...
+                           "tiffn"];
+  opengl_ok = any (strcmp (gl_devlist, arg_st.devopt));
+
+  if (strcmp (arg_st.renderer, "auto")
+      && strcmp (get (arg_st.figure, "renderermode"), "manual"))
+    arg_st.renderer = get (arg_st.figure, "renderer");
+  endif
+
+  if (strcmp (arg_st.renderer, "auto"))
+    if (opengl_ok && strcmp (graphics_toolkit (arg_st.figure), "qt"))
+      arg_st.renderer = "opengl";
+    else
+      arg_st.renderer = "painters";
+    endif
+  elseif (strcmp (arg_st.renderer, "opengl") && ! opengl_ok)
+    arg_st.renderer = "painters";
+    warning (["print: unsupported output format \"%s\" for renderer ", ...
+              "\"opengl\"."], arg_st.devopt);
+  endif
+
+  
   if (arg_st.use_color == 0)
     if (any (strcmp ({"ps", "ps2", "eps", "eps2"}, arg_st.devopt)))
       arg_st.use_color = -1;
@@ -211,37 +258,41 @@
     arg_st.devopt = "emf";
   elseif (strcmp (arg_st.devopt, "jpg"))
     arg_st.devopt = "jpeg";
+  elseif (strcmp (arg_st.devopt, "tif"))
+    arg_st.devopt = "tiff";
+  elseif (strcmp (arg_st.devopt, "pdfcrop"))
+    arg_st.devopt = "pdfwrite";
   endif
 
-  persistent dev_list = {"aifm", "corel", "fig", "png", "jpeg", ...
+  persistent dev_list = [{"aifm", "corel", "dumb", "fig", "png", "jpeg", ...
               "gif", "pbm", "pbmraw", "dxf", "mf", ...
               "svg", "hpgl", "ps", "ps2", "psc", ...
               "psc2", "eps", "eps2", "epsc", "epsc2", ...
               "emf", "pdf", "pslatex", "epslatex", "epslatexstandalone", ...
               "pslatexstandalone", "pdflatexstandalone", ...
-              "pstex", "tiff", "tiffn" "tikz", "pcxmono", ...
+              "pstex", "tiff", "tiffn", "tikz", "tikzstandalone", "pcxmono", ...
               "pcx24b", "pcx256", "pcx16", "pgm", "pgmraw", ...
               "ppm", "ppmraw", "pdflatex", "texdraw", ...
               "epscairo", "pdfcairo", "pngcairo", "cairolatex", ...
               "pdfcairolatex", "pdfcairolatexstandalone", ...
               "epscairolatex", "epscairolatexstandalone", "pstricks", ...
               "epswrite", "eps2write", "pswrite", "ps2write", "pdfwrite", ...
-              "canvas", "cgm", "latex", "eepic"};
+              "canvas", "cgm", "latex", "eepic"}, gl_devlist];
 
-  persistent suffixes = {"ai", "cdr", "fig", "png", "jpg", ...
+  persistent suffixes = [{"ai", "cdr", "txt", "fig", "png", "jpg", ...
               "gif", "pbm", "pbm", "dxf", "mf", ...
               "svg", "hpgl", "ps", "ps", "ps", ...
               "ps", "eps", "eps", "eps", "eps", ...
               "emf", "pdf", "tex", "tex", "tex", ...
               "tex", "tex", ...
-              "ps", "tiff", "tiff", "tikz", "pcx", ...
+              "ps", "tiff", "tiff", "tikz", "tikz", "pcx", ...
               "pcx", "pcx", "pcx", "pgm", "pgm", ...
               "ppm", "ppm", "tex", "tex", ...
               "eps", "pdf", "png", "tex", ...
               "tex", "tex", ...
               "tex", "tex", "tex", ...
               "eps", "eps", "ps", "ps", "pdf", ...
-              "js", "cgm", "tex", "tex"};
+              "js", "cgm", "tex", "tex"}, gl_devlist];
 
   if (isfigure (arg_st.figure))
     __graphics_toolkit__ = get (arg_st.figure, "__graphics_toolkit__");
@@ -273,7 +324,8 @@
                                           "ps", "ps2", "psc", "psc2", "pdf"})))
       have_ghostscript = ! isempty (__ghostscript_binary__ ());
       if (have_ghostscript)
-        file_exists = (numel (dir (arg_st.name)) == 1 && ! isdir (arg_st.name));
+        file_exists = (numel (dir (arg_st.name)) == 1
+                       && ! isfolder (arg_st.name));
         if (! file_exists)
           arg_st.append_to_file = false;
         endif
@@ -288,7 +340,12 @@
     endif
   endif
 
-  if (! isempty (arg_st.printer) || isempty (arg_st.name))
+  if (arg_st.rgb_output)
+    if (! isempty (arg_st.printer) || ! isempty (arg_st.name))
+      warning ("octave:print:ignored_argument",
+               "print: ignoring file name and printer argument when using -RGBImage option");
+    endif
+  elseif (! isempty (arg_st.printer) || isempty (arg_st.name))
     arg_st.send_to_printer = true;
   endif
 
@@ -297,7 +354,8 @@
   endif
 
   aliases = gs_aliases ();
-  if (any (strcmp (arg_st.devopt, fieldnames (aliases))))
+  if (any (strcmp (arg_st.devopt, fieldnames (aliases)))
+      && ! strcmp (arg_st.renderer, "opengl"))
     arg_st.devopt = aliases.(arg_st.devopt);
     unknown_device = false;
   endif
@@ -311,7 +369,7 @@
     arg_st.ghostscript.output = arg_st.name;
     arg_st.ghostscript.antialiasing = true;
     if (arg_st.formatted_for_printing)
-      arg_st.ghostscript.epscrop = ! arg_st.loose;
+      arg_st.ghostscript.epscrop = arg_st.tight;
     else
       ## pstoedit throws errors if the EPS file isn't cropped
       arg_st.ghostscript.epscrop = true;
@@ -322,13 +380,21 @@
     arg_st.ghostscript.device = arg_st.devopt;
     arg_st.ghostscript.output = arg_st.name;
     arg_st.ghostscript.antialiasing = false;
-    arg_st.ghostscript.epscrop = ! arg_st.loose;
+    arg_st.ghostscript.epscrop = arg_st.tight;
   endif
 
   if (unknown_device)
     error ("print: unknown device %s", arg_st.devopt);
   endif
 
+  if (arg_st.resize_flag)
+    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);
+    endif
+  endif
+
   if (arg_st.send_to_printer)
     if (isempty (arg_st.name))
       ## Pipe the ghostscript output
@@ -340,19 +406,42 @@
       ## Only supported ghostscript devices
       error ("print: format must be a valid Ghostscript format for spooling to a printer");
     endif
-  elseif (isempty (arg_st.name))
+  elseif (isempty (arg_st.name) && ! arg_st.rgb_output)
     error ("print: an output filename must be specified");
   endif
 
   if (isempty (arg_st.canvas_size))
     if (isfigure (arg_st.figure))
-      [arg_st.ghostscript.papersize, paperposition] = ...
+      [arg_st.ghostscript.papersize, papersize_points, paperposition] = ...
                            gs_papersize (arg_st.figure, arg_st.orientation);
     else
       ## allows BIST tests to be run
       arg_st.ghostscript.papersize = "letter";
       paperposition = [0.25, 2.50, 8.00, 6.00] * 72;
+      papersize_points = [8.5, 11.0] * 72;
     endif
+
+    ## resize paper
+    if (arg_st.resize_flag)
+      if (strcmp (arg_st.resize_flag, "fillpage"))
+        ## leave a 0.25 inch margin on all sides of the page.
+        paperposition = [0.25 * 72, 0.25 * 72, ...
+                         papersize_points(1) - 0.5*72, ...
+                         papersize_points(2) - 0.5*72];
+      elseif (strcmp (arg_st.resize_flag, "bestfit"))
+        ## leaves a minimum page margin of 0.25 inches
+        if (paperposition(3) > paperposition(4))
+          fit_scale = papersize_points(1) / paperposition(3);
+        else
+          fit_scale = papersize_points(2) / paperposition(4);
+        endif
+        paperposition = [(papersize_points(1) - fit_scale*paperposition(3)) * 0.5, ...
+                        (papersize_points(2) - fit_scale*paperposition(4)) * 0.5, ...
+                        fit_scale * paperposition(3), ...
+                        fit_scale * paperposition(4)];
+      endif
+    endif
+
     arg_st.canvas_size = paperposition(3:4);
     if (strcmp (__graphics_toolkit__, "gnuplot")
         && ! arg_st.ghostscript.epscrop)
@@ -381,7 +470,9 @@
 
   if (warn_on_missing_ghostscript)
     if (isempty (arg_st.ghostscript.binary))
-      warning ("print:missing_gs", "print.m: Ghostscript binary is not available.  Only eps output is possible");
+      warning ("octave:print:missing_gs", ...
+               ["print.m: Ghostscript binary is not available.  ", ...
+                "Only eps output is possible"]);
     endif
     warn_on_missing_ghostscript = false;
   endif
@@ -413,7 +504,7 @@
 
 #%!test
 %! opts = __print_parse_opts__ ("-deps", "-tight");
-%! assert (opts.tight_flag, true);
+%! assert (opts.tight, true);
 %! assert (opts.send_to_printer, true);
 %! assert (opts.use_color, -1);
 %! assert (opts.ghostscript.device, "");
@@ -464,7 +555,6 @@
 
 endfunction
 
-
 function gs = __ghostscript_binary__ ()
 
   persistent ghostscript_binary = "";
@@ -476,7 +566,7 @@
         || (! isempty (GSC) && file_in_path (getenv ("PATH"), GSC)))
       gs_binaries = {GSC};
     elseif (! isempty (GSC) && warn_on_bad_gsc)
-      warning ("print:badgscenv",
+      warning ("octave:print:badgscenv",
                "print.m: GSC environment variable not set properly");
       warn_on_bad_gsc = false;
       gs_binaries = {};
@@ -502,6 +592,32 @@
 
 endfunction
 
+function bin = __svgconv_binary__ ()
+
+  persistent binary = "";
+
+  if (isempty (binary))
+    bindir = getenv ("OCTAVE_ARCHLIBDIR");
+    if (isempty (bindir))
+      bindir = __octave_config_info__ ("archlibdir");
+    endif
+    
+    binary = fullfile (bindir, "octave-svgconvert");
+
+    if (! exist (binary, "file"))
+      if (! isunix () && exist ([binary, ".exe"], "file"))
+        ## Unix - Includes Mac OSX and Cygwin.
+        binary = [binary, ".exe"];
+      else
+        binary = "";
+      endif
+    endif
+  endif
+
+  bin = binary;
+
+endfunction
+
 function bin = __find_binary__ (binary)
 
   persistent data = struct ();
@@ -528,7 +644,7 @@
 
 endfunction
 
-function [papersize, paperposition] = gs_papersize (hfig, paperorientation)
+function [papersize, papersize_points, paperposition] = gs_papersize (hfig, paperorientation)
   persistent papertypes papersizes;
 
   if (isempty (papertypes))
@@ -553,9 +669,9 @@
   paperposition = get (hfig, "paperposition");
   if (strcmp (papertype, "<custom>"))
     papersize = get (hfig, "papersize");
-    papersize = convert2points (papersize , paperunits);
+    papersize = convert2points (papersize, paperunits);
   else
-    papersize = papersizes (strcmp (papertypes, papertype), :);
+    papersize = papersizes(strcmp (papertypes, papertype), :);
   endif
 
   if (strcmp (paperunits, "normalized"))
@@ -565,12 +681,16 @@
   endif
 
   ## FIXME: This will be obsoleted by listeners for paper properties.
-  ##        Papersize is tall when portrait,and wide when landscape.
+  ##        papersize is tall when portrait, and wide when landscape.
   if ((papersize(1) > papersize(2) && strcmpi (paperorientation, "portrait"))
       || (papersize(1) < papersize(2) && strcmpi (paperorientation, "landscape")))
     papersize = papersize([2,1]);
   endif
 
+  ## papersize is now [h,w] and measured in points.
+  ## Return it for possible resize outside of this function.
+  papersize_points = papersize;
+
   if (! strcmp (papertype, "<custom>")
       && (strcmp (paperorientation, "portrait")))
     ## For portrait use the ghostscript name
@@ -598,7 +718,7 @@
     case "inches"
       value *= 72;
     case "centimeters"
-      value *= 72 / 2.54;
+      value *= (72 / 2.54);
     case "normalized"
       error ("print:customnormalized",
              "print.m: papersize=='<custom>' and paperunits='normalized' may not be combined");
@@ -614,10 +734,13 @@
                  "pcxcmyk"; "pcxgray"; "pcxmono"; "pdfwrite"; "pgm"; ...
                  "pgmraw"; "pgnm"; "pgnmraw"; "png16"; "png16m"; ...
                  "png256"; "png48"; "pngalpha"; "pnggray"; "pngmono"; ...
-                 "pnm"; "pnmraw"; "ppm"; "ppmraw"; "pswrite"; ...
-                 "ps2write"; "tiff12nc"; "tiff24nc"; "tiff32nc"; ...
-                 "tiffcrle"; "tiffg3"; "tiffg32d"; "tiffg4"; ...
-                 "tiffgray"; "tifflzw"; "tiffpack"; "tiffsep"};
+                 "pnm"; "pnmraw"; "ppm"; "ppmraw"; "pswrite"; "ps2write"; ...
+                 "tiff12nc"; "tiff24nc"; "tiff32nc"; "tiff48nc"; ...
+                 "tiff64nc"; "tiffcrle"; "tiffg3"; "tiffg32d"; "tiffg4"; ...
+                 "tiffgray"; "tifflzw"; "tiffpack"; "tiffscaled"; ...
+                 "tiffscaled24"; "tiffscaled32"; "tiffscaled4"; ...
+                 "tiffscaled8"; "tiffsep"; "tiffsep1" };
+
 endfunction
 
 function aliases = gs_aliases ()
@@ -633,6 +756,6 @@
   aliases.ps2   = "ps2write";
   aliases.psc   = "ps2write";
   aliases.psc2  = "ps2write";
-  aliases.tiff  = "tiff24nc";
+  aliases.tiff  = "tiffscaled24";
   aliases.tiffn = "tiff24nc";
 endfunction
--- a/scripts/plot/util/saveas.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/saveas.m	Thu Dec 20 17:18:56 2018 -0500
@@ -39,10 +39,13 @@
 ##     JPEG Image
 ##
 ##   @item png
-##     PNG Image
+##     Portable Network Graphics image
 ##
 ##   @item emf
-##     Enhanced Meta File
+##     Enhanced MetaFile
+##
+##   @item tif
+##     TIFF Image, compressed
 ##
 ## @end table
 ##
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/util/savefig.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,136 @@
+## Copyright (C) 2018 Guillaume Flandin
+##
+## 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.
+## 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 filename COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} savefig ()
+## @deftypefnx {} {} savefig (@var{h})
+## @deftypefnx {} {} savefig (@var{filename})
+## @deftypefnx {} {} savefig (@var{h}, @var{filename})
+## @deftypefnx {} {} savefig (@var{h}, @var{filename}, @qcode{"compact"})
+## Save figure windows specified by graphics handle(s) @var{h} to file
+## @var{filename}.
+##
+## If unspecified, @var{h} is the current figure returned by @code{gcf}.
+##
+## If unspecified, @var{filename} is set to @file{"Untitled.fig"}.  If
+## @var{filename} does not have an extension then the default extension
+## @file{".fig"} will be added.
+##
+## If the optional third input @qcode{"compact"} is present then the data
+## will be compressed to save more space.
+##
+## @seealso{hgsave, hdl2struct, openfig}
+## @end deftypefn
+
+function savefig (varargin)
+
+  if (nargin > 3)
+    print_usage ();
+  endif
+
+  ## Default values for input arguments
+  h = [];
+  filename = "Untitled.fig";
+  fmt = "-binary";
+
+  ## Check input arguments
+  if (nargin == 1)
+    if (all (isfigure (varargin{1})))
+      h = varargin{1};
+    elseif (ischar (varargin{1}))
+      filename = varargin{1};
+    else
+      error ("savefig: first argument must be a figure handle or filename");
+    endif
+  else
+    if (! all (isfigure (varargin{1})))
+      error ("savefig: H must be a valid figure handle");
+    endif
+    h = varargin{1};
+    if (! ischar (varargin{2}))
+      error ("savefig: FILENAME must be a string");
+    endif
+    filename = varargin{2};
+    if (nargin == 3)
+      if (strcmpi (varargin{3}, "compact"))
+        fmt = "-zip";
+      else
+        warning ("savefig: unrecognized option '%s'", varargin{3});
+      endif
+    endif
+  endif
+
+  ## Check figure handle input
+  if (isempty (h))
+    h = gcf ();
+  endif
+
+  ## Check filename extension
+  [~, ~, ext] = fileparts (filename);
+  if (isempty (ext))
+    filename = [filename ".fig"];
+  endif
+
+  ## Save handles to file
+  hgsave (h, filename, fmt);
+
+endfunction
+
+
+%!test
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   ftmp = [tempname() ".fig"];
+%!   savefig (h, ftmp);
+%!   savefig (ftmp);
+%! unwind_protect_cleanup
+%!   close (h);
+%!   unlink (ftmp);
+%! end_unwind_protect
+
+%!testif HAVE_ZLIB
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   ftmp = [tempname() ".fig"];
+%!   savefig (h, ftmp, "compact");
+%! unwind_protect_cleanup
+%!   close (h);
+%!   unlink (ftmp);
+%! end_unwind_protect
+
+## Test input validation
+%!error savefig (1,2,3,4)
+%!error <must be a figure handle or filename> savefig (struct ())
+%!error <H must be a valid figure handle> savefig ([0, -1], "foobar")
+%!error <FILENAME must be a string>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   savefig (h, -1);
+%! unwind_protect_cleanup
+%!   close (h);
+%! end_unwind_protect
+%!warning <unrecognized option 'foobar'>
+%! unwind_protect
+%!   h = figure ("visible", "off");
+%!   ftmp = [tempname() ".fig"];
+%!   savefig (h, ftmp, "foobar");
+%! unwind_protect_cleanup
+%!   close (h);
+%!   unlink (ftmp);
+%! end_unwind_protect
--- a/scripts/plot/util/shg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/shg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -20,8 +20,12 @@
 ## @deftypefn {} {} shg
 ## Show the graph window.
 ##
-## Currently, this is the same as executing @code{drawnow}.
-## @seealso{drawnow, figure}
+## This function makes the current figure visible, and places it on top of
+## of all other plot windows.
+##
+## Programming Note: @code{shg} is equivalent to @code{figure (gcf)} assuming
+## that a current figure exists.
+## @seealso{figure, drawnow, gcf}
 ## @end deftypefn
 
 ## Author: jwe
@@ -32,6 +36,10 @@
     warning ("shg: ignoring extra arguments");
   endif
 
-  drawnow ();
+  hf = get (0, "currentfigure");
+  if (! isempty (hf))
+    set (hf, "visible", "on");
+    __show_figure__ (hf));
+  endif
 
 endfunction
--- a/scripts/plot/util/struct2hdl.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/struct2hdl.m	Thu Dec 20 17:18:56 2018 -0500
@@ -96,14 +96,18 @@
     p = p(1:2, 1:(tst(end)-1));
   endif
 
+  ## Use lowercase for all properties
+  s.properties = cell2struct (struct2cell (s.properties), ...
+                              tolower (fieldnames (s.properties)));
+
   ## Place the "*mode" properties at the end to avoid having the updaters
   ## 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"));
   names = [names(! n); names(n)];
-  if (strcmp (s.type, "axes"))
-    n_pos = find (strcmp (names, "position") | strcmp (names, "outerposition"));
+  n_pos = find (strcmp (names, "position") | strcmp (names, "outerposition"));
+  if (strcmp (s.type, "axes") && numel (n_pos) == 2)
     if (strcmp (s.properties.activepositionproperty, "position"))
       names{n_pos(1)} = "outerposition";
       names{n_pos(2)} = "position";
@@ -123,14 +127,15 @@
     h = 0;
     s.properties = rmfield (s.properties, ...
                               {"callbackobject", "commandwindowsize", ...
+                               "monitorpositions", "pointerwindow", ...
                                "screendepth", "screenpixelsperinch", ...
                                "screensize"});
   elseif (strcmp (s.type, "figure"))
-    h = figure ();
+    [h, s] = createfigure (s);
   elseif (strcmp (s.type, "axes"))
-    ## legends and colorbars are "transformed" in normal axes
-    ## if hilev is not requested
-    if (! hilev)
+    ## legends and colorbars are "transformed" in to normal axes
+    ## if hilev is not requested.
+    if (! hilev && isfield (s.properties, "tag"))
       if (strcmp (s.properties.tag, "legend"))
         s.properties.tag = "";
         s.properties.userdata = [];
@@ -141,13 +146,18 @@
         par = gcf;
       endif
     endif
-
+    if (isfield (s.properties, "tightinset"))
+      s.properties = rmfield (s.properties, {"tightinset"});
+    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, "text"))
+    if (isfield (s.properties, "extent"))
+      s.properties = rmfield (s.properties, "extent");
+    endif
     h = createtext (s, par);
   elseif (strcmp (s.type, "image"))
     h = createimage (s, par);
@@ -155,6 +165,13 @@
     h = createsurface (s, par);
   elseif (strcmp (s.type, "hggroup"))
     [h, s, p] = createhg (s, p, par, hilev);
+  elseif (any (strcmp (s.type, {"uimenu", "uicontextmenu",...
+                                "uicontrol", "uipanel", "uibuttongroup",...
+                                "uitoolbar", "uipushtool", "uitable"})))
+    if (isfield (s.properties, "extent"))
+      s.properties = rmfield (s.properties, "extent");
+    endif
+    [h, s] = createui (s, par);
   else
     error ("struct2hdl: %s objects are not implemented yet", s.type);
   endif
@@ -179,9 +196,29 @@
 
 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.
+    opts = [opts {"integerhandle", s.properties.integerhandle}];
+    s.properties = rmfield (s.properties, "integerhandle");
+  endif
+  h = figure (opts{:});
+  rmprops = {"currentaxes", "currentcharacter", "currentobject", ...
+             "currentpoint", "number"};
+  rmprops (! isfield (s.properties, rmprops)) = [];
+  s.properties = rmfield (s.properties, rmprops);
+  if (! isfield (s.properties, "visible"))
+    s.properties.visible = "on";
+  endif
+  addmissingprops (h, s.properties);
+  sout = s;
+endfunction
+
 function [h, sout] = createaxes (s, p, par)
 
-  if (! any (strcmpi (s.properties.tag, {"colorbar", "legend"})))
+  if (! isfield (s.properties, "tag")
+      || ! any (strcmpi (s.properties.tag, {"colorbar", "legend"})))
     ## regular axes
     propval = {"position", s.properties.position};
     hid = {"__autopos_tag__", "looseinset"};
@@ -330,6 +367,14 @@
   addmissingprops (h, s.properties);
 endfunction
 
+function [h, s] = createui (s, par)
+  if (isfield (s.properties, "style") && strcmp (s.properties.style, "frame"))
+    s.type = "uipanel";  # frame is deprecated: use uipanel instead
+  endif
+  h = feval (s.type, "parent", par);
+  addmissingprops (h, s.properties);
+endfunction
+
 function [h, sout, pout] = createhg (s, p, par, hilev)
   ## Here we infer from properties the type of hggroup we should build
   ## an call corresponding high level functions
@@ -566,8 +611,14 @@
 
 function setprops (s, h, p, hilev)
 
-  if (! any (strcmpi (s.properties.tag, {"colorbar", "legend"})))
-    specs = s.children(s.special);
+  isspecial = (isfield (s.properties, "tag")
+               && any (strcmpi (s.properties.tag, {"colorbar", "legend"})));
+  if (! isspecial)
+    try
+      specs = s.children(s.special);
+    catch
+      specs = [];
+    end_try_catch
     if (isempty (specs))
       hdls = [];
     else
@@ -579,8 +630,8 @@
       set (h, s.properties);
     else
       ## Specials are objects that where automatically constructed with
-      ## current object.  Among them are "x(yz)labels", "title", high
-      ## level hggroup children
+      ## current object.  Among them are "x(yz)labels", "title", and
+      ## high level hggroup children
       fields = fieldnames (s.properties);
       vals = struct2cell (s.properties);
       idx = find (cellfun (@(x) valcomp(x, hdls) , vals));
@@ -597,8 +648,14 @@
         field = fields{nf};
         idx = find (hdls == vals{nf});
         spec = specs(idx);
+        ## FIXME: Wouldn't it be better to call struct2hdl recursively
+        ##        for this handle?  That way the function could determine
+        ##        based on type what special actions to take.
+        try
+          spec.properties = rmfield (spec.properties, "extent");
+        end_try_catch
         if (isprop (h, field))
-          h2 = get (h , field);
+          h2 = get (h, field);
           addmissingprops (h2, spec.properties);
           set (h2, spec.properties);
         endif
--- a/scripts/plot/util/subplot.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/plot/util/subplot.m	Thu Dec 20 17:18:56 2018 -0500
@@ -436,7 +436,7 @@
       if (iscell (opos))
         opos = cell2mat (opos);
       endif
-      for ii = 1:numel (hsubplots);
+      for ii = 1:numel (hsubplots)
         set (hsubplots(ii), "outerposition", opos(ii,:), ...
              "activepositionproperty", "position");
       endfor
--- a/scripts/polynomial/conv.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/conv.m	Thu Dec 20 17:18:56 2018 -0500
@@ -61,36 +61,17 @@
     error ('conv: SHAPE argument must be "full", "same", or "valid"');
   endif
 
-  la = la_orig = length (a);
-  lb = lb_orig = length (b);
-
-  ly = la + lb - 1;
-
-  if (ly == 0)
-    y = zeros (1, 0);
-    return;
-  endif
+  y = conv2 (a(:), b(:), shape);
 
-  ## Use shortest vector as the coefficent vector to filter.
-  if (la > lb)
-    [a, b] = deal (b, a);  # Swap vectors
-    lb = la;
-  endif
-  x = b;
-
-  ## Pad longer vector to convolution length.
-  if (ly > lb)
-    x(end+1:end+ly-lb) = 0;
-  endif
-
-  y = filter (a, 1, x);
-
-  if (strcmpi (shape, "same"))
-    idx = ceil ((ly - la) / 2);
-    y = y(idx+1:idx+la);
-  elseif (strcmpi (shape, "valid"))
-    len = la_orig - lb_orig;
-    y = y(lb_orig:lb_orig+len);
+  if (strcmpi (shape, "full"))
+    ## Adapt the shape to the longest input argument, if necessary.
+    if ((length (a) > length (b) && isrow (a)) ...
+        || (length (a) <= length (b) && isrow (b)))
+      y = y.';
+    endif
+  elseif (isrow (a))
+    ## Adapt the shape to the first input argument, if necessary.
+    y = y.';
   endif
 
 endfunction
--- a/scripts/polynomial/mkpp.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/mkpp.m	Thu Dec 20 17:18:56 2018 -0500
@@ -42,6 +42,10 @@
 ## @var{r}-th polynomial defined on interval @var{i}.  In any case @var{coefs}
 ## is reshaped to a 2-D matrix of size @code{[@var{ni}*prod(@var{d}) @var{m}]}.
 ##
+## Programming Note: @code{ppval} evaluates polynomials at
+## @code{@var{xi} - @var{breaks}(i)}, i.e., it subtracts the lower endpoint of
+## the current interval from @var{xi}.  This must be taken into account when
+## creating piecewise polynomials objects with @code{mkpp}.
 ## @seealso{unmkpp, ppval, spline, pchip, ppder, ppint, ppjumps}
 ## @end deftypefn
 
--- a/scripts/polynomial/poly.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/poly.m	Thu Dec 20 17:18:56 2018 -0500
@@ -73,12 +73,18 @@
 
   y = zeros (1, n+1);
   y(1) = 1;
-  for j = 1:n;
-    y(2:(j+1)) = y(2:(j+1)) - v(j) .* y(1:j);
+  for j = 1:n
+    y(2:(j+1)) -= v(j) .* y(1:j);
   endfor
 
-  if (all (all (imag (x) == 0)))
+  ## Real, or complex conjugate inputs, should result in real output
+  if (isreal (x))
     y = real (y);
+  else
+    tmp = sort (v(imag (v) > 0)) == sort (conj (v(imag (v) < 0)));
+    if (! isempty (tmp) && all (tmp))
+      y = real (y);
+    endif
   endif
 
 endfunction
@@ -88,4 +94,12 @@
 %!assert (poly ([1, 2, 3]), [1, -6, 11, -6])
 %!assert (poly ([1, 2; 3, 4]), [1, -5, -2], sqrt (eps))
 
+%!test <*53897>
+%! x = [1, sqrt(2)/2+sqrt(2)/2*i, 1i, -sqrt(2)/2+sqrt(2)/2*i, -1, ...
+%!      -sqrt(2)/2-sqrt(2)/2*i, -1i, sqrt(2)/2-sqrt(2)/2*i];
+%! y = poly (x);
+%! assert (isreal (y), true);
+
+%!error poly ()
+%!error poly (1,2)
 %!error poly ([1, 2, 3; 4, 5, 6])
--- a/scripts/polynomial/polyeig.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/polyeig.m	Thu Dec 20 17:18:56 2018 -0500
@@ -40,18 +40,15 @@
 ## @seealso{eig, eigs, compan}
 ## @end deftypefn
 
-## Author: Fotios Kasolis
-
 function [z, v] = polyeig (varargin)
 
   if (nargin < 1 || nargout > 2)
     print_usage ();
   endif
 
-  nin = numel (varargin);
   n = rows (varargin{1});
 
-  for i = 1 : nin
+  for i = 1 : nargin
     if (! issquare (varargin{i}))
       error ("polyeig: coefficients must be square matrices");
     endif
@@ -61,33 +58,33 @@
   endfor
 
   ## matrix polynomial degree
-  l = nin - 1;
+  l = nargin - 1;
 
   ## form needed matrices
   C = [ zeros(n * (l - 1), n), eye(n * (l - 1));
        -cell2mat(varargin(1:end-1)) ];
 
   D = [ eye(n * (l - 1)), zeros(n * (l - 1), n);
-       zeros(n, n * (l - 1)), varargin{end} ];
+        zeros(n, n * (l - 1)), varargin{end} ];
 
   ## solve generalized eigenvalue problem
-  if (nargout == 2)
+  if (nargout < 2)
+    z = eig (C, D);
+  else
     [z, v] = eig (C, D);
     v = diag (v);
     ## return n-element eigenvectors normalized so that the infinity-norm = 1
     z = z(1:n,:);
-    ## max() takes the abs if complex:
-    t = max (z);
-    z /= diag (t);
-  else
-    z = eig (C, D);
+    t = max (z);    # max() takes the abs if complex.
+    z ./= t;
   endif
 
 endfunction
 
 
 %!shared C0, C1
-%! C0 = [8, 0; 0, 4]; C1 = [1, 0; 0, 1];
+%! C0 = [8, 0; 0, 4];
+%! C1 = [1, 0; 0, 1];
 
 %!test
 %! z = polyeig (C0, C1);
@@ -104,4 +101,5 @@
 %!error polyeig ()
 %!error [a,b,c] = polyeig (1)
 %!error <coefficients must be square matrices> polyeig (ones (3,2))
-%!error <coefficients must have the same dimensions> polyeig (ones (3,3), ones (2,2))
+%!error <coefficients must have the same dimensions>
+%! polyeig (ones (3,3), ones (2,2))
--- a/scripts/polynomial/ppjumps.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/ppjumps.m	Thu Dec 20 17:18:56 2018 -0500
@@ -50,7 +50,7 @@
     llim = shiftdim (reshape (P(1:(n-1) * prod (d), 1), [d, n-1]), nd - 1);
   endif
 
-  for i = 2 : k;
+  for i = 2 : k
     llim .*= dx;
     llim += shiftdim (reshape (P(1:(n-1) * prod (d), i), [d, n-1]), nd - 1);
   endfor
--- a/scripts/polynomial/ppval.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/ppval.m	Thu Dec 20 17:18:56 2018 -0500
@@ -80,7 +80,7 @@
     yi = shiftdim (reshape (Pidx, dimvec), ndv - 1);
   endif
 
-  for i = 2 : k;
+  for i = 2 : k
     yi .*= dx;
     yi += shiftdim (reshape (Pidx(i,:), dimvec), ndv - 1);
   endfor
--- a/scripts/polynomial/residue.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/polynomial/residue.m	Thu Dec 20 17:18:56 2018 -0500
@@ -87,8 +87,8 @@
 ## polynomial specified by @var{r}, @var{p} and @var{k}, and the pole
 ## multiplicity @var{e}.
 ##
-## If the multiplicity, @var{e}, is not explicitly specified the
-## multiplicity is determined by the function @code{mpoles}.
+## If the multiplicity, @var{e}, is not explicitly specified the multiplicity
+## is determined by the function @code{mpoles}.
 ##
 ## For example:
 ##
@@ -151,7 +151,7 @@
     print_usage ();
   endif
 
-  toler = .001;
+  tol = .001;
 
   if (nargin >= 3)
     if (nargin >= 4)
@@ -159,14 +159,13 @@
     else
       e = [];
     endif
-    ## The inputs are the residue, pole, and direct part.  Solve for the
-    ## corresponding numerator and denominator polynomials
-    [r, p] = rresidue (b, a, varargin{1}, toler, e);
+    ## The inputs are the residue, pole, and direct part.
+    ## Solve for the corresponding numerator and denominator polynomials.
+    [r, p] = rresidue (b, a, varargin{1}, tol, e);
     return;
   endif
 
-  ## Make sure both polynomials are in reduced form.
-
+  ## Make sure both polynomials are in reduced form, and scaled.
   a = polyreduce (a);
   b = polyreduce (b);
 
@@ -177,7 +176,6 @@
   lb = length (b);
 
   ## Handle special cases here.
-
   if (la == 0 || lb == 0)
     k = r = p = e = [];
     return;
@@ -188,19 +186,16 @@
   endif
 
   ## Find the poles.
-
   p = roots (a);
   lp = length (p);
 
   ## Sort poles so that multiplicity loop will work.
-
-  [e, indx] = mpoles (p, toler, 1);
-  p = p(indx);
+  [e, idx] = mpoles (p, tol, 1);
+  p = p(idx);
 
   ## For each group of pole multiplicity, set the value of each
   ## pole to the average of the group.  This reduces the error in
   ## the resulting poles.
-
   p_group = cumsum (e == 1);
   for ng = 1:p_group(end)
     m = find (p_group == ng);
@@ -208,7 +203,6 @@
   endfor
 
   ## Find the direct term if there is one.
-
   if (lb >= la)
     ## Also return the reduced numerator.
     [k, b] = deconv (b, a);
@@ -218,7 +212,6 @@
   endif
 
   ## Determine if the poles are (effectively) zero.
-
   small = max (abs (p));
   if (isa (a, "single") || isa (b, "single"))
     small = max ([small, 1]) * eps ("single") * 1e4 * (1 + numel (p))^2;
@@ -228,36 +221,31 @@
   p(abs (p) < small) = 0;
 
   ## Determine if the poles are (effectively) real, or imaginary.
+  idx = (abs (imag (p)) < small);
+  p(idx) = real (p(idx));
+  idx = (abs (real (p)) < small);
+  p(idx) = 1i * imag (p(idx));
 
-  index = (abs (imag (p)) < small);
-  p(index) = real (p(index));
-  index = (abs (real (p)) < small);
-  p(index) = 1i * imag (p(index));
-
-  ## The remainder determines the residues.  The case of one pole
-  ## is trivial.
-
+  ## The remainder determines the residues.  The case of one pole is trivial.
   if (lp == 1)
     r = polyval (b, p);
     return;
   endif
 
   ## Determine the order of the denominator and remaining numerator.
-  ## With the direct term removed the potential order of the numerator
+  ## With the direct term removed, the potential order of the numerator
   ## is one less than the order of the denominator.
-
   aorder = numel (a) - 1;
   border = aorder - 1;
 
   ## Construct a system of equations relating the individual
   ## contributions from each residue to the complete numerator.
-
   A = zeros (border+1, border+1);
   B = prepad (reshape (b, [numel(b), 1]), border+1, 0);
   for ip = 1:numel (p)
     ri = zeros (size (p));
     ri(ip) = 1;
-    A(:,ip) = prepad (rresidue (ri, p, [], toler), border+1, 0).';
+    A(:,ip) = prepad (rresidue (ri, p, [], tol), border+1, 0).';
   endfor
 
   ## Solve for the residues.
@@ -269,37 +257,20 @@
 
 endfunction
 
-function [pnum, pden, e] = rresidue (r, p, k, toler, e)
-
-  ## Reconstitute the numerator and denominator polynomials from the
-  ## residues, poles, and direct term.
+## Reconstitute the numerator and denominator polynomials
+## from the residues, poles, and direct term.
+function [pnum, pden, e] = rresidue (r, p, k = [], tol = [], e = [])
 
-  if (nargin < 2 || nargin > 5)
-    print_usage ();
-  endif
-
-  if (nargin < 5)
-    e = [];
+  if (! isempty (e))
+    idx = 1:numel (p);
+  else
+    [e, idx] = mpoles (p, tol, 0);
+    p = p(idx);
+    r = r(idx);
   endif
 
-  if (nargin < 4)
-    toler = [];
-  endif
-
-  if (nargin < 3)
-    k = [];
-  endif
-
-  if (numel (e))
-    indx = 1:numel (p);
-  else
-    [e, indx] = mpoles (p, toler, 0);
-    p = p(indx);
-    r = r(indx);
-  endif
-
-  indx = 1:numel (p);
-  for n = indx
+  idx = 1:numel (p);
+  for n = idx
     pn = [1, -p(n)];
     if (n == 1)
       pden = pn;
@@ -320,7 +291,7 @@
   K = numel (k) - 1;
   N = K + D;
   pnum = zeros (1, N+1);
-  for n = indx(abs (r) > 0)
+  for n = idx(abs (r) > 0)
     p1 = [1, -p(n)];
     pn = 1;
     for j = 1:n - 1
--- a/scripts/prefs/getpref.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/prefs/getpref.m	Thu Dec 20 17:18:56 2018 -0500
@@ -145,7 +145,7 @@
 %!
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (exist (tmp_home, "dir"))
+%!   if (isfolder (tmp_home))
 %!     rmdir (tmp_home);
 %!   endif
 %!   if (isempty (HOME))
--- a/scripts/prefs/prefdir.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/prefs/prefdir.m	Thu Dec 20 17:18:56 2018 -0500
@@ -48,7 +48,7 @@
   dir = get_home_directory ();
 
   if (nargin > 0)
-    if (! exist (dir, "dir"))
+    if (! isfolder (dir))
       mkdir (dir);
     endif
   endif
--- a/scripts/prefs/setpref.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/prefs/setpref.m	Thu Dec 20 17:18:56 2018 -0500
@@ -91,7 +91,7 @@
 %!         "size mismatch for PREF and VAL");
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (exist (tmp_home, "dir"))
+%!   if (isfolder (tmp_home))
 %!     rmdir (tmp_home);
 %!   endif
 %!   if (isempty (HOME))
--- a/scripts/profiler/profexport.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/profiler/profexport.m	Thu Dec 20 17:18:56 2018 -0500
@@ -64,7 +64,7 @@
     endif
   endif
 
-  if (! exist (dir, "dir"))
+  if (! isfolder (dir))
     ok = mkdir (dir);
     if (! ok)
       error ("profexport: failed to create output directory '%s'", dir);
--- a/scripts/set/ismember.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/set/ismember.m	Thu Dec 20 17:18:56 2018 -0500
@@ -108,6 +108,13 @@
     a = {a};
   endif
 
+  ## Another Matlab-compatible behavior.  See bug #53924.
+  if (isnumeric (a) && ischar (s))
+    s = double (s);
+  elseif (ischar (a) && isnumeric (s))
+    a = double (a);
+  endif
+
   [a, s] = validsetargs ("ismember", a, s, varargin{:});
 
   by_rows = nargin == 3;
@@ -165,12 +172,15 @@
 %!assert (ismember ("abc", {"abc", "def"}), true)
 %!assert (isempty (ismember ([], [1, 2])), true)
 %!assert (isempty (ismember ({}, {'a', 'b'})), true)
+%!assert (isempty (ismember ([], 'a')), true)
 %!assert (ismember ("", {"abc", "def"}), false)
+%!assert (ismember (1, 'abc'), false)
+%!assert (ismember ("abc", 1), [false false false])
+%!assert (ismember ("abc", 99), [false false true])
 %!fail ("ismember ([], {1, 2})")
 %!fail ("ismember ({[]}, {1, 2})")
 %!fail ("ismember ({}, {1, 2})")
 %!fail ("ismember ({1}, {'1', '2'})")
-%!fail ("ismember (1, 'abc')")
 %!fail ("ismember ({'1'}, {'1' '2'},'rows')")
 %!fail ("ismember ([1 2 3], [5 4 3 1], 'rows')")
 %!assert (ismember ({"foo", "bar"}, {"foobar"}), [false false])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/signal/__parse_movargs__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,99 @@
+## Copyright (C) 2018 Juan Pablo Carbajal
+##
+## 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/>.
+
+## Author: Juan Pablo Carbajal <ajuanpi+dev@gmail.com>
+## Created: 2018-08-13
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{args} =} __parse_movargs__ (@var{varargin})
+##
+## Parse arguments for movXXX functions before passing to @code{movfun}.
+##
+## @seealso{movfun}
+## @end deftypefn
+
+function args = __parse_movargs__ (caller, varargin)
+
+  args = {};
+
+  have_dim = have_nancond = false;
+  imax = numel (varargin);
+  i = 1;
+  while (i <= imax)
+    arg = varargin{i};
+    if (ischar (arg))
+      if (any (strcmpi (arg, {"omitnan", "includenan"})))
+        args(end+(1:2)) = {"nancond", arg};
+        have_nancond = true;
+      else
+        i += 1;  # Prop/Val pair
+        if (i > imax)
+          error ([caller ": property '%s' missing value argument"], arg);
+        endif
+        args(end+(1:2)) = {arg, varargin{i}};
+      endif
+    elseif (isnumeric (arg))
+      args(end+(1:2)) = {"dim", arg};
+      have_dim = true;
+    else
+      error ("Octave:invalid-input-arg",
+             [caller ": invalid input at position %d"], i);
+      args(end+1) = arg;
+    endif
+
+    i += 1;  # Advance to next element
+    if (have_nancond && have_dim)
+      args = [args, varargin(i:end)];
+      break;
+    endif
+  endwhile
+
+endfunction
+
+
+%!test
+%! caller = "tstblock";
+%! vararg = {5};
+%! assert (__parse_movargs__ (caller, vararg{:}), {"dim", 5});
+%! vararg = {"Endpoints", "shrink", 3};
+%! assert (__parse_movargs__ (caller, vararg{:}),
+%!         {"Endpoints", "shrink", "dim", 3});
+%! vararg = {"includenan", 2};
+%! assert (__parse_movargs__ (caller, vararg{:}),
+%!         {"nancond", "includenan", "dim", 2});
+
+%!test
+%! caller = "tstblock";
+%! vararg = {"INCLUDENAN"};
+%! assert (__parse_movargs__ (caller, vararg{:}), {"nancond", "INCLUDENAN"});
+%! vararg = {"Endpoints", "fill", "OMITNAN"};
+%! assert (__parse_movargs__ (caller, vararg{:}),
+%!         {"Endpoints", "fill", "nancond", "OMITNAN"});
+%! vararg = {2, "includenan"};
+%! assert (__parse_movargs__ (caller, vararg{:}),
+%!         {"dim", 2, "nancond", "includenan"});
+
+%!test
+%! caller = "tstblock";
+%! vararg = {};
+%! assert (__parse_movargs__ (caller, vararg{:}), {});
+%! vararg = {"Endpoints", "fill"};
+%! assert (__parse_movargs__ (caller, vararg{:}), {"Endpoints", "fill"});
+%! vararg = {5, "omitnan", "Endpoints", "fill"};
+%! assert (__parse_movargs__ (caller, vararg{:}),
+%!         {"dim", 5, "nancond", "omitnan", "Endpoints", "fill"});
--- a/scripts/signal/arch_fit.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/arch_fit.m	Thu Dec 20 17:18:56 2018 -0500
@@ -91,15 +91,15 @@
   esq = e.^2;
   Z = autoreg_matrix (esq, p);
 
-  for i = 1 : iter;
+  for i = 1 : iter
     h   = Z * a;
     tmp = esq ./ h.^2 - 1 ./ h;
     s   = 1 ./ h(1:T-p);
-    for j = 1 : p;
+    for j = 1 : p
       s -= a(j+1) * tmp(j+1:T-p+j);
     endfor
     r = 1 ./ h(1:T-p);
-    for j = 1:p;
+    for j = 1:p
       r += 2 * h(j+1:T-p+j).^2 .* esq(1:T-p);
     endfor
     r = sqrt (r);
--- a/scripts/signal/autoreg_matrix.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/autoreg_matrix.m	Thu Dec 20 17:18:56 2018 -0500
@@ -44,7 +44,7 @@
   T = length (y);
   y = reshape (y, T, 1);
   X = ones (T, k+1);
-  for j = 1 : k;
+  for j = 1 : k
     X(:, j+1) = [(zeros (j, 1)); y(1:T-j)];
   endfor
 
--- a/scripts/signal/fftconv.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/fftconv.m	Thu Dec 20 17:18:56 2018 -0500
@@ -66,7 +66,7 @@
 
 
 ## FIXME: Borrow tests from conv.m.  May need tolerance on the assert stmt.
-%!test
+%!testif HAVE_FFTW
 %! x = ones (3,1);
 %! y = ones (1,3);
 %! b = 2;
--- a/scripts/signal/fftfilt.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/fftfilt.m	Thu Dec 20 17:18:56 2018 -0500
@@ -85,7 +85,7 @@
     B = B(:, ones (c_x,1));
     R = ceil (r_x / L);
     y = zeros (r_x, c_x);
-    for r = 1:R;
+    for r = 1:R
       lo = (r - 1) * L + 1;
       hi = min (r * L, r_x);
       tmp = zeros (n, c_x);
@@ -132,7 +132,7 @@
 
 %!shared b, x, r
 
-%!test
+%!testif HAVE_FFTW
 %! b = [1 1];
 %! x = [1, zeros(1,9)];
 %! assert (fftfilt (b,  x  ), [1 1 0 0 0 0 0 0 0 0]  );
@@ -142,14 +142,14 @@
 %! assert (fftfilt (b,  [x.' x.']), [1 1 0 0 0 0 0 0 0 0].'*[1 1]);
 %! assert (fftfilt (b,  [x.'+2*eps x.']) == [1 1 0 0 0 0 0 0 0 0].'*[1 1], [false(10, 1) true(10, 1)]);
 
-%!test
+%!testif HAVE_FFTW
 %! r = sqrt (1/2) * (1+i);
 %! b = b*r;
 %! assert (fftfilt (b, x  ), r*[1 1 0 0 0 0 0 0 0 0]  , eps  );
 %! assert (fftfilt (b, r*x), r*r*[1 1 0 0 0 0 0 0 0 0], 2*eps);
 %! assert (fftfilt (b, x.'), r*[1 1 0 0 0 0 0 0 0 0].', eps  );
 
-%!test
+%!testif HAVE_FFTW
 %! b  = [1 1];
 %! x  = zeros (10,3); x(1,1)=-1; x(1,2)=1;
 %! y0 = zeros (10,3); y0(1:2,1)=-1; y0(1:2,2)=1;
@@ -166,7 +166,7 @@
 %! assert (true, isreal (y(:,1)));
 %! assert (false, any (real (y(:,2))));
 
-%!test
+%!testif HAVE_FFTW
 %! b  = rand (10, 1);
 %! x  = rand (10, 1);
 %! y0 = filter (b, 1, x);
@@ -176,7 +176,7 @@
 %! y  = fftfilt (b*i, x*i);
 %! assert (y0, y, 16*eps);
 
-%!test
+%!testif HAVE_FFTW
 %! b  = rand (10, 1) + i*rand (10, 1);
 %! x  = rand (10, 1) + i*rand (10, 1);
 %! y0 = filter (b, 1, x);
--- a/scripts/signal/freqz.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/freqz.m	Thu Dec 20 17:18:56 2018 -0500
@@ -201,7 +201,7 @@
 endfunction
 
 
-%!test # correct values and fft-polyval consistency
+%!testif HAVE_FFTW # correct values and fft-polyval consistency
 %! ## butterworth filter, order 2, cutoff pi/2 radians
 %! b = [0.292893218813452  0.585786437626905  0.292893218813452];
 %! a = [1  0  0.171572875253810];
@@ -210,7 +210,7 @@
 %! assert (abs (h(17)).^2,0.5,10*eps);
 %! assert (h,freqz (b,a,w),10*eps);  # fft should be consistent with polyval
 
-%!test # whole-half consistency
+%!testif HAVE_FFTW # whole-half consistency
 %! b = [1 1 1]/3; # 3-sample average
 %! [h,w] = freqz (b,1,32,"whole");
 %! assert (h(2:16),conj (h(32:-1:18)),20*eps);
@@ -218,7 +218,7 @@
 %! assert (h(1:16),h2,20*eps);
 %! assert (w(1:16),w2,20*eps);
 
-%!test # Sampling frequency properly interpreted
+%!testif HAVE_FFTW # Sampling frequency properly interpreted
 %! b = [1 1 1]/3; a = [1 0.2];
 %! [h,f] = freqz (b,a,16,320);
 %! assert (f,[0:15]'*10,10*eps);
--- a/scripts/signal/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -9,6 +9,7 @@
   %reldir%/private/triangle_sw.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/__parse_movargs__.m \
   %reldir%/arch_fit.m \
   %reldir%/arch_rnd.m \
   %reldir%/arch_test.m \
@@ -30,6 +31,8 @@
   %reldir%/hanning.m \
   %reldir%/hurst.m \
   %reldir%/ifftshift.m \
+  %reldir%/movfun.m \
+  %reldir%/movslice.m \
   %reldir%/periodogram.m \
   %reldir%/sinc.m \
   %reldir%/sinetone.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/signal/movfun.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,620 @@
+## Copyright (C) 2018 Juan Pablo Carbajal
+##
+## 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/>.
+
+## Author: Juan Pablo Carbajal <ajuanpi+dev@gmail.com>
+## Created: 2018-08-09
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{y} =} movfun (@var{fcn}, @var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movfun (@var{fcn}, @var{x}, @var{[@var{nb}, @var{na}}])
+## @deftypefnx {} {@var{y} =} movfun (@dots{}, "@var{property}", @var{value})
+##
+## Apply function @var{fcn} to a moving window of length @var{wlen} on data
+## @var{x}.
+##
+## If @var{wlen} is a scalar, the function @var{fcn} is applied to a moving
+## window of length @var{wlen}.  When @var{wlen} is an odd number the window is
+## symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on either
+## side of the central element.  For example, when calculating the output at
+## index 5 with a window length of 3, @code{movfun} uses data elements
+## @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window is
+## asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movfun} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## During calculations the data input @var{x} is reshaped into a 2-dimensional
+## @var{wlen}-by-@var{N} matrix and @var{fcn} is called on this new matrix.
+## Therefore, @var{fcn} must accept an array input argument and apply the
+## computation along dimension 1, i.e., down the columns of the array.
+##
+## When applied to an array (possibly multi-dimensional) with @var{n} columns,
+## @var{fcn} may return a result in either of two formats: @w{Format 1)}
+## an array of size 1-by-@var{n}-by-@var{dim3}-by-@dots{}-by-@var{dimN}.  This
+## is the typical output format from Octave core functions.  Type
+## @code{demo ("movfun", 5)} for an example of this use case.
+## @w{Format 2)} a row vector of length
+## @code{@var{n} * @var{numel_higher_dims}} where @var{numel_higher_dims} is
+## @w{@code{prod (size (@var{x})(3:end))}}.  The output of @var{fcn} for the
+## i-th input column must be found in the output at indices
+## @w{@code{i:@var{n}:(@var{n}*@var{numel_higher_dims})}}.
+## This format is useful when concatenating functions into arrays, or when
+## using @code{nthargout}.  Type @code{demo ("movfun", 6)} for an example of
+## this case.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"dim"}
+## Operate along the dimension specified, rather than the default of the first
+## non-singleton dimension.
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = @var{fcn} (@var{x}(1:2))}, and
+## @code{@var{y}(end) = @var{fcn} (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = @var{fcn} ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = @var{fcn} ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @var{fcn} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = @var{fcn} ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = @var{fcn} ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = @var{fcn} ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = @var{fcn} ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = @var{fcn} ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = @var{fcn} ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## Note that for some of these choices, the window size at the boundaries is
+## not the same as for the central part, and @var{fcn} must work in these
+## cases.
+##
+## @item @qcode{"nancond"}
+## Controls whether @code{NaN} and @code{NA} values should be included (value:
+## @qcode{"includenan"}), or excluded (value: @qcode{"omitnan"}), from the data
+## passed to @var{fcn}.  The default is @qcode{"includenan"}.  Caution:
+## The @qcode{"omitnan"} option is not yet implemented.
+##
+## @item @qcode{"outdim"}
+## A row vector that selects which dimensions of the calculation will appear
+## in the output @var{y}.  This is only useful when @var{fcn} returns an
+## N-dimensional array in @w{Format 1}.  The default is to return all output
+## dimensions.
+##
+## @end table
+##
+## Programming Note: The property @qcode{"outdim"} can be used to save memory
+## when the output of @var{fcn} has many dimensions, or when a wrapper to the
+## base function that selects the desired outputs is too costly.  When memory
+## is not an issue, the easiest way to select output dimensions is to first
+## calculate the complete result with @code{movfun} and then filter that result
+## with indexing.  If code complexity is not an issue then a wrapper can be
+## created using anonymous functions.  For example, if @code{basefcn}
+## is a function returning a @var{K}-dimensional row output, and only
+## dimension @var{D} is desired, then the following wrapper could be used.
+##
+## @example
+## @group
+## @var{fcn} = @@(x) basefcn (x)(:,size(x,2) * (@var{D}-1) + (1:size(x,2)));
+## @var{y} = movfun (@@fcn, @dots{});
+## @end group
+## @end example
+##
+## @seealso{movslice, prepad, postpad, permute, reshape}
+## @end deftypefn
+
+function y = movfun (fcn, x, wlen, varargin)
+
+  if (nargin < 3)
+    print_usage ();
+  endif
+
+  valid_bc = {"shrink", "discard", "fill", "same", "periodic"};
+
+  ## Parse input arguments
+  parser = inputParser ();
+  parser.FunctionName = "movfun";
+  parser.addParamValue ("Endpoints", "shrink", ...
+    @(x) any (strcmpi (x, valid_bc)) || (isnumeric (x) && isscalar (x)));
+  parser.addParamValue ("dim", [], ...
+    @(d) isempty (d) || (isscalar (d) && isindex (d, ndims (x))));
+  parser.addParamValue ("nancond", "includenan", ...
+    @(x) any (strcmpi (x, {"includenan", "omitnan"})));
+  parser.addParamValue ("outdim", [], ...
+    @(d) isempty (d) || (isvector (d) && isindex (d)));
+
+  parser.parse (varargin{:});
+  bc      = parser.Results.Endpoints;   # boundary condition
+  dim     = parser.Results.dim;         # dimension to be used as input
+  nancond = parser.Results.nancond;     # whether NaN are ignored or not
+  outdim  = parser.Results.outdim;      # selected output dimension of fcn
+  clear parser
+  ## End parse input arguments
+
+  ## If dim was not provided find the first non-singleton dimension.
+  szx = size (x);
+  if (isempty (dim))
+    (dim = find (szx > 1, 1)) || (dim = 1);
+  endif
+
+  N = szx(dim);
+
+  ## Calculate slicing indices.  This call also validates WLEN input.
+  [slc, C, Cpre, Cpos, win] = movslice (N, wlen);
+
+  ## Use [nb, na] format which makes replaceval_bc() simpler.
+  if (isscalar (wlen))
+    wlen = [wlen, wlen];
+  endif
+
+  omitnan = strcmpi (nancond, "omitnan");
+  if (omitnan)
+    warning ('movfun: "omitnan" is not yet implemented, using "includenan"');
+  endif
+
+  ## Move the desired dim to be the 1st dimension (rows)
+  nd    = length (szx);                  # number of dimensions
+  dperm = [dim, 1:(dim-1), (dim+1):nd];  # permutation of dimensions
+  x     = permute (x, dperm);            # permute dims to first dimension
+  ncols = prod (szx(dperm(2:end)));      # rest of dimensions as single column
+  x     = reshape (x, N, ncols);         # reshape input
+
+  ## Obtain function for boundary conditions
+  if (isnumeric (bc))
+    bcfunc = @replaceval_bc;
+    bcfunc (true, bc);  # initialize replaceval function with value
+  else
+    switch (tolower (bc))
+      case "shrink"
+        bcfunc = @shrink_bc;
+
+      case "discard"
+        bcfunc = [];
+        C -= length (Cpre);
+        Cpre = Cpos = [];
+        N = length (C);
+        szx(dperm(1)) = N;
+
+      case "fill"
+        bcfunc = @replaceval_bc;
+        bcfunc (true, NaN);
+
+      case "same"
+        bcfunc = @same_bc;
+
+      case "periodic"
+        bcfunc = @periodic_bc;
+
+    endswitch
+  endif
+
+  ## FIXME: Validation doesn't seem to work correctly (noted 12/16/2018).
+  ## Validate that outdim makes sense
+  tmp     = fcn (zeros (length (win), 1));  # output for window
+  noutdim = length (tmp);                   # number of output dimensions
+  if (! isempty (outdim))
+    if (max (outdim) > noutdim)
+      error ("Octave:invalid-input-arg", ...
+             "movfun: output dimension OUTDIM (%d) is larger than largest available dimension (%d)", ...
+             max (outdim), noutdim);
+    endif
+  else
+    outdim = 1:noutdim;
+  endif
+  soutdim = length (outdim);  # length of selected output dimensions
+  ## If noutdim is not one then modify function to handle multiple outputs
+  if (noutdim > 1)
+    fcn_ = @(x) reshape (fcn (x), columns (x), noutdim)(:, outdim);
+  else
+    fcn_ = fcn;
+  endif
+
+  ## Apply processing to each column
+  ## FIXME: Is it faster with cellfun?  Don't think so, but needs testing.
+  y = zeros (N, ncols, soutdim);
+  parfor i = 1:ncols
+    y(:,i,:) = movfun_oncol (fcn_, x(:,i), wlen, bcfunc,
+                             slc, C, Cpre, Cpos, win, soutdim);
+  endparfor
+
+  ## Restore shape
+  y = reshape (y, [szx(dperm), soutdim]);
+  y = permute (y, [dperm, nd+1]);
+  y = squeeze (y);
+
+endfunction
+
+function y = movfun_oncol (fcn, x, wlen, bcfunc, slcidx, C, Cpre, Cpos, win, odim)
+
+  N = length (Cpre) + length (C) + length (Cpos);
+  y = NA (N, odim);
+
+  ## Process center part
+  y(C,:) = fcn (x(slcidx));
+
+  ## Process boundaries
+  if (! isempty (Cpre))
+    y(Cpre,:) = bcfunc (fcn, x, Cpre, win, wlen, odim);
+  endif
+  if (! isempty (Cpos))
+    y(Cpos,:) = bcfunc (fcn, x, Cpos, win, wlen, odim);
+  endif
+
+endfunction
+
+## 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
+
+  n   = length (idxp);
+  y   = zeros (n, odim);
+  ## FIXME: This nested for loop accounts for 70% of running time.
+  ##        Given that "shrink" is the default Endpoint value this
+  ##        code needs to be reworked.
+  for i = 1:n
+    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)
+
+  persistent substitute;
+
+  ## In-band method to initialize substitute value
+  if (islogical (fcn))
+    substitute = x;
+    return;
+  endif
+
+  if (min (idxp) == 1)
+    ## pre-pad window
+    sz = size (x);
+    sz(1) = wlen(1);
+    x = [substitute(ones (sz)); x];
+    idx = idxp + win + wlen(1);
+  else
+    ## post-pad window
+    sz = size (x);
+    sz(1) = wlen(2);
+    x = [x; substitute(ones (sz))];
+    idx = idxp + win;
+  endif
+
+  y = fcn (x(idx));
+
+endfunction
+
+## 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)
+  idx          = idxp + win;
+  idx(idx < 1) = 1;
+  N            = length (x);
+  idx(idx > N) = N;
+  y            = fcn (x(idx));
+endfunction
+
+## 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)
+  N       = length (x);
+  idx     = idxp + win;
+  tf      = idx < 1;
+  idx(tf) = N + idx(tf);
+  tf      = idx > N;
+  idx(tf) = idx(tf) - N;
+  y       = fcn (x(idx));
+endfunction
+
+
+%!demo
+%! clf;
+%! t  = 2 * pi * linspace (0,1,100).';
+%! x  = sin (3 * t);
+%! xn = x + 0.1 * randn (size (x));
+%! x_s = movfun (@mean, xn, 5, "Endpoints", "shrink");
+%! x_p = movfun (@mean, xn, 5, "Endpoints", "periodic");
+%! x_m = movfun (@mean, xn, 5, "Endpoints", "same");
+%! x_z = movfun (@mean, xn, 5, "Endpoints", 0);
+%! x_f = movfun (@mean, xn, 5, "Endpoints", "fill");
+%!
+%! h = plot (t, xn, "o;noisy signal;",
+%!           t, x, "-;true;",
+%!           t, x_s, "-;shrink;",
+%!           t, x_p, "-;periodic;",
+%!           t, x_m, "-;same;",
+%!           t, x_z, "-;zero;",
+%!           t, x_f, "-;fill;");
+%! set (h(1), "markerfacecolor", "auto");
+%! set (h(2:end), "linewidth", 3);
+%! axis tight
+%! xlabel ("time");
+%! ylabel ("signal");
+%! title ("moving mean with different boundary conditions");
+%! #-----------------------------------------------------------------
+%! # Moving mean of noisy sinusoidal function with different boundary
+%! # conditions.
+
+%!demo
+%! clf;
+%! t  = 2 * pi * linspace (0,1,100).';
+%! x  = sin (3 * t);
+%! xn = x + 0.1 * randn (size (x));
+%! nwin = 5;
+%! x_ = zeros (rows (x), nwin);
+%! wlen = 3 + (1:nwin) * 4;
+%! for i = 1:nwin
+%!   x_(:,i) = movfun (@mean, xn, wlen(i), "Endpoints", "periodic");
+%! endfor
+%!
+%! h = plot (t, xn, "o",
+%!           t, x, "-",
+%!           t, x_, "-");
+%! set (h(1), "markerfacecolor", "auto");
+%! set (h(2:end), "linewidth", 3);
+%! axis tight
+%! xlabel ("time");
+%! ylabel ("signal");
+%! title ({'moving mean with "periodic" boundary conditions',
+%!         "and windows of different lengths"});
+%! legend (h, {"noisy", "true", strsplit(num2str(wlen)){:}});
+%! #-----------------------------------------------------------------
+%! # Moving mean of noisy sinusoidal function with periodic boundary conditions
+%! # using windows of different lengths.
+
+%!demo
+%! clf;
+%! t  = linspace (0,1,100).';
+%! x  = exp (-(t - [0.1:0.3:1]).^2/2/0.1^2);
+%! y  = movfun (@max, x, 15);
+%!
+%! h = plot (t, x, "-",
+%!           t, y, "--");
+%! axis tight
+%! xlabel ("time");
+%! ylabel ("signal");
+%! title ("moving max of several Gaussian functions");
+%! #-----------------------------------------------------------------
+%! # Moving max of different Gaussian functions.
+%! # Illustrates the application of movfun() to inputs with several columns.
+
+%!demo
+%! clf;
+%! t  = linspace (0,1-1e-2,100).';
+%! w  = 2 * pi * 3;
+%! x  = sin (w * t);
+%! y  = cos (w * t);
+%! y_  = movfun (@diff, x, [1 0], "Endpoints", "periodic");
+%! ## Is the same as y_ = x(2:end) - x(1:end-1);
+%! dt = t(2) - t(1);
+%! y_  = y_ / w / dt;
+%!
+%! h = plot (t, x, "-",
+%!           t, y, "-",
+%!           t, y_, ":");
+%! set (h, "linewidth", 3);
+%! axis tight
+%! xlabel ("time");
+%! ylabel ("signal");
+%! title ("movfun with periodic boundary conditions and asymmetric window");
+%! legend (h, {"sin", "cos", "[nb, na]"});
+%! #-----------------------------------------------------------------
+%! # Backward diff() of sinusoidal function with periodic boundary conditions.
+%! # Illustrates the use of asymmetric windows.
+
+%!demo
+%! clf;
+%! N    = 1e3;
+%! wlen = 99;
+%! x  = linspace (-1, 1, N).';
+%! pp = [-2 0 1 0];
+%! y  = polyval (pp, x);
+%! yn = y + 0.1 * (abs (y) + 0.5) .* exp (randn (N, 1));
+%!
+%! st = movfun (@(y) (statistics (y)).', yn, wlen);
+%!
+%! h = plot (x, y, "-",
+%!           x, yn, ".",
+%!           x, st(:,[3 6]), "-",
+%!           x, st(:,6) + [-1 1].*st(:,7), "-",
+%!           x, st(:,[1 2 4 5]), "-");
+%! set (h([1 3:4]), "linewidth", 3);  # mean
+%! set (h(5:end), "color", "k");
+%! axis tight
+%! xlabel ("x")
+%! ylabel ("y")
+%! title ("movfun() with Format 1 output data");
+%! legend (h, {"noiseless", "noisy", "mean", "median"})
+%! #-----------------------------------------------------------------
+%! # Moving window statistics.  The plot highlights mean and median.
+%! # Black lines how minimum, first quartile, third quartile, and maximum.
+%! # Demo illustrates the use of functions with multidimensional output.
+
+%!demo
+%! clf;
+%! N    = 1e2;
+%! wlen = 9;
+%! x  = linspace (-1, 1, N).';
+%! pp = [-2 0 1 0];
+%! y  = polyval (pp, x);
+%! y(:,2) = y + 0.1 * (abs (y) + 0.5) .* exp (randn (N, 1));
+%! y(:,1) = -y(:,1) + 0.1 * randn (N, 1);
+%!
+%! fcn = @(y) [min(y), max(y)];
+%! st = movfun (fcn, y, wlen);
+%!
+%! h = plot (x, y, "o",
+%!           x, squeeze (st(:,1,:)), "-",
+%!           x, squeeze (st(:,2,:)), "-");
+%! axis tight
+%! set (h(3:4), "color", get (h(1), "color"));
+%! set (h(5:6), "color", get (h(2), "color"));
+%! xlabel ("x")
+%! ylabel ("y")
+%! title ("movfun() with Format 2 output data");
+%! legend (h(1:2), {"data1", "data2"})
+%! #-----------------------------------------------------------------
+%! # Moving min() and max() on the same window.
+%! # Demo illustrates the use of functions with flat multidimensional output.
+
+%!test
+%! x = (1:10).' + [-3, 0, 4];
+%! ctrfun = @(x) x(2,:);
+%! valid_bc = {"periodic", 0, "fill", "same"};
+%! for bc = valid_bc
+%!   assert (movfun (ctrfun, x, 3, "Endpoints", bc{1}), x);
+%! endfor
+%! x_ = x; x_([1 end],:) = x([2 end],:);
+%! assert (movfun (ctrfun, x, 3, "Endpoints", "shrink"), x_);
+
+%!test
+%! ## dim == 2, same as transpose
+%! x = randi (10, 3);
+%! ctrfun = @(x) x(2,:);
+%! valid_bc = {"periodic", 0, "fill", "same"};
+%! for bc = valid_bc
+%!   assert (movfun (ctrfun, x.', 3, "Endpoints", bc{1}, "dim", 2), x.');
+%! endfor
+%! x_ = x; x_([1 end],:) = x([2 end],:);
+%! assert (movfun (ctrfun, x.', 3, "Endpoints", "shrink", "dim", 2), x_.');
+
+%!test
+%! x = randi (10, 3, 10, 2);
+%! y = movfun (@(x) x(2,:), x, 3, "Endpoints", "same", "dim", 2);
+%! assert (x, y);
+
+%!test
+%! ## bad zero_bc
+%! x = ones (10, 1);
+%! y = x; y(1:2) = y([end end-1]) = [0.6;0.8];
+%! assert (movfun (@mean, x, 5, "Endpoints", 0), y);
+
+## Asymmetric windows
+%!shared x, wlen, wlen02, wlen20, ctrfun, UNO
+%! x = (1:10).' + [-3, 0, 4];
+%! wlen = [2, 1];
+%! wlen02 = [0, 2];
+%! wlen20 = [2, 0];
+%! ctrfun = @(x) x(wlen(1)+1,:);
+%! UNO = ones (7,1);
+
+%!assert (movfun (ctrfun, x, wlen, "Endpoints", "periodic"), x)
+%!assert (movfun (ctrfun, x, wlen, "Endpoints", 0), x)
+%!assert (movfun (ctrfun, x, wlen, "Endpoints", "fill"), x)
+%!assert (movfun (ctrfun, x, wlen, "Endpoints", "same"), x)
+## for shorter x, indexing fails
+%!error movfun (ctrfun, x, wlen, "Endpoints", "shrink")
+
+%!assert (movfun (@min, UNO, wlen, "Endpoints", "shrink"), UNO)
+%!assert (movfun (@min, UNO, wlen02, "Endpoints", "shrink"), UNO)
+%!assert (movfun (@min, UNO, wlen20, "Endpoints", "shrink"), UNO)
+
+%!assert (movfun (@min, UNO, wlen02, "Endpoints", "periodic"), UNO)
+%!assert (movfun (@min, UNO, wlen20, "Endpoints", "periodic"), UNO)
+
+%!assert (movfun (@max, UNO, wlen02, "Endpoints", 0), UNO)
+%!assert (movfun (@max, UNO, wlen20, "Endpoints", 0), UNO)
+
+%!assert (movfun (@min, UNO, wlen02, "Endpoints", "fill"), UNO)
+%!assert (movfun (@min, UNO, wlen20, "Endpoints", "fill"), UNO)
+
+%!assert (movfun (@min, UNO, wlen02, "Endpoints", "same"), UNO)
+%!assert (movfun (@min, UNO, wlen20, "Endpoints", "same"), UNO)
+
+## Multidimensional output
+%!assert (size( movfun (@(x) [min(x), max(x)], (1:10).', 3)), [10 2])
+%!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))
+
+## Test input validation
+%!error movfun ()
+%!error movfun (@min)
+%!error 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)
+%!error <WLEN must be . 1> movfun (@min, 1, 1)
+%!error <WLEN must be a scalar or 2-element array> movfun (@min, 1, [1, 2, 3])
+%!error <WLEN \(3\) must be shorter than length along DIM \(1\)>
+%! movfun (@min, 1, 3)
+%!error <WLEN \(4\) must be shorter than length along DIM \(1\)>
+%! movfun (@min, 1, [4, 1]);
+%!error <WLEN \(5\) must be shorter than length along DIM \(1\)>
+%! movfun (@min, 1, [1, 5]);
+%!warning <"omitnan" is not yet implemented>
+%! movfun (@min, 1:3, 3, "nancond", "omitnan");
+## FIXME: This test is commented out until OUTDIM validation is clarified.
+%!#error <OUTDIM \(5\) is larger than largest available dimension \(3\)>
+%! movfun (@min, ones (6,3,4), 3, "outdim", 5);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/signal/movslice.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,108 @@
+## Copyright (C) 2018 Juan Pablo Carbajal
+##
+## 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/>.
+
+## Author: Juan Pablo Carbajal <ajuanpi+dev@gmail.com>
+## Created: 2018-12-08
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{slcidx} =} movslice (@var{N}, @var{wlen})
+## @deftypefnx {} {[@var{slcidx}, @var{C}, @var{Cpre}, @var{Cpost}, @var{win}] =} movslice (@dots{})
+## Generate indices to slice a vector of length @var{N} in to windows
+## of length @var{wlen}.
+##
+## FIXME: Document inputs N, wlen
+##
+## FIXME: Document outputs slcidx, C, Cpre, Cpost, win.
+## @seealso{movfun}
+## @end deftypefn
+
+function [slcidx, C, Cpre, Cpost, win] = movslice (N, wlen)
+
+  if (nargin != 2)
+    print_usage ();
+  endif
+
+  ## Validate N
+  if (! (isscalar (N) && isindex (N)))
+    error ("movslice: N must be a positive integer");
+  endif
+
+  ## Validate window length
+  if (! (isnumeric (wlen) && all (wlen >= 0) && fix (wlen) == wlen))
+    error ("Octave:invalid-input-arg",
+           "movslice: WLEN must be a scalar or 2-element array of integers >= 0");
+  endif
+  if (isscalar (wlen))
+    ## Check for proper window length
+    if (wlen == 1)
+      error ("Octave:invalid-input-arg", "movslice: WLEN must be > 1");
+    endif
+  elseif (numel (wlen) == 2)
+    ## wlen = [nb, na].  No further validation here.
+  else
+    error ("Octave:invalid-input-arg",
+           "movslice: WLEN must be a scalar or 2-element array of integers >= 0");
+  endif
+  if (max (wlen) > N)
+    error ("Octave:invalid-input-arg", ...
+           "movslice: window length WLEN (%d) must be shorter than length along DIM (%d)", ...
+           max (wlen), N);
+  endif
+
+  if (isscalar (wlen))
+    if (mod (wlen, 2) == 1)
+      ## Symmetric window
+      nb = na = (wlen - 1) / 2;
+      wlen = [nb, na];
+    else
+      ## Asymmetric window
+      nb = wlen / 2;
+      na = nb - 1;
+      wlen = [nb, na];
+    endif
+  endif
+
+  Cpre  = 1:wlen(1);              # centers that can't fit the pre-window
+  Cnf   = N - wlen(2) + 1;        # first center that can't fit the post-window
+  Cpost = Cnf:N;                  # centers that can't fit centered post-window
+  C     = (wlen(1) + 1):(Cnf - 1);
+  win   = (-wlen(1):wlen(2)).';
+  slcidx = C + win;
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+
+## Test input validation
+%!error movslice ()
+%!error movslice (1)
+%!error movslice (1,2,3)
+%!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})
+%!error <WLEN must be .* array of integers .= 0> movslice (1, -1)
+%!error <WLEN must be .* array of integers> movslice (1, 1.5)
+%!error <WLEN must be . 1> movslice (1, 1)
+%!error <WLEN must be a scalar or 2-element array> movslice (1, [1, 2, 3])
+%!error <WLEN \(3\) must be shorter than length along DIM \(1\)>
+%! movslice (1, 3);
+%!error <WLEN \(4\) must be shorter than length along DIM \(1\)>
+%! movslice (1, [4, 1]);
+%!error <WLEN \(5\) must be shorter than length along DIM \(1\)>
+%! movslice (1, [1, 5]);
--- a/scripts/signal/periodogram.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/signal/periodogram.m	Thu Dec 20 17:18:56 2018 -0500
@@ -151,7 +151,7 @@
 
   if (! isempty (window))
     n = sumsq (window);
-  endif;
+  endif
   Pxx = (abs (fft (x, nfft))) .^ 2 / n;
 
   if (use_w_freq)
--- a/scripts/sparse/eigs.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/eigs.m	Thu Dec 20 17:18:56 2018 -0500
@@ -1480,11 +1480,86 @@
 %! 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
-%! [Evectors Evalues] = eigs(A, B, 5, 'SM'); # call_eig is true
+%! [Evectors, Evalues] = eigs(A, B, 5, "SM"); # call_eig is true
 %! ResidualVectors = A * Evectors - B * Evectors * Evalues;
 %! RelativeErrors = norm (ResidualVectors, "columns") ./ ...
 %! norm (A * Evectors, "columns");
-%! assert (RelativeErrors, zeros (1, 5))
+%! assert (RelativeErrors, zeros (1, 5));
 %!testif HAVE_ARPACK
 %! A = rand (8);
 %! eigs (A, 6, "lr"); # this failed on 4.2.x
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M);
+%! B = cos (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "LM", opts);
+%! Afun = @(x) A * x;
+%! [Evector_f Evalues_f] = eigs (Afun, 10, B, 4, "LM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M);
+%! B = cos (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "SM", opts);
+%! [L, U, P] = lu (A);
+%! Afun = @(x) U \ (L \ (P * x));
+%! [Evector_f Evalues_f] = eigs (Afun, 10, B, 4, "SM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M);
+%! A = A * A';
+%! B = cos (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "LM", opts);
+%! Afun = @(x) A * x;
+%! opts.issym = true;
+%! [Evector_f Evalues_f] = eigs (Afun, 10, B, 4, "LM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M);
+%! A = A * A';
+%! B = cos (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "SM", opts);
+%! [L, U, P] = lu (A);
+%! Afun = @(x) U \ (L \ (P * x));
+%! opts.issym = true;
+%! [Evector_f Evalues_f] = eigs (Afun, 10, B, 4, "SM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M) + 1i * cos (M);
+%! B = cos (M) + 1i * sin (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "LM", opts);
+%! Afun = @(x) A * x;
+%! opts.isreal = false;
+%! [Evector_f Evalues_f] = eigs (Afun, 10, B, 4, "LM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
+%!testif HAVE_ARPACK
+%! M = magic (10);
+%! A = sin (M) + 1i * cos (M);
+%! B = cos (M) + 1i * sin (M);
+%! B = B * B';
+%! opts.v0 = (1:10)';
+%! [Evector, Evalues] = eigs (A, B, 4, "SM", opts);
+%! [L, U, P] = lu (A);
+%! Afun = @(x) U \ (L \ (P *x));
+%! opts.isreal = false;
+%! [Evector_f, Evalues_f] = eigs (Afun, 10, B, 4, "SM", opts);
+%! assert (Evector, Evector_f);
+%! assert (Evalues, Evalues_f);
--- a/scripts/sparse/nonzeros.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/nonzeros.m	Thu Dec 20 17:18:56 2018 -0500
@@ -17,20 +17,24 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {} nonzeros (@var{s})
-## Return a vector of the nonzero values of the sparse matrix @var{s}.
+## @deftypefn {} {@var{v} =} nonzeros (@var{A})
+## Return a column vector of the nonzero values of the matrix @var{A}.
 ## @seealso{find, nnz}
 ## @end deftypefn
 
-function t = nonzeros (s)
+function v = nonzeros (A)
 
   if (nargin != 1)
     print_usage ();
   endif
 
-  [~, ~, t] = find (s);
-
-  t = t(:);
+  if (issparse (A))
+    [~, ~, v] = find (A);
+    v = v(:);
+  else
+    v = A(find (A));
+    v = v(:);
+  endif
 
 endfunction
 
@@ -39,3 +43,7 @@
 %!assert (nonzeros ([1,2,3,0]), [1;2;3])
 %!assert (nonzeros (sparse ([1,2;3,0])), [1;3;2])
 %!assert (nonzeros (sparse ([1,2,3,0])), [1;2;3])
+
+## Test input validation
+%!error nonzeros ()
+%!error nonzeros (1, 2)
--- a/scripts/sparse/pcg.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/pcg.m	Thu Dec 20 17:18:56 2018 -0500
@@ -551,10 +551,10 @@
 %!test
 %! ## solve tridiagonal system, do not converge in default 20 iterations
 %! N = 100;
-%! A = zeros (N, N);
-%! for i = 1 : N - 1  # form 1-D Laplacian matrix
-%!   A(i:i+1, i:i+1) = [2 -1; -1 2];
-%! endfor
+%! ## Form 1-D Laplacian matrix
+%! A = 2 * eye (N,N);
+%! A(2:(N+1):end) = -1;
+%! A((N+1):(N+1):end) = -1;
 %! b = ones (N, 1);
 %! [x, flag, relres, iter, resvec, eigest] = pcg (A, b, 1e-12);
 %! assert (flag);
@@ -564,10 +564,10 @@
 %! ## solve tridiagonal system with "perfect" preconditioner which converges
 %! ## in one iteration, so the eigest does not work and issues a warning.
 %! N = 100;
-%! A = zeros (N, N);
-%! for i = 1 : N - 1  # form 1-D Laplacian matrix
-%!   A(i:i+1, i:i+1) = [2 -1; -1 2];
-%! endfor
+%! ## Form 1-D Laplacian matrix
+%! A = 2 * eye (N,N);
+%! A(2:(N+1):end) = -1;
+%! A((N+1):(N+1):end) = -1;
 %! b = ones (N, 1);
 %! [x, flag, relres, iter, resvec, eigest] = pcg (A, b, [], [], A, [], b);
 %! assert (flag, 0);
--- a/scripts/sparse/pcr.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/pcr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -363,10 +363,11 @@
 %! ## Note that we use here indefinite preconditioners!
 %!
 %! N = 100;
-%! A = zeros (N,N);
-%! for i=1:N-1 # form 1-D Laplacian matrix
-%!   A(i:i+1,i:i+1) = [2 -1; -1 2];
-%! endfor
+%! ## Form 1-D Laplacian matrix
+%! A = 2 * eye (N,N);
+%! A(2:(N+1):end) = -1;
+%! A((N+1):(N+1):end) = -1;
+%!
 %! A = [A, zeros(size(A)); zeros(size(A)), -A];
 %! b = rand (2*N,1);
 %! X = A \ b;  # X is the true solution
@@ -416,10 +417,10 @@
 %! ## should perform max allowable default number of iterations
 %!
 %! N = 100;
-%! A = zeros (N,N);
-%! for i=1:N-1 # form 1-D Laplacian matrix
-%!   A(i:i+1,i:i+1) = [2 -1; -1 2];
-%! endfor
+%! ## Form 1-D Laplacian matrix
+%! A = 2 * eye (N,N);
+%! A(2:(N+1):end) = -1;
+%! A((N+1):(N+1):end) = -1;
 %! b = ones (N,1);
 %! X = A \ b;  # X is the true solution
 %! [x, flag, relres, iter, resvec] = pcr (A,b,1e-12);
@@ -432,10 +433,10 @@
 %! ## converges in one iteration
 %!
 %! N = 100;
-%! A = zeros (N,N);
-%! for i=1:N-1 # form 1-D Laplacian matrix
-%!   A(i:i+1,i:i+1) = [2 -1; -1 2];
-%! endfor
+%! ## Form 1-D Laplacian matrix
+%! A = 2 * eye (N,N);
+%! A(2:(N+1):end) = -1;
+%! A((N+1):(N+1):end) = -1;
 %! b = ones (N,1);
 %! X = A \ b;  # X is the true solution
 %! [x, flag, relres, iter] = pcr (A,b,[],[],A,b);
--- a/scripts/sparse/private/__alltohandles__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/private/__alltohandles__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -53,7 +53,7 @@
   M2_is_numeric = false;
 
   ## Check A and set its type
-  if (isa (A, "function_handle"))
+  if (is_function_handle (A))
      Afun = A;
   elseif (ischar (A))
     Afun = str2func (A);
@@ -70,7 +70,7 @@
   if (isempty (M1)) # M1 empty, set to identity function
       M1fun = @(x) x;
   else # M1 not empty
-    if (isa (M1, "function_handle"))
+    if (is_function_handle (M1))
       M1fun = M1;
     elseif (ischar (M1))
       M1fun = str2func (M1);
@@ -84,7 +84,7 @@
   if (isempty (M2)) # M2 empty, then I set is to the identity function
     M2fun = @(x) x;
   else # M2 not empty
-    if (isa (M2, "function_handle"))
+    if (is_function_handle (M2))
       M2fun = M2;
     elseif (ischar (M2))
       M2fun = str2func (M2);
--- a/scripts/sparse/qmr.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/qmr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -95,7 +95,7 @@
       fun = str2func (A);
       Ax  = @(x) feval (fun, x, "notransp");
       Atx = @(x) feval (fun, x, "transp");
-    elseif (isa (A, "function_handle"))
+    elseif (is_function_handle (A))
       Ax  = @(x) feval (A, x, "notransp");
       Atx = @(x) feval (A, x, "transp");
     elseif (isnumeric (A) && issquare (A))
@@ -122,7 +122,7 @@
       fun = str2func (M1);
       M1m1x  = @(x) feval (fun, x, "notransp");
       M1tm1x = @(x) feval (fun, x, "transp");
-    elseif (isa (M1, "function_handle"))
+    elseif (is_function_handle (M1))
       M1m1x  = @(x) feval (M1, x, "notransp");
       M1tm1x = @(x) feval (M1, x, "transp");
     elseif (isnumeric (M1) && ismatrix (M1))
@@ -139,7 +139,7 @@
       fun = str2func (M2);
       M2m1x  = @(x) feval (fun, x, "notransp");
       M2tm1x = @(x) feval (fun, x, "transp");
-    elseif (isa (M2, "function_handle"))
+    elseif (is_function_handle (M2))
       M2m1x  = @(x) feval (M2, x, "notransp");
       M2tm1x = @(x) feval (M2, x, "transp");
     elseif (isnumeric (M2) && ismatrix (M2))
--- a/scripts/sparse/spfun.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/sparse/spfun.m	Thu Dec 20 17:18:56 2018 -0500
@@ -35,7 +35,7 @@
   [i, j, v] = find (S);
   [m, n] = size (S);
 
-  if (isa (f, "function_handle") || isa (f, "inline function"))
+  if (is_function_handle (f))
     y = sparse (i, j, f(v), m, n);
   else
     y = sparse (i, j, feval (f, v), m, n);
--- a/scripts/specfun/betaincinv.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/specfun/betaincinv.m	Thu Dec 20 17:18:56 2018 -0500
@@ -161,7 +161,7 @@
   i_upp = (! i_low);
 
   idx = todo & i_low;
-  if (any (idx));
+  if (any (idx))
     n = nnz (idx);
     ## Function and derivative of the lower version.
     F = @(x, a, b, y) y - betainc (x, a, b);
@@ -178,7 +178,7 @@
   endif
 
   idx = todo & i_upp;
-  if (any (idx));
+  if (any (idx))
     n = nnz (idx);
     ## Function and derivative of the upper version.
     F = @(x, a, b, y) y - betainc (x, a, b, "upper");
--- a/scripts/specfun/cosint.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/specfun/cosint.m	Thu Dec 20 17:18:56 2018 -0500
@@ -140,7 +140,7 @@
   flag_sum = true (nnz (todo), 1);
   it = 0;
   maxit = 300;
-  while (any (flag_sum) && (++it < maxit));
+  while (any (flag_sum) && (++it < maxit))
     ssum .*= - xx .^ 2 * (2 * it) / ((2 * it + 2) ^ 2 * (2 * it + 1));
     yy(flag_sum) += ssum (flag_sum);
     flag_sum = (abs (ssum) >= tol);
--- a/scripts/specfun/factor.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/specfun/factor.m	Thu Dec 20 17:18:56 2018 -0500
@@ -23,32 +23,27 @@
 ##
 ## The prime factorization is defined as @code{prod (@var{pf}) == @var{q}}
 ## where every element of @var{pf} is a prime number.  If @code{@var{q} == 1},
-## return 1.
+## return 1.  The output @var{pf} is of the same numeric class as the input.
 ##
 ## With two output arguments, return the unique prime factors @var{pf} and
 ## their multiplicities.  That is,
 ## @code{prod (@var{pf} .^ @var{n}) == @var{q}}.
 ##
-## Implementation Note: The input @var{q} must be less than
-## @code{flintmax} (9.0072e+15) in order to factor correctly.
+## Implementation Note: The input @var{q} must be less than @code{flintmax}
+## (9.0072e+15) in order to factor correctly.
 ## @seealso{gcd, lcm, isprime, primes}
 ## @end deftypefn
 
 ## Author: Paul Kienzle
 
-## 2002-01-28 Paul Kienzle
-## * remove recursion; only check existing primes for multiplicity > 1
-## * return multiplicity as suggested by Dirk Laurie
-## * add error handling
-
 function [pf, n] = factor (q)
 
   if (nargin != 1)
     print_usage ();
   endif
 
-  if (! isreal (q) || ! isscalar (q) || q != fix (q))
-    error ("factor: Q must be a real integer");
+  if (! isscalar (q) || ! isreal (q) || q < 0 || q != fix (q))
+    error ("factor: Q must be a real non-negative integer");
   endif
 
   ## Special case of no primes less than sqrt(q).
@@ -58,7 +53,8 @@
     return;
   endif
 
-  q = double (q);  # For the time being, calcs rely on double precision var.
+  cls = class (q); # store class
+  q = double (q);  # internal algorithm relies on numbers being doubles.
   qorig = q;
   pf = [];
   ## There is at most one prime greater than sqrt(q), and if it exists,
@@ -79,7 +75,7 @@
   endwhile
   pf = sort (pf);
 
-  ## Verify algorithm was succesful
+  ## Verify algorithm was successful
   q = prod (pf);
   if (q != qorig)
     error ("factor: Q too large to factor");
@@ -87,13 +83,16 @@
     warning ("factor: Q too large.  Answer is unreliable");
   endif
 
-  ## Determine muliplicity.
+  ## Determine multiplicity.
   if (nargout > 1)
     idx = find ([0, pf] != [pf, 0]);
     pf = pf(idx(1:length (idx)-1));
     n = diff (idx);
   endif
 
+ ## Restore class of input
+ pf = feval (cls, pf);
+
 endfunction
 
 
@@ -108,9 +107,17 @@
 %!   assert (all ([0,pf] != [pf,0]));
 %! endfor
 
+%!assert (factor (uint8 (8)), uint8 ([2 2 2]))
+%!assert (factor (single (8)), single ([2 2 2]))
+%!test
+%! [pf, n] = factor (int16 (8));
+%! assert (pf, int16 (2));
+%! assert (n, double (3));
+
 ## Test input validation
 %!error factor ()
 %!error factor (1,2)
-%!error <Q must be a real integer> factor (6i)
-%!error <Q must be a real integer> factor ([1,2])
-%!error <Q must be a real integer> factor (1.5)
+%!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)
+%!error <Q must be a real non-negative integer> factor (-20)
--- a/scripts/specfun/primes.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/specfun/primes.m	Thu Dec 20 17:18:56 2018 -0500
@@ -48,8 +48,8 @@
     print_usage ();
   endif
 
-  if (! isscalar (n))
-    error ("primes: N must be a scalar");
+  if (! (isnumeric (n) && isscalar (n)))
+    error ("primes: N must be a numeric scalar");
   endif
 
   if (n > 100e3)
@@ -107,4 +107,5 @@
 
 %!error primes ()
 %!error primes (1, 2)
-%!error <N must be a scalar> primes (ones (2,2))
+%!error <N must be a numeric scalar> primes ("1")
+%!error <N must be a numeric scalar> primes (ones (2,2))
--- a/scripts/special-matrix/magic.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/special-matrix/magic.m	Thu Dec 20 17:18:56 2018 -0500
@@ -36,10 +36,10 @@
   endif
 
   n = fix (n);
-  if (n < 1)
-
+  if (n < 0)
+    error ("magic: N must be non-negative");
+  elseif (n < 1)
     A = [];
-
   elseif (mod (n, 2) == 1)
 
     shift = floor ((0:n*n-1)/n);
@@ -91,10 +91,8 @@
 %!test <*46672>
 %! m = magic (2);
 %! assert (size (m), [2 2]);
-%! assert (unique (m), [1; 2; 3; 4]);
+%! assert (m, [4 3; 1 2]);
 
-%!assert (magic (2), [4 3; 1 2])
-%!assert (isempty (magic (-1)))
 %!assert (isempty (magic (0)))
 %!assert (magic (1), 1)
 %!assert (magic (1.5), 1)
@@ -102,3 +100,4 @@
 ## Test input validation
 %!error magic ()
 %!error magic (1, 2)
+%!error <N must be non-negative> magic (-5)
--- a/scripts/statistics/corrcoef.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/corrcoef.m	Thu Dec 20 17:18:56 2018 -0500
@@ -19,9 +19,9 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{r} =} corrcoef (@var{x})
 ## @deftypefnx {} {@var{r} =} corrcoef (@var{x}, @var{y})
+## @deftypefnx {} {@var{r} =} corrcoef (@dots{}, @var{param}, @var{value}, @dots{})
 ## @deftypefnx {} {[@var{r}, @var{p}] =} corrcoef (@dots{})
 ## @deftypefnx {} {[@var{r}, @var{p}, @var{lci}, @var{hci}] =} corrcoef (@dots{})
-## @deftypefnx {} {[@dots{}] =} corrcoef (@dots{}, @var{param}, @var{value}, @dots{})
 ## Compute a matrix of correlation coefficients.
 ##
 ## @var{x} is an array where each column contains a variable and each row is
@@ -30,24 +30,13 @@
 ## If a second input @var{y} (of the same size as @var{x}) is given then
 ## calculate the correlation coefficients between @var{x} and @var{y}.
 ##
-## @var{r} is a matrix of Pearson's product moment correlation coefficients for
-## each pair of variables.
-##
-## @var{p} is a matrix of pair-wise p-values testing for the null hypothesis of
-## a correlation coefficient of zero.
-##
-## @var{lci} and @var{hci} are matrices containing, respectively, the lower and
-## higher bounds of the 95% confidence interval of each correlation
-## coefficient.
-##
-## @var{param}, @var{value} are pairs of optional parameters and values.
-## Valid options are:
+## @var{param}, @var{value} are optional pairs of parameters and values which
+## modify the calculation.  Valid options are:
 ##
 ## @table @asis
 ## @item @qcode{"alpha"}
-## Confidence level used for the definition of the bounds of the confidence
-## interval, @var{lci} and @var{hci}.  Default is 0.05, i.e., 95% confidence
-## interval.
+## Confidence level used for the bounds of the confidence interval, @var{lci}
+## and @var{hci}.  Default is 0.05, i.e., 95% confidence interval.
 ##
 ## @item @qcode{"rows"}
 ## Determine processing of NaN values.  Acceptable values are @qcode{"all"},
@@ -55,9 +44,17 @@
 ## With @qcode{"complete"}, only the rows without NaN values are considered.
 ## With @qcode{"pairwise"}, the selection of NaN-free rows is made for each
 ## pair of variables.
-##
 ## @end table
 ##
+## Output @var{r} is a matrix of Pearson's product moment correlation
+## coefficients for each pair of variables.
+##
+## Output @var{p} is a matrix of pair-wise p-values testing for the null
+## hypothesis of a correlation coefficient of zero.
+##
+## Outputs @var{lci} and @var{hci} are matrices containing, respectively, the
+## lower and higher bounds of the 95% confidence interval of each correlation
+## coefficient.
 ## @seealso{corr, cov}
 ## @end deftypefn
 
@@ -75,9 +72,15 @@
 
   if (nargin > 1)
 
-    ## Check for numeric y argument
+    ## Check for matrix argument y
     if (isnumeric (varargin{1}))
-      x = [x(:), varargin{1}(:)];
+      y = varargin{1};
+      nx = numel (x);
+      ny = numel (y);
+      if (nx > 0 && ny > 0 && nx != ny)
+        error ("corrcoef: X and Y must be the same size");
+      endif
+      x = [x(:), y(:)];
       varargin(1) = [];
     endif
 
@@ -88,7 +91,7 @@
         error ("corrcoef: parameter %d must be a string", i);
       endif
       parameter = varargin{i};
-      if (numel (varargin) < i+1)
+      if (i+1 > numel (varargin))
         error ('corrcoef: parameter "%s" missing value', parameter);
       endif
       value = varargin{i+1};
@@ -99,7 +102,7 @@
               && value >= 0 && value <= 1)
             alpha = value;
           else
-            error ('corrcoef: "alpha" must be a number between 0 and 1');
+            error ('corrcoef: "alpha" must be a scalar between 0 and 1');
           endif
 
         case "rows"
@@ -111,7 +114,7 @@
             case {"all", "complete", "pairwise"}
               rows = value;
             otherwise
-              error ('corrcoef: "rows" must be "all", "complete", or "pairwise".');
+              error ('corrcoef: "rows" must be "all", "complete", or "pairwise"');
           endswitch
 
         otherwise
@@ -228,27 +231,16 @@
 %! assert (size (r) == [5, 5]);
 
 %!test
-%! x = [1 2 3];
+%! x = [1, 2, 3];
 %! r = corrcoef (x);
 %! assert (size (r) == [1, 1]);
 
-%!test
-%! x = [];
-%! r = corrcoef (x);
-%! assert (isnan (r));
+%!assert (isnan (corrcoef ([])))
+%!assert (isnan (corrcoef (NaN)))
+%!assert (isnan (corrcoef (1)))
 
 %!test
-%! x = [NaN];
-%! r = corrcoef (x);
-%! assert (isnan (r));
-
-%!test
-%! x = [1];
-%! r = corrcoef (x);
-%! assert (isnan (r));
-
-%!test
-%! x = [NaN NaN];
+%! x = [NaN, NaN];
 %! r = corrcoef (x);
 %! assert (size(r) == [1, 1] && isnan (r));
 
@@ -256,6 +248,7 @@
 %! x = rand (5);
 %! [r, p] = corrcoef (x);
 %! assert (size (r) == [5, 5] && size (p) == [5 5]);
+%! assert (diag (r), ones (5,1), eps);
 
 %!test
 %! x = rand (5,1);
@@ -263,6 +256,8 @@
 %! R1 = corrcoef (x, y);
 %! R2 = corrcoef ([x, y]);
 %! assert (R1, R2);
+%! R3 = corrcoef (x.', y.');
+%! assert (R1, R3);
 
 %!test
 %! x = [1;2;3];
@@ -282,13 +277,12 @@
 %! r = corrcoef (x, y);
 %! assert (r, [1, NaN; NaN, 1]);
 
-%!test
 %!error 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 number> corrcoef (1,2, "alpha", "1")
-%!error <"alpha" must be a number> corrcoef (1,2, "alpha", ones (2,2))
-%!error <"alpha" must be a number between 0 and 1> corrcoef (1,2, "alpha", -1)
-%!error <"alpha" must be a number between 0 and 1> corrcoef (1,2, "alpha", 2)
+%!error <"alpha" must be a scalar> corrcoef (1,2, "alpha", "1")
+%!error <"alpha" must be a scalar> corrcoef (1,2, "alpha", ones (2,2))
+%!error <"alpha" must be a scalar between 0 and 1> corrcoef (1,2, "alpha", -1)
+%!error <"alpha" must be a scalar between 0 and 1> corrcoef (1,2, "alpha", 2)
 %!error <"rows" must be "all"...> corrcoef (1,2, "rows", "foobar")
 %!error <Unknown option "foobar"> corrcoef (1,2, "foobar", 1)
--- a/scripts/statistics/discrete_cdf.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/discrete_cdf.m	Thu Dec 20 17:18:56 2018 -0500
@@ -42,7 +42,7 @@
 
   p = p(:) / sum (p);   # Reshape and normalize probability vector
 
-  if (isa (x, "single") || isa (v, "single") || isa (p, "single"));
+  if (isa (x, "single") || isa (v, "single") || isa (p, "single"))
     cdf = NaN (size (x), "single");
   else
     cdf = NaN (size (x));
--- a/scripts/statistics/discrete_inv.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/discrete_inv.m	Thu Dec 20 17:18:56 2018 -0500
@@ -43,7 +43,7 @@
     error ("discrete_inv: P must be a nonzero, non-negative vector");
   endif
 
-  if (isa (x, "single") || isa (v, "single") || isa (p, "single"));
+  if (isa (x, "single") || isa (v, "single") || isa (p, "single"))
     inv = NaN (size (x), "single");
   else
     inv = NaN (size (x));
@@ -51,7 +51,7 @@
 
   ## FIXME: This isn't elegant.  But cumsum and lookup together produce
   ## different results when called with a single or a double.
-  if (isa (p, "single"));
+  if (isa (p, "single"))
     p = double (p);
   endif
 
--- a/scripts/statistics/iqr.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/iqr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -68,7 +68,7 @@
     y = zeros (sz);
   endif
   stride = prod (sz(1:dim-1));
-  for i = 1 : nel / n;
+  for i = 1 : nel / n
     offset = i;
     offset2 = 0;
     while (offset > stride)
--- a/scripts/statistics/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -24,6 +24,15 @@
   %reldir%/median.m \
   %reldir%/mode.m \
   %reldir%/moment.m \
+  %reldir%/movmad.m \
+  %reldir%/movmax.m \
+  %reldir%/movmean.m \
+  %reldir%/movmedian.m \
+  %reldir%/movmin.m \
+  %reldir%/movprod.m \
+  %reldir%/movstd.m \
+  %reldir%/movsum.m \
+  %reldir%/movvar.m \
   %reldir%/prctile.m \
   %reldir%/quantile.m \
   %reldir%/range.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movmad.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,142 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movmad (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movmad (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movmad (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movmad (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movmad (@dots{}, @var{property}, @var{value})
+## Calculate the moving mean absolute deviation over a sliding window of length
+## @var{wlen} on data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{mad} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movmad} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movmad} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{mad}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = mad (@var{x}(1:2))}, and
+## @code{@var{y}(end) = mad (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = mad ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mad ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{mad} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = mad ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mad ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = mad ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mad ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = mad ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mad ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmax, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movmad (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@mad, x, wlen, __parse_movargs__ ("movmad", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# 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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movmax.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movmax (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movmax (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movmax (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movmax (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movmax (@dots{}, @var{property}, @var{value})
+## Calculate the moving maximum over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{max} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movmax} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movmax} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{max}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = max (@var{x}(1:2))}, and
+## @code{@var{y}(end) = max (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = max ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = max ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{max} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = max ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = max ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = max ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = max ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = max ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = max ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movmax (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@max, x, wlen, __parse_movargs__ ("movmax", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([(2:10).'; 10], movmax ((1:10).', 3))
+
+## Test input validation
+%!error movmax ()
+%!error movmax (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movmean.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movmean (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movmean (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movmean (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movmean (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movmean (@dots{}, @var{property}, @var{value})
+## Calculate the moving average over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{mean} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movmean} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movmean} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{mean}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = mean (@var{x}(1:2))}, and
+## @code{@var{y}(end) = mean (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = mean ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mean ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{mean} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = mean ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mean ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = mean ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mean ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = mean ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = mean ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmedian, movmin, movprod, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movmean (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@mean, x, wlen, __parse_movargs__ ("movmean", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([1.5; (2:9).'; 9.5], movmean ((1:10).', 3))
+
+## Test input validation
+%!error movmean ()
+%!error movmean (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movmedian.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movmedian (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movmedian (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movmedian (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movmedian (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movmedian (@dots{}, @var{property}, @var{value})
+## Calculate the moving median over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{movmedian} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movmedian} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movmedian} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{movmedian}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = movmedian (@var{x}(1:2))}, and
+## @code{@var{y}(end) = movmedian (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = movmedian ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movmedian ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{movmedian} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = movmedian ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movmedian ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = movmedian ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movmedian ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = movmedian ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movmedian ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmin, movprod, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movmedian (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@median, x, wlen, __parse_movargs__ ("movmedian", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([1.5; (2:9).'; 9.5], movmedian ((1:10).', 3))
+
+## Test input validation
+%!error movmedian ()
+%!error movmedian (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movmin.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movmin (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movmin (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movmin (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movmin (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movmin (@dots{}, @var{property}, @var{value})
+## Calculate the moving minimum over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{min} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movmin} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movmin} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{min}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = min (@var{x}(1:2))}, and
+## @code{@var{y}(end) = min (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = min ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = min ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{min} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = min ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = min ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = min ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = min ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = min ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = min ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movprod, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movmin (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@min, x, wlen, __parse_movargs__ ("movmin", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([1; (1:9).'], movmin ((1:10).', 3))
+
+## Test input validation
+%!error movmin ()
+%!error movmin (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movprod.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movprod (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movprod (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movprod (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movprod (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movprod (@dots{}, @var{property}, @var{value})
+## Calculate the moving product over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{movprod} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movprod} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movprod} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{movprod}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = movprod (@var{x}(1:2))}, and
+## @code{@var{y}(end) = movprod (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = movprod ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movprod ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{movprod} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = movprod ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movprod ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = movprod ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movprod ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = movprod ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movprod ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movstd, movsum, movvar}
+## @end deftypefn
+
+function y = movprod (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@prod, x, wlen, __parse_movargs__ ("movprod", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# 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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movstd.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movstd (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movstd (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movstd (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movstd (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movstd (@dots{}, @var{property}, @var{value})
+## Calculate the moving standard deviation over a sliding window of length
+## @var{wlen} on data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{movstd} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movstd} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movstd} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{movstd}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = movstd (@var{x}(1:2))}, and
+## @code{@var{y}(end) = movstd (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = movstd ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movstd ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{movstd} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = movstd ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movstd ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = movstd ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movstd ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = movstd ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movstd ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movsum, movvar}
+## @end deftypefn
+
+function y = movstd (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@std, x, wlen, __parse_movargs__ ("movstd", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([1/sqrt(2); ones(8,1); 1/sqrt(2)], movstd ((1:10).', 3), 1e-8)
+
+## Test input validation
+%!error movstd ()
+%!error movstd (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movsum.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movsum (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movsum (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movsum (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movsum (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movsum (@dots{}, @var{property}, @var{value})
+## Calculate the moving sum over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{movsum} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movsum} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movsum} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{movsum}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = movsum (@var{x}(1:2))}, and
+## @code{@var{y}(end) = movsum (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = movsum ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movsum ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{movsum} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = movsum ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movsum ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = movsum ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movsum ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = movsum ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = movsum ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movvar}
+## @end deftypefn
+
+function y = movsum (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@sum, x, wlen, __parse_movargs__ ("movsum", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([(3:3:27).'; 19], movsum ((1:10).', 3))
+
+## Test input validation
+%!error movsum ()
+%!error movsum (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/movvar.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,141 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## 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} =} movvar (@var{x}, @var{wlen})
+## @deftypefnx {} {@var{y} =} movvar (@var{x}, [@var{na}, @var{nb}])
+## @deftypefnx {} {@var{y} =} movvar (@dots{}, @var{dim})
+## @deftypefnx {} {@var{y} =} movvar (@dots{}, "@var{nancond}")
+## @deftypefnx {} {@var{y} =} movvar (@dots{}, @var{property}, @var{value})
+## Calculate the moving variance over a sliding window of length @var{wlen} on
+## data @var{x}.
+##
+## If @var{wlen} is a scalar, the function @code{var} is applied to a
+## moving window of length @var{wlen}.  When @var{wlen} is an odd number the
+## window is symmetric and includes @w{@code{(@var{wlen} - 1) / 2}} elements on
+## either side of the central element.  For example, when calculating the
+## output at index 5 with a window length of 3, @code{movvar} uses data
+## elements @w{@code{[4, 5, 6]}}.  If @var{wlen} is an even number, the window
+## is asymmetric and has @w{@code{@var{wlen}/2}} elements to the left of the
+## central element and @w{@code{@var{wlen}/2 - 1}} elements to the right of the
+## central element.  For example, when calculating the output at index 5 with a
+## window length of 4, @code{movvar} uses data elements
+## @w{@code{[3, 4, 5, 6]}}.
+##
+## If @var{wlen} is an array with two elements @w{@code{[@var{nb}, @var{na}]}},
+## the function is applied to a moving window @code{-@var{nb}:@var{na}}.  This
+## window includes @var{nb} number of elements @emph{before} the current
+## element and @var{na} number of elements @emph{after} the current element.
+## The current element is always included.  For example, given
+## @w{@code{@var{wlen} = [3, 0]}}, the data used to calculate index 5 is
+## @w{@code{[2, 3, 4, 5]}}.
+##
+## If the optional argument @var{dim} is given, operate along this dimension.
+##
+## The optional string argument @qcode{"@var{nancond}"} controls whether
+## @code{NaN} and @code{NA} values should be included (@qcode{"includenan"}),
+## or excluded (@qcode{"omitnan"}), from the data passed to @code{var}.  The
+## default is @qcode{"includenan"}.  Caution: the @qcode{"omitnan"} option is
+## not yet implemented.
+##
+## The calculation can be controlled by specifying @var{property}/@var{value}
+## pairs.  Valid properties are
+##
+## @table @asis
+##
+## @item @qcode{"Endpoints"}
+##
+## This property controls how results are calculated at the boundaries
+## (@w{endpoints}) of the window.  Possible values are:
+##
+## @table @asis
+## @item @qcode{"shrink"}  (default)
+## The window is truncated at the beginning and end of the array to exclude
+## elements for which there is no source data.  For example, with a window of
+## length 3, @code{@var{y}(1) = var (@var{x}(1:2))}, and
+## @code{@var{y}(end) = var (@var{x}(end-1:end))}.
+##
+## @item @qcode{"discard"}
+## Any @var{y} values that use a window extending beyond the original
+## data array are deleted.  For example, with a 10-element data vector and a
+## window of length 3, the output will contain only 8 elements.  The first
+## element would require calculating the function over indices
+## @w{@code{[0, 1, 2]}} and is therefore discarded.  The last element would
+## require calculating the function over indices @w{@code{[9, 10, 11]}} and is
+## therefore discarded.
+##
+## @item @qcode{"fill"}
+## Any window elements outside the data array are replaced by @code{NaN}.  For
+## example, with a window of length 3,
+## @code{@var{y}(1) = var ([NaN, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = var ([@var{x}(end-1:end), NaN])}.
+## This option usually results in @var{y} having @code{NaN} values at the
+## boundaries, although it is influenced by how @code{var} handles @code{NaN},
+## and also by the property @qcode{"nancond"}.
+##
+## @item @var{user_value}
+## Any window elements outside the data array are replaced by the specified
+## value @var{user_value} which must be a numeric scalar.  For example, with a
+## window of length 3,
+## @code{@var{y}(1) = var ([@var{user_value}, @var{x}(1:2)])}, and
+## @code{@var{y}(end) = var ([@var{x}(end-1:end), @var{user_value}])}.
+## A common choice for @var{user_value} is 0.
+##
+## @item @qcode{"same"}
+## Any window elements outside the data array are replaced by the value of
+## @var{x} at the boundary.  For example, with a window of length 3,
+## @code{@var{y}(1) = var ([@var{x}(1), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = var ([@var{x}(end-1:end), @var{x}(end)])}.
+##
+## @item @qcode{"periodic"}
+## The window is wrapped so that any missing data elements are taken from
+## the other side of the data.  For example, with a window of length 3,
+## @code{@var{y}(1) = var ([@var{x}(end), @var{x}(1:2)])}, and
+## @code{@var{y}(end) = var ([@var{x}(end-1:end), @var{x}(1)])}.
+##
+## @end table
+##
+## @item @qcode{"SamplePoints"}
+## Caution: This option is not yet implemented.
+##
+## @end table
+##
+## Programming Note: This function is a wrapper which calls @code{movfun}.
+## For additional options and documentation, @xref{XREFmovfun,,movfun}.
+##
+## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movsum}
+## @end deftypefn
+
+function y = movvar (x, wlen, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  y = movfun (@var, x, wlen, __parse_movargs__ ("movvar", varargin{:}){:});
+
+endfunction
+
+
+## FIXME: Need functional BIST tests
+# test for bug #55241
+%!assert ([0.5; ones(8,1); 0.5], movvar ((1:10).', 3))
+
+## Test input validation
+%!error movvar ()
+%!error movvar (1)
--- a/scripts/statistics/quantile.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/quantile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -187,21 +187,30 @@
   ## Permute dim to the 1st index.
   x = permute (x, perm);
 
-  ## Save the size of the permuted x N-d array.
+  ## Save the size of the permuted x N-D array.
   sx = size (x);
 
-  ## Reshape to a 2-d array.
-  x = reshape (x, [sx(1), prod(sx(2:end))]);
+  ## Reshape to a 2-D array.
+  x = reshape (x, sx(1), []);
 
   ## Calculate the quantiles.
   q = __quantile__ (x, p, method);
 
-  ## Return the shape to the original N-d array.
+  ## Return the shape to the original N-D array.
   q = reshape (q, [numel(p), sx(2:end)]);
 
   ## Permute the 1st index back to dim.
   q = ipermute (q, perm);
 
+  ## For Matlab compatibility, return vectors with the same orientation as p
+  if (isvector (q) && ! isscalar (q) && ! isscalar (p))
+    if (isrow (p))
+      q = reshape (q, 1, []);
+    else
+      q = reshape (q, [], 1);
+    endif
+  endif
+
 endfunction
 
 
@@ -251,7 +260,7 @@
 %!      1.0000   1.4167   2.5000   3.5833   4.0000
 %!      1.0000   1.4375   2.5000   3.5625   4.0000];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -268,7 +277,7 @@
 %!      1.0000   1.6667   3.0000   4.3333   5.0000
 %!      1.0000   1.6875   3.0000   4.3125   5.0000];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -285,7 +294,7 @@
 %!      1.0000   1.4167   3.5000   7.3333   9.0000
 %!      1.0000   1.4375   3.5000   7.2500   9.0000];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -302,7 +311,7 @@
 %!      1.0000    1.6667    5.0000    9.6667   11.0000
 %!      1.0000    1.6875    5.0000    9.6250   11.0000];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -319,7 +328,7 @@
 %!      6.0000    9.8333   11.5000   15.0000   16.0000
 %!      6.0000    9.8750   11.5000   15.0000   16.0000];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -337,7 +346,7 @@
 %!      -2.551474  -0.591566  -0.067751   0.146459   0.495271
 %!      -2.551474  -0.590801  -0.067751   0.140686   0.495271];
 %! for m = 1:9
-%!   q = quantile (x, p, 1, m).';
+%!   q = quantile (x, p, 1, m);
 %!   assert (q, a(m,:), 0.0001);
 %! endfor
 
@@ -366,6 +375,10 @@
 %! assert (yobs, yexp);
 
 %!assert <*45455> (quantile ([1 3 2], 0.5, 1), [1 3 2])
+%!assert <*54421> (quantile ([1:10], 0.5, 1), 1:10)
+%!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])
 
 ## Test input validation
 %!error quantile ()
--- a/scripts/statistics/ranks.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/statistics/ranks.m	Thu Dec 20 17:18:56 2018 -0500
@@ -1,4 +1,5 @@
 ## Copyright (C) 1995-2018 Kurt Hornik
+## Copyright (C) 2012 Dave Goel
 ##
 ## This file is part of Octave.
 ##
@@ -17,24 +18,36 @@
 ## <https://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {} {} ranks (@var{x}, @var{dim})
-## Return the ranks of @var{x} along the first non-singleton dimension
-## adjusted for ties.
+## @deftypefn  {} {} ranks (@var{x})
+## @deftypefnx {} {} ranks (@var{x}, @var{dim})
+## @deftypefnx {} {} ranks (@var{x}, @var{dim}, @var{rtype})
+## Return the ranks (in the sense of order statistics) of @var{x} along the
+## first non-singleton dimension adjusted for ties.
+##
+## If the optional @var{dim} argument is given, operate along this dimension.
+##
+## The optional parameter @var{rtype} determines how ties are handled.  All
+## examples below assume an input of @code{[ 1, 2, 2, 4 ]}.
 ##
-## If the optional argument @var{dim} is given, operate along this dimension.
+## @table @asis
+## @item 0 or @qcode{"fractional"} (default) for fractional ranking (1, 2.5,
+## 2.5, 4);
+##
+## @item 1 or @qcode{"competition"} for competition ranking (1, 2, 2, 4);
+##
+## @item 2 or @qcode{"modified"} for modified competition ranking (1, 3, 3, 4);
+##
+## @item 3 or @qcode{"ordinal"} for ordinal ranking (1, 2, 3, 4);
+##
+## @item 4 or @qcode{"dense"} for dense ranking (1, 2, 2, 3).
+## @end table
+##
 ## @seealso{spearman, kendall}
 ## @end deftypefn
 
-## Author: KH <Kurt.Hornik@wu-wien.ac.at>
-## Description: Compute ranks
+function y = ranks (x, dim, rtype = 0)
 
-## This code was rather ugly, since it didn't use sort due to the
-## fact of how to deal with ties.  Now it does use sort and its
-## even uglier!  At least it handles NDArrays.
-
-function y = ranks (x, dim)
-
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -44,41 +57,61 @@
 
   nd = ndims (x);
   sz = size (x);
-  if (nargin != 2)
+
+  if (nargin < 2 || isempty (dim))
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
       error ("ranks: DIM must be an integer and a valid dimension");
     endif
   endif
 
   if (sz(dim) == 1)
-    y = ones (sz);
+    y = ones (sz);  # dimension DIM is singleton, so all are ranked first.
   else
-    ## The algorithm works only on dim = 1, so permute if necesary.
+    ## The algorithm works only on dim = 1, so permute if necessary.
+    ## FIXME: Most all functions now accept a dim argument.
+    ##        Would it be faster not to permute and use the dim argument
+    ##        to sort, find, cumsum, etc.?
     if (dim != 1)
       perm = [1 : nd];
       perm(1) = dim;
       perm(dim) = 1;
       x = permute (x, perm);
+      sz = size (x);
     endif
-    sz = size (x);
-    infvec = -Inf ([1, sz(2 : end)]);
-    [xs, xi] = sort (x);
-    eq_el = find (diff ([xs; infvec]) == 0);
-    if (isempty (eq_el))
-      [eq_el, y] = sort (xi);
-    else
-      runs = setdiff (eq_el, eq_el+1);
-      len = diff (find (diff ([Inf; eq_el; -Inf]) != 1)) + 1;
-      [eq_el, y] = sort (xi);
-      for i = 1 : length (runs)
-        y (xi (runs (i) + [0:(len(i)-1)]) + floor (runs (i) ./ sz(1))
-           * sz(1)) = eq_el(runs(i)) + (len(i) - 1) / 2;
-      endfor
-    endif
+
+    [sx, ids] = sort (x);  # sx is sorted x.
+    lin = repmat ((1:rows (x))', [1, sz(2:end)]);  # linearly increasing array.
+
+    switch (rtype)
+      case {0, "fractional"};
+        lin = (_competition (lin, sx, sz) + _modified (lin, sx, sz)) / 2;
+      case {1, "competition"};
+        lin = _competition (lin, sx, sz);
+      case {2, "modified"};
+        lin = _modified (lin, sx, sz);
+      case {3, "ordinal"};
+        ## no processing needed here.
+      case {4, "dense"};
+        lin = _dense (lin, sx, sz);
+      otherwise
+        if (! ischar (rtype))
+          rtype = num2str (rtype);
+        end
+        error ("ranks: unknown RTYPE '%s'", rtype);
+    endswitch
+
+    y = NaN (size (lin));
+
+    ## Offsets to map indices into each column to indices into the linear array.
+    ## FIXME: Would sub2ind be faster here?
+    idf = zeros (sz);
+    idf(1, :) = 0 : sz(1) : (numel (ids)-1);
+    idf(:, :) = repmat (idf(1, :), [sz(1), ones(1,length(sz)-1)]);
+    y(ids + idf) = lin;
+
     if (dim != 1)
       y = permute (y, perm);
     endif
@@ -86,6 +119,30 @@
 
 endfunction
 
+function linnew = _dense (lin, sx, sz)
+  infvec = -Inf ([1, sz(2:end)]);
+  fnewp = logical (diff ([infvec; sx]));
+  linnew = cumsum (fnewp, 1);
+endfunction
+
+function linnew = _competition (lin, sx, sz)
+  ## Stop increasing lin when sx does not increase.  Otherwise, same as before.
+  infvec = -Inf ([1, sz(2:end)]);
+  fnewp = find (diff ([infvec; sx]));
+  linnew = zeros (size (lin));
+  linnew(fnewp) = lin(fnewp);
+  linnew = cummax (linnew, 1);
+endfunction
+
+function linnew = _modified (lin, sx, sz)
+  ## Traverse lin backwards.  Stop decreasing it when sx doesn't decrease.
+  infvec = Inf ([1, sz(2:end)]);
+  fnewp = find (diff ([sx; infvec]));
+  linnew = Inf (size (lin));
+  linnew(fnewp) = lin(fnewp);
+  linnew = flip (cummin (flip (linnew, 1)), 1);
+endfunction
+
 
 %!assert (ranks (1:2:10), 1:5)
 %!assert (ranks (10:-2:1), 5:-1:1)
@@ -94,11 +151,17 @@
 %!assert (ranks (1e6*ones (1, 5)), 3*ones (1, 5))
 %!assert (ranks (rand (1, 5), 1), ones (1, 5))
 
+%!assert (ranks ([1, 2, 2, 4], [], "fractional"), [1, 2.5, 2.5, 4])
+%!assert (ranks ([1, 2, 2, 4], [], "competition"), [1, 2, 2, 4])
+%!assert (ranks ([1, 2, 2, 4], [], "modified"), [1, 3, 3, 4])
+%!assert (ranks ([1, 2, 2, 4], [], "ordinal"), [1, 2, 3, 4])
+%!assert (ranks ([1, 2, 2, 4], [], "dense"), [1, 2, 2, 3])
+
 ## Test input validation
 %!error ranks ()
-%!error ranks (1, 2, 3)
-%!error ranks ({1, 2})
-%!error ranks (['A'; 'B'])
-%!error ranks (1, 1.5)
-%!error ranks (1, 0)
-%!error ranks (1, 3)
+%!error ranks (1, 2, 3, 4)
+%!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)
+%!error <DIM must be .* a valid dimension> ranks (1, 0)
+%!error <unknown RTYPE 'foobar'> ranks (ones (2), 1, "foobar")
--- a/scripts/strings/base2dec.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/strings/base2dec.m	Thu Dec 20 17:18:56 2018 -0500
@@ -74,7 +74,7 @@
     endif
   elseif (! isscalar (base))
     error ("base2dec: cannot convert from several bases at once");
-  elseif (base < 2 || base > length (symbols))
+  elseif (! (base >= 2 && base <= length (symbols)))
     error ("base2dec: BASE must be between 2 and 36, or a string of symbols");
   else
     s = toupper (s);
@@ -127,7 +127,9 @@
 %!error base2dec ()
 %!error base2dec ("11120")
 %!error base2dec ("11120", 3, 4)
-%!error base2dec ("11120", "1231")
-%!error base2dec ("11120", "12 3")
-%!error base2dec ("11120", ones (2))
-%!error base2dec ("11120", 37)
+%!error <symbols .* must be unique> base2dec ("11120", "1231")
+%!error <whitespace characters are not valid> base2dec ("11120", "12 3")
+%!error <cannot convert from several bases> base2dec ("11120", ones (2))
+%!error <BASE must be between 2 and 36> base2dec ("11120", 1)
+%!error <BASE must be between 2 and 36> base2dec ("11120", 37)
+%!error <BASE must be between 2 and 36> base2dec ("11120", NaN)
--- a/scripts/strings/findstr.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-## Copyright (C) 1996-2018 Kurt Hornik
-##
-## 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  {} {} findstr (@var{s}, @var{t})
-## @deftypefnx {} {} findstr (@var{s}, @var{t}, @var{overlap})
-## Return the vector of all positions in the longer of the two strings @var{s}
-## and @var{t} where an occurrence of the shorter of the two starts.
-##
-## If the optional argument @var{overlap} is true (default), the returned
-## vector can include overlapping positions.  For example:
-##
-## @example
-## @group
-## findstr ("ababab", "a")
-##      @result{} [1, 3, 5];
-## findstr ("abababa", "aba", 0)
-##      @result{} [1, 5]
-## @end group
-## @end example
-##
-## @strong{Caution:} @code{findstr} is scheduled for deprecation.  Use
-## @code{strfind} in all new code.
-## @seealso{strfind, strmatch, strcmp, strncmp, strcmpi, strncmpi, find}
-## @end deftypefn
-
-## Note that this implementation swaps the strings if second one is longer
-## than the first, so try to put the longer one first.
-##
-## Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
-## Adapted-By: jwe
-
-function v = findstr (s, t, overlap = true)
-
-  if (nargin < 2 || nargin > 3)
-    print_usage ();
-  endif
-
-  if (all (size (s) > 1) || all (size (t) > 1))
-    error ("findstr: arguments must have only one non-singleton dimension");
-  endif
-
-  ## Make S be the longer string.
-  if (length (s) < length (t))
-    [s, t] = deal (t, s);
-  endif
-
-  l_s = length (s);
-  l_t = length (t);
-
-  if (l_t == 0)
-    ## zero length target: return empty set
-    v = [];
-
-  elseif (l_t == 1)
-    ## length one target: simple find
-    v = find (s == t);
-
-  elseif (l_t == 2)
-    ## length two target: find first at i and second at i+1
-    v = find (s(1:l_s-1) == t(1) & s(2:l_s) == t(2));
-
-  else
-    ## length three or more: match the first three by find then go through
-    ## the much smaller list to determine which of them are real matches
-    limit = l_s - l_t + 1;
-    v = find (  s(1:limit)   == t(1)
-              & s(2:limit+1) == t(2)
-              & s(3:limit+2) == t(3));
-  endif
-
-  ## Need to search the index vector if our find was too short
-  ## (target length > 3), or if we don't allow overlaps.  Note though
-  ## that there cannot be any overlaps if the first character in the
-  ## target is different from the remaining characters in the target,
-  ## so a single character, two different characters, or first character
-  ## different from the second two don't need to be searched.
-  if (l_t >= 3 || (! overlap && l_t > 1 && any (t(1) == t(2:l_t))))
-    ## force strings to be both row vectors or both column vectors
-    if (all (size (s) != size (t)))
-      t = t.';
-    endif
-
-    ## determine which ones to keep
-    keep = zeros (size (v));
-    ind = 0:l_t-1;
-    if (overlap)
-      for idx = 1:length (v)
-        keep(idx) = all (s(v(idx) + ind) == t);
-      endfor
-    else
-      ## First possible position for next non-overlapping match.
-      next = 1;
-      for idx = 1:length (v)
-        if (v(idx) >= next && s(v(idx) + ind) == t)
-          keep(idx) = 1;
-          ## Skip to the next possible match position.
-          next = v(idx) + l_t;
-        else
-          keep(idx) = 0;
-        endif
-      endfor
-    endif
-    if (! isempty (v))
-      v = v(find (keep));
-    endif
-  endif
-
-  if (isempty (v))
-    v = [];
-  endif
-
-  ## Always return a row vector, because that's what the old one did.
-  if (iscolumn (v))
-    v = v.';
-  endif
-
-endfunction
-
-
-%!assert (findstr ("abababa", "a"), [1, 3, 5, 7])
-%!assert (findstr ("abababa", "aba"), [1, 3, 5])
-%!assert (findstr ("aba", "abababa", 0), [1, 5])
-
-## Test input validation
-%!error findstr ()
-%!error findstr ("foo", "bar", 3, 4)
-%!error <must have only one non-singleton dimension> findstr (["AB" ; "CD"], "C")
--- a/scripts/strings/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/strings/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -10,7 +10,6 @@
   %reldir%/dec2bin.m \
   %reldir%/dec2hex.m \
   %reldir%/erase.m \
-  %reldir%/findstr.m \
   %reldir%/hex2dec.m \
   %reldir%/index.m \
   %reldir%/isletter.m \
@@ -26,7 +25,6 @@
   %reldir%/strchr.m \
   %reldir%/strjoin.m \
   %reldir%/strjust.m \
-  %reldir%/strmatch.m \
   %reldir%/strsplit.m \
   %reldir%/strtok.m \
   %reldir%/strtrim.m \
--- a/scripts/strings/strmatch.m	Tue Dec 04 10:12:41 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-## Copyright (C) 2000-2018 Paul Kienzle
-## Copyright (C) 2003 Alois Schloegl
-## Copyright (C) 2010 VZLU Prague
-##
-## 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  {} {} strmatch (@var{s}, @var{A})
-## @deftypefnx {} {} strmatch (@var{s}, @var{A}, "exact")
-## Return indices of entries of @var{A} which begin with the string @var{s}.
-##
-## The second argument @var{A} must be a string, character matrix, or a cell
-## array of strings.
-##
-## If the third argument @qcode{"exact"} is not given, then @var{s} only
-## needs to match @var{A} up to the length of @var{s}.  Trailing spaces and
-## nulls in @var{s} and @var{A} are ignored when matching.
-##
-## For example:
-##
-## @example
-## @group
-## strmatch ("apple", "apple juice")
-##      @result{} 1
-##
-## strmatch ("apple", ["apple  "; "apple juice"; "an apple"])
-##      @result{} [1; 2]
-##
-## strmatch ("apple", ["apple  "; "apple juice"; "an apple"], "exact")
-##      @result{} [1]
-## @end group
-## @end example
-##
-## @strong{Caution:} @code{strmatch} is scheduled for deprecation.  Use
-## @code{strncmp} (normal case), or @code{strcmp} (@qcode{"exact"} case), or
-## @code{regexp} in all new code.
-## @seealso{strfind, findstr, strcmp, strncmp, strcmpi, strncmpi, find}
-## @end deftypefn
-
-## Author: Paul Kienzle, Alois Schloegl
-## Adapted-by: jwe
-
-function idx = strmatch (s, A, exact)
-
-  if (nargin < 2 || nargin > 3)
-    print_usage ();
-  endif
-
-  if (! ischar (s) || (! isempty (s) && ! isvector (s)))
-    error ("strmatch: S must be a string");
-  elseif (! (ischar (A) || iscellstr (A)))
-    error ("strmatch: A must be a string or cell array of strings");
-  endif
-
-  ## Trim blanks and nulls from search string
-  if (any (s != " " & s != "\0"))
-    s = regexprep (s, "[ \\0]+$", '');
-  endif
-  len = length (s);
-
-  exact = nargin == 3 && ischar (exact) && strcmp (exact, "exact");
-
-  if (ischar (A))
-    [nr, nc] = size (A);
-    if (len > nc)
-      idx = [];
-    else
-      match = all (bsxfun (@eq, A(:,1:len), s), 2);
-      if (exact)
-        AA = A(:,len+1:nc);
-        match &= all (AA == " " | AA == "\0", 2);
-      endif
-      idx = find (match);
-    endif
-  else
-    if (len > 0)
-      idx = find (strncmp (s, A, len));
-    else
-      idx = find (strcmp (s, A));
-    endif
-    if (exact)
-      ## We can't just use strcmp, because we need to ignore spaces at end.
-      B = regexprep (A(idx), "[ \\0]+$", '');
-      idx = idx(strcmp (s, B));
-    endif
-  endif
-
-endfunction
-
-
-%!assert (strmatch ("a", {"aaa", "bab", "bbb"}), 1)
-%!assert (strmatch ("apple", "apple juice"), 1)
-%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), [1; 2])
-%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), [1; 2])
-%!assert (strmatch ("apple pie", "apple"), [])
-%!assert (strmatch ("a ", "a"), 1)
-%!assert (strmatch ("a", "a \0", "exact"), 1)
-%!assert (strmatch ("a b", {"a b", "a c", "c d"}), 1)
-%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4])
-%!assert (strmatch ('', { '', '% comment', 'var a = 5', ''}, "exact"), [1,4])
-
-## Weird Matlab corner cases
-%!test <*49601>
-%! assert (strmatch (" ", " "), 1);
-%! assert (strmatch (" ", "   "), 1);
-%! assert (strmatch ("  ", " "), []);
-%! assert (strmatch ("  ", "  "), 1);
-
-## 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 <S must be a string> strmatch (1, "aaa")
-%!error <S must be a string> strmatch (char ("a", "bb"), "aaa")
-%!error <A must be a string> strmatch ("a", 1)
-%!error <A must be a string> strmatch ("a", {"hello", [1]})
--- a/scripts/strings/strsplit.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/strings/strsplit.m	Thu Dec 20 17:18:56 2018 -0500
@@ -177,6 +177,8 @@
 
   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")
   elseif (! isscalar (args.collapsedelimiters))
     error ("strsplit: COLLAPSEDELIMITERS must be a scalar value");
   endif
@@ -307,5 +309,7 @@
 %!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")
+%!error <S must be a char row vector> strsplit (["abc"; "xyz"])
+%!error <S must be a char row vector> strsplit (reshape ("axbycz", [1 3 2]))
 %!error <COLLAPSEDELIMITERS must be a scalar value> strsplit ("abc", "def", "collapsedelimiters", ones (3,3))
 %!error <Invalid DELIMITERTYPE> strsplit ("abc", "b", "delimitertype", "foobar")
--- a/scripts/testfun/__run_test_suite__.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/__run_test_suite__.m	Thu Dec 20 17:18:56 2018 -0500
@@ -51,6 +51,7 @@
     page_screen_output (false);
     warning ("on", "quiet");
     warning ("off", "Octave:deprecated-function");
+    warning ("off", "Octave:legacy-function");
     nfail = dp = dn = dxf = dxb = dsk = drtsk = drgrs = 0;
     try
       fid = fopen (logfile, "wt");
@@ -60,7 +61,7 @@
       test ("", "explain", fid);
       puts ("\nIntegrated test scripts:\n\n");
       for i = 1:length (fcndirs)
-        [p, n, xf, xb, sk, rtsk, rgrs] = run_test_script (fid, fcndirs{i});
+        [p, n, xf, xb, sk, rtsk, rgrs] = run_test_dir (fid, fcndirs{i});
         dp += p;
         dn += n;
         dxf += xf;
@@ -116,10 +117,10 @@
         puts ("indicating which dependencies were not found.\n");
       endif
 
-      ## Weed out deprecated and private functions
-      weed_idx = cellfun (@isempty, regexp (files_with_tests, '\<deprecated\>|\<private\>', 'once'));
+      ## Weed out deprecated, legacy, and private functions
+      weed_idx = cellfun (@isempty, regexp (files_with_tests, '\<deprecated\>|\<legacy\>|\<private\>', 'once'));
       files_with_tests = files_with_tests(weed_idx);
-      weed_idx = cellfun (@isempty, regexp (files_with_no_tests, '\<deprecated\>|\<private\>', 'once'));
+      weed_idx = cellfun (@isempty, regexp (files_with_no_tests, '\<deprecated\>|\<legacy\>|\<private\>', 'once'));
       files_with_no_tests = files_with_no_tests(weed_idx);
 
       report_files_with_no_tests (files_with_tests, files_with_no_tests, ".m");
@@ -149,15 +150,13 @@
     regress = drgrs;
   endif
 
-
   function [dp, dn, dxf, dxb, dsk, drtsk, drgrs] = run_test_dir (fid, d)
 
     lst = dir (d);
     dp = dn = dxf = dxb = dsk = drtsk = drgrs = 0;
     for i = 1:length (lst)
       nm = lst(i).name;
-      if (lst(i).isdir
-          && nm(1) != "." && ! strcmp (nm, "private") && nm(1) != "@")
+      if (lst(i).isdir && nm(1) != "." && ! strcmp (nm, "private"))
         [p, n, xf, xb, sk, rtsk, rgrs] = run_test_dir (fid, [d, filesep, nm]);
         dp += p;
         dn += n;
@@ -171,27 +170,41 @@
 
     saved_dir = pwd ();
     unwind_protect
-      cd (d);
+      [dnm, fnm] = fileparts (d);
+      if (fnm(1) != "@")
+        cd (d);
+      endif
       for i = 1:length (lst)
         nm = lst(i).name;
-        if (length (nm) > 4 && strcmpi (nm((end-3):end), ".tst"))
-          p = n = xf = xb = sk = rtsk = 0;
+        ## Ignore hidden files
+        if (nm(1) == '.')
+          continue
+        endif
+        if ((length (nm) > 2 && strcmpi (nm((end-1):end), ".m"))
+            || (length (nm) > 4
+                && (strcmpi (nm((end-3):end), "-tst")
+                    || strcmpi (nm((end-3):end), ".tst"))))
+          p = n = xf = xb = sk = rtsk = rgrs = 0;
           ffnm = fullfile (d, nm);
+          ## Only run if contains %!test, %!assert, %!error, %!fail, or %!warning
           if (has_tests (ffnm))
-            print_test_file_name (nm);
-            [p, n, xf, xb, sk, rtsk, rgrs] = test (nm, "quiet", fid);
+            tmp = reduce_test_file_name (ffnm, topbuilddir, topsrcdir);
+            print_test_file_name (tmp);
+            [p, n, xf, xb, sk, rtsk, rgrs] = test (ffnm, "quiet", fid);
             print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs);
+            dp += p;
+            dn += n;
+            dxf += xf;
+            dxb += xb;
+            dsk += sk;
+            drtsk += rtsk;
+            drgrs += rgrs;
             files_with_tests(end+1) = ffnm;
           else
+            ## To reduce the list length, only mark .cc files that contain
+            ## DEFUN definitions.
             files_with_no_tests(end+1) = ffnm;
           endif
-          dp += p;
-          dn += n;
-          dxf += xf;
-          dxb += xb;
-          dsk += sk;
-          drtsk += rtsk;
-          drgrs += rgrs;
         endif
       endfor
     unwind_protect_cleanup
@@ -200,90 +213,39 @@
 
   endfunction
 
-  function [dp, dn, dxf, dxb, dsk, drtsk, drgrs] = run_test_script (fid, d)
-
-    lst = dir (d);
-    dp = dn = dxf = dxb = dsk = drtsk = drgrs = 0;
-    for i = 1:length (lst)
-      nm = lst(i).name;
-      if (lst(i).isdir && nm(1) != ".")
-        [p, n, xf, xb, sk, rtsk, rgrs] = run_test_script (fid, [d, filesep, nm]);
-        dp += p;
-        dn += n;
-        dxf += xf;
-        dxb += xb;
-        dsk += sk;
-        drtsk += rtsk;
-        drgrs += rgrs;
-      endif
-    endfor
-
-    for i = 1:length (lst)
-      nm = lst(i).name;
-      ## Ignore hidden files
-      if (nm(1) == '.')
-        continue
-      endif
-      f = fullfile (d, nm);
-      if ((length (nm) > 2 && strcmpi (nm((end-1):end), ".m"))
-          || (length (nm) > 4
-              && (   strcmpi (nm((end-3):end), "-tst")
-                  || strcmpi (nm((end-3):end), ".tst"))))
-        p = n = xf = xb = 0;
-        ## Only run if contains %!test, %!assert, %!error, %!fail, or %!warning
-        if (has_tests (f))
-          tmp = reduce_test_file_name (f, topbuilddir, topsrcdir);
-          print_test_file_name (tmp);
-          [p, n, xf, xb, sk, rtsk, rgrs] = test (f, "quiet", fid);
-          print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs);
-          dp += p;
-          dn += n;
-          dxf += xf;
-          dxb += xb;
-          dsk += sk;
-          drtsk += rtsk;
-          drgrs += rgrs;
-          files_with_tests(end+1) = f;
-        else
-          ## To reduce the list length, only mark .cc files that contain
-          ## DEFUN definitions.
-          files_with_no_tests(end+1) = f;
-        endif
-      endif
-    endfor
-    ##  printf("%s%s -> passes %d of %d tests\n", ident, d, dp, dn);
-
-  endfunction
-
 endfunction
 
 function print_test_file_name (nm)
-  filler = repmat (".", 1, 60-length (nm));
+  nmlen = numel (nm);
+  filler = repmat (".", 1, 63-nmlen);
+  if (nmlen > 63)
+    nm = ["..", nm(nmlen-60:end)];
+  endif
   printf ("  %s %s", nm, filler);
 endfunction
 
 function print_pass_fail (p, n, xf, xb, sk, rtsk, rgrs)
 
   if ((n + sk + rtsk + rgrs) > 0)
-    printf (" PASS   %4d/%-4d", p, n);
+    printf (" PASS %4d/%-4d", p, n);
     nfail = n - p - xf - xb - rgrs;
     if (nfail > 0)
-      printf ("\n%71s %3d", "FAIL ", nfail);
+      printf ("\n%72s %3d", "FAIL ", nfail);
     endif
     if (rgrs > 0)
-      printf ("\n%71s %3d", "REGRESSION", rgrs);
+      printf ("\n%72s %3d", "REGRESSION", rgrs);
     endif
     if (sk > 0)
-      printf ("\n%71s %3d", "(missing feature) SKIP ", sk);
+      printf ("\n%72s %3d", "(missing feature) SKIP ", sk);
     endif
     if (rtsk > 0)
-      printf ("\n%71s %3d", "(run-time condition) SKIP ", rtsk);
+      printf ("\n%72s %3d", "(run-time condition) SKIP ", rtsk);
     endif
     if (xb > 0)
-      printf ("\n%71s %3d", "(reported bug) XFAIL", xb);
+      printf ("\n%72s %3d", "(reported bug) XFAIL", xb);
     endif
     if (xf > 0)
-      printf ("\n%71s %3d", "(expected failure) XFAIL", xf);
+      printf ("\n%72s %3d", "(expected failure) XFAIL", xf);
     endif
   endif
   puts ("\n");
@@ -296,11 +258,12 @@
   ## of the likely root directory prefixes.
 
   prefix = { builddir, fullfile(builddir, "scripts"), ...
-             srcdir, fullfile(srcdir, "scripts") };
+             srcdir, fullfile(srcdir, "scripts"), ...
+             srcdir, fullfile(srcdir, "test") };
 
   retval = nm;
 
-  for i = 1:length (prefix)
+  for i = 1:numel (prefix)
     tmp = strrep (nm, [prefix{i}, filesep], "");
     if (length (tmp) < length (retval))
       retval = tmp;
--- a/scripts/testfun/assert.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/assert.m	Thu Dec 20 17:18:56 2018 -0500
@@ -88,7 +88,7 @@
           || isempty (cond) || ! all (cond(:)))
         if (nargin == 1)
           ## Perhaps, say which elements failed?
-          argin = ["(" strjoin(cellstr (argn), ",") ")"];
+          argin = ["(" inputname(1, false) ")"];
           error ("assert %s failed", argin);
         else
           error (varargin{:});
@@ -401,7 +401,11 @@
 
       ## Print any errors
       if (! isempty (err.index))
-        argin = ["(" strjoin(cellstr (argn), ",") ")"];
+        arg_names = cell (nargin, 1);
+        for i = 1:nargin
+          arg_names{i} = inputname (i, false);
+        endfor
+        argin = ["(" strjoin(arg_names, ",") ")"];
         if (! isempty (errmsg))
           errmsg = [errmsg "\n"];
         endif
--- a/scripts/testfun/private/compare_plot_demos.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/private/compare_plot_demos.m	Thu Dec 20 17:18:56 2018 -0500
@@ -86,7 +86,7 @@
   unwind_protect
     addpath (pwd);
     for n = 1:numel (arg.toolkits)
-      if (! isdir (fullfile (cwd, arg.toolkits{n})))
+      if (! isfolder (fullfile (cwd, arg.toolkits{n})))
         mkdir (arg.toolkits{n});
       endif
       cd (arg.toolkits{n});
--- a/scripts/testfun/private/dump_demos.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/private/dump_demos.m	Thu Dec 20 17:18:56 2018 -0500
@@ -93,7 +93,7 @@
     if (! is_absolute_filename (d))
       d = dir_in_loadpath (d);
     endif
-    if (! exist (d, "dir"))
+    if (! isfolder (d))
       error ("dump_demos: directory %s does not exist", d);
     endif
     dump_all_demos (d, fid, fmt);
--- a/scripts/testfun/private/html_compare_plot_demos.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/private/html_compare_plot_demos.m	Thu Dec 20 17:18:56 2018 -0500
@@ -80,7 +80,7 @@
   fclose (fid);
 
   anchor = "<!-- ##ADD TABLE HERE## -->";
-  n = findstr (template, anchor);
+  n = strfind (template, anchor);
   header = strtrim (template(1:n-1));
   trailer = strtrim (template(n+numel(anchor):end));
 
--- a/scripts/testfun/rundemos.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/rundemos.m	Thu Dec 20 17:18:56 2018 -0500
@@ -38,7 +38,7 @@
     do_class_dirs = true;
   elseif (nargin == 1)
     dirs = {canonicalize_file_name(directory)};
-    if (isempty (dirs{1}) || ! isdir (dirs{1}))
+    if (isempty (dirs{1}) || ! isfolder (dirs{1}))
       ## Search for directory name in path
       if (directory(end) == '/' || directory(end) == '\')
         directory(end) = [];
@@ -82,7 +82,7 @@
       endif
     elseif (f(1) == "@")
       f = fullfile (directory, f);
-      if (isdir (f))
+      if (isfolder (f))
         dirs(end+1) = f;
       endif
     endif
--- a/scripts/testfun/runtests.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/runtests.m	Thu Dec 20 17:18:56 2018 -0500
@@ -38,7 +38,7 @@
     do_class_dirs = true;
   elseif (nargin == 1)
     dirs = {canonicalize_file_name(directory)};
-    if (isempty (dirs{1}) || ! isdir (dirs{1}))
+    if (isempty (dirs{1}) || ! isfolder (dirs{1}))
       ## Search for directory name in path
       if (directory(end) == '/' || directory(end) == '\')
         directory(end) = [];
@@ -83,7 +83,7 @@
       endif
     elseif (f(1) == "@")
       f = fullfile (directory, f);
-      if (isdir (f))
+      if (isfolder (f))
         dirs(end+1) = f;
       endif
     endif
--- a/scripts/testfun/speed.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/speed.m	Thu Dec 20 17:18:56 2018 -0500
@@ -288,8 +288,8 @@
   elseif (do_display)
 
     subplot (1, 2, 1);
-    semilogx (__test_n, __tnew./__torig, "-*g",
-              __test_n, __torig./__tnew, "-*r");
+    semilogx (__test_n, __tnew ./ __torig, "-*g",
+              __test_n, __torig ./ __tnew, "-*r");
     legend ({[strrep(__f1, ";", ".") " / " strrep(__f2, ";", ".")],
              [strrep(__f2, ";", ".") " / " strrep(__f1, ";", ".")]},
             "location", "northwest");
--- a/scripts/testfun/test.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/testfun/test.m	Thu Dec 20 17:18:56 2018 -0500
@@ -293,6 +293,17 @@
     disp ([__signal_file, __file]);
   endif
 
+  ## Track file descriptor leaks
+  __fid_list_orig = fopen ("all");
+
+  ## Track variable leaks
+  __base_variables_orig = evalin ("base", "who");
+  ## Add automatic variable "ans" which may not have been created yet.
+  __base_variables_orig{end+1} = "ans";
+
+  ## Track variable leaks
+  __global_variables_orig = who ("global");
+
   ## Assume all tests will pass.
   __all_success = true;
 
@@ -729,9 +740,28 @@
     end_unwind_protect
   endfor
 
-  ## Clear any functions created during test run
+  ## Clear any functions created during test run.
   eval (__clearfcn, "");
 
+  ## Verify test file did not leak file descriptors.
+  if (! isempty (setdiff (fopen ("all"), __fid_list_orig)))
+    warning ("test: file %s leaked file descriptors\n", __file);
+  endif
+
+  ## Verify test file did not leak variables in to base workspace.
+  __leaked_vars = setdiff (evalin ("base", "who"), __base_variables_orig);
+  if (! isempty (__leaked_vars))
+    warning ("test: file %s leaked variables to base workspace:%s\n",
+             __file, sprintf (" %s", __leaked_vars{:}));
+  endif
+
+  ## Verify test file did not leak global variables.
+  __leaked_vars = setdiff (who ("global"), __global_variables_orig);
+  if (! isempty (__leaked_vars))
+    warning ("test: file %s leaked global variables:%s\n",
+             __file, sprintf (" %s", __leaked_vars{:}));
+  endif
+
   if (nargout == 0)
     if (__tests || __xfail || __xbug || __xskip || __xrtskip)
       if (__xfail || __xbug)
@@ -785,7 +815,7 @@
 ## Create structure with fieldnames the name of the input variables.
 function s = var2struct (varargin)
   for i = 1:nargin
-    s.(deblank (argn(i,:))) = varargin{i};
+    s.(inputname (i, true)) = varargin{i};
   endfor
 endfunction
 
--- a/scripts/time/datestr.m	Tue Dec 04 10:12:41 2018 -0800
+++ b/scripts/time/datestr.m	Thu Dec 20 17:18:56 2018 -0500
@@ -23,9 +23,9 @@
 ## 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}) or a date vector
-## (see @code{datevec}).  The value of @var{date} may also be a string or cell
-## array of strings.
+## @var{date} is a serial date number (see @code{datenum}), a date vector (see
+## @code{datevec}), or a 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.
--- a/src/main-cli.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/src/main-cli.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,7 +36,6 @@
 #include "oct-env.h"
 #include "signal-wrappers.h"
 
-#include "defaults.h"
 #include "octave.h"
 #include "octave-build-info.h"
 #include "sysdep.h"
--- a/src/main-gui.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/src/main-gui.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -37,7 +37,6 @@
 
 #include "oct-env.h"
 
-#include "defaults.h"
 #include "octave.h"
 #include "octave-build-info.h"
 #include "octave-gui.h"
--- a/src/mkoctfile.in.cc	Tue Dec 04 10:12:41 2018 -0800
+++ b/src/mkoctfile.in.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -36,15 +36,27 @@
 #include <vector>
 #include <cstdlib>
 
+// 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
+// itself is being cross compiled.
+//
+// We don't use the wrapper and gnulib functions when we are building
+// with CROSS defined.  This configuration is only expected to work on
+// modern systems that should not need to have gnulib to fix POSIX
+// portability problems.  So we just assume a working POSIX system when
+// CROSS is defined.
+
 #if defined (CROSS)
+#  include <stdlib.h>
 #  include <sys/types.h>
 #  include <sys/wait.h>
 #  include <unistd.h>
-
 #  ifndef OCTAVE_UNUSED
 #    define OCTAVE_UNUSED
 #  endif
 #else
+#  include "mkostemps-wrapper.h"
 #  include "unistd-wrappers.h"
 #  include "wait-wrappers.h"
 #endif
@@ -68,6 +80,12 @@
 #if defined (CROSS)
 
 static int
+octave_mkostemps_wrapper (char *tmpl, int suffixlen)
+{
+  return mkostemps (tmpl, suffixlen, 0);
+}
+
+static int
 octave_unlink_wrapper (const char *nm)
 {
   return unlink (nm);
@@ -133,7 +151,39 @@
   vars["OCTAVE_HOME"] = Voctave_home;
   vars["OCTAVE_EXEC_HOME"] = Voctave_exec_home;
 
-  vars["SED"] = get_variable ("SED", %OCTAVE_CONF_SED%);
+  vars["API_VERSION"] = %OCTAVE_API_VERSION%;
+  vars["CANONICAL_HOST_TYPE"] = %OCTAVE_CANONICAL_HOST_TYPE%;
+  vars["DEFAULT_PAGER"] = %OCTAVE_DEFAULT_PAGER%;
+  vars["EXEEXT"] = %OCTAVE_EXEEXT%;
+  vars["MAN1EXT"] = %OCTAVE_MAN1EXT%;
+  vars["VERSION"] = %OCTAVE_VERSION%;
+
+  vars["ARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_ARCHLIBDIR%);
+  vars["BINDIR"] = prepend_octave_exec_home (%OCTAVE_BINDIR%);
+  vars["DATADIR"] = prepend_octave_home (%OCTAVE_DATADIR%);
+  vars["DATAROOTDIR"] = prepend_octave_home (%OCTAVE_DATAROOTDIR%);
+  vars["FCNFILEDIR"] = prepend_octave_home (%OCTAVE_FCNFILEDIR%);
+  vars["IMAGEDIR"] = prepend_octave_home (%OCTAVE_IMAGEDIR%);
+  vars["INFODIR"] = prepend_octave_home (%OCTAVE_INFODIR%);
+  vars["INFOFILE"] = prepend_octave_home (%OCTAVE_INFOFILE%);
+  vars["LIBEXECDIR"] = prepend_octave_exec_home (%OCTAVE_LIBEXECDIR%);
+  vars["LOCALAPIARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALAPIARCHLIBDIR%);
+  vars["LOCALAPIFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALAPIFCNFILEDIR%);
+  vars["LOCALAPIOCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALAPIOCTFILEDIR%);
+  vars["LOCALARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALARCHLIBDIR%);
+  vars["LOCALFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALFCNFILEDIR%);
+  vars["LOCALOCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALOCTFILEDIR%);
+  vars["LOCALSTARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALSTARTUPFILEDIR%);
+  vars["LOCALVERARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALVERARCHLIBDIR%);
+  vars["LOCALVERFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALVERFCNFILEDIR%);
+  vars["LOCALVEROCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALVEROCTFILEDIR%);
+  vars["MAN1DIR"] = prepend_octave_home (%OCTAVE_MAN1DIR%);
+  vars["MANDIR"] = prepend_octave_home (%OCTAVE_MANDIR%);
+  vars["OCTDATADIR"] = prepend_octave_home (%OCTAVE_OCTDATADIR%);
+  vars["OCTDOCDIR"] = prepend_octave_home (%OCTAVE_OCTDOCDIR%);
+  vars["OCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_OCTFILEDIR%);
+  vars["OCTFONTSDIR"] = prepend_octave_home (%OCTAVE_OCTFONTSDIR%);
+  vars["STARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_STARTUPFILEDIR%);
 
   vars["OCTINCLUDEDIR"]
     = get_variable ("OCTINCLUDEDIR",
@@ -162,7 +212,15 @@
   if (vars["INCLUDEDIR"] != "/usr/include")
     DEFAULT_INCFLAGS += " -I" + quote_path (vars["INCLUDEDIR"]);
 
-  std::string DEFAULT_LFLAGS = "-L" + quote_path (vars["OCTLIBDIR"]);
+  std::string DEFAULT_LFLAGS;
+
+#if defined (OCTAVE_USE_WINDOWS_API) || defined (CROSS)
+
+  // We'll be linking the files we compile with -loctinterp and
+  // -loctave, so we need to know where to find them.
+
+  DEFAULT_LFLAGS += "-L" + quote_path (vars["OCTLIBDIR"]);
+#endif
 
   if (vars["LIBDIR"] != "/usr/lib")
     DEFAULT_LFLAGS += " -L" + quote_path (vars["LIBDIR"]);
@@ -322,36 +380,80 @@
 "\n"
 "  -g                      Enable debugging options for compilers.\n"
 "\n"
-"  -p VAR, --print VAR     Print configuration variable VAR.  Recognized\n"
-"                          variables are:\n"
+"  -p VAR, --print VAR     Print configuration variable VAR.  There are\n"
+"                          three categories of variables:\n"
+"\n"
+"                          Octave configuration variables that users may\n"
+"                          override with environment variables.  These are\n"
+"                          used in commands that mkoctfile executes.\n"
+"\n"
+"                            ALL_CFLAGS                  LAPACK_LIBS\n"
+"                            ALL_CXXFLAGS                LDFLAGS\n"
+"                            ALL_FFLAGS                  LD_CXX\n"
+"                            ALL_LDFLAGS                 LD_STATIC_FLAG\n"
+"                            BLAS_LIBS                   LFLAGS\n"
+"                            CC                          LIBDIR\n"
+"                            CFLAGS                      LIBOCTAVE\n"
+"                            CPICFLAG                    LIBOCTINTERP\n"
+"                            CPPFLAGS                    OCTAVE_LINK_OPTS\n"
+"                            CXX                         OCTINCLUDEDIR\n"
+"                            CXXFLAGS                    OCTAVE_LIBS\n"
+"                            CXXPICFLAG                  OCTAVE_LINK_DEPS\n"
+"                            DL_LD                       OCTLIBDIR\n"
+"                            DL_LDFLAGS                  OCT_LINK_DEPS\n"
+"                            F77                         OCT_LINK_OPTS\n"
+"                            F77_INTEGER8_FLAG           RDYNAMIC_FLAG\n"
+"                            FFLAGS                      SPECIAL_MATH_LIB\n"
+"                            FPICFLAG                    XTRA_CFLAGS\n"
+"                            INCFLAGS                    XTRA_CXXFLAGS\n"
+"                            INCLUDEDIR\n"
+"\n"
+"                          Octave configuration variables as above, but\n"
+"                          currently unused by mkoctfile.\n"
 "\n"
-"                            ALL_CFLAGS                  INCFLAGS\n"
-"                            ALL_CXXFLAGS                INCLUDEDIR\n"
-"                            ALL_FFLAGS                  LAPACK_LIBS\n"
-"                            ALL_LDFLAGS                 LD_CXX\n"
-"                            AR                          LDFLAGS\n"
-"                            BLAS_LIBS                   LD_STATIC_FLAG\n"
-"                            CC                          LFLAGS\n"
-"                            CFLAGS                      LIBDIR\n"
-"                            CPICFLAG                    LIBOCTAVE\n"
-"                            CPPFLAGS                    LIBOCTINTERP\n"
-"                            CXX                         LIBS\n"
-"                            CXXFLAGS                    OCTAVE_EXEC_HOME\n"
-"                            CXXPICFLAG                  OCTAVE_HOME\n"
-"                            DEPEND_EXTRA_SED_PATTERN    OCTAVE_LIBS\n"
-"                            DEPEND_FLAGS                OCTAVE_LINK_DEPS\n"
-"                            DL_LD                       OCTAVE_LINK_OPTS\n"
-"                            DL_LDFLAGS                  OCTINCLUDEDIR\n"
-"                            F77                         OCTLIBDIR\n"
-"                            F77_INTEGER8_FLAG           OCT_LINK_DEPS\n"
-"                            FFLAGS                      OCT_LINK_OPTS\n"
-"                            FFTW3F_LDFLAGS              RANLIB\n"
-"                            FFTW3F_LIBS                 RDYNAMIC_FLAG\n"
-"                            FFTW3_LDFLAGS               READLINE_LIBS\n"
-"                            FFTW3_LIBS                  SED\n"
-"                            FFTW_LIBS                   SPECIAL_MATH_LIB\n"
-"                            FLIBS                       XTRA_CFLAGS\n"
-"                            FPICFLAG                    XTRA_CXXFLAGS\n"
+"                            AR\n"
+"                            DEPEND_EXTRA_SED_PATTERN\n"
+"                            DEPEND_FLAGS\n"
+"                            FFTW3F_LDFLAGS\n"
+"                            FFTW3F_LIBS\n"
+"                            FFTW3_LDFLAGS\n"
+"                            FFTW3_LIBS\n"
+"                            FFTW_LIBS\n"
+"                            FLIBS\n"
+"                            LIBS\n"
+"                            RANLIB\n"
+"                            READLINE_LIBS\n"
+"\n"
+"                          Octave configuration variables that are provided\n"
+"                          for informational purposes only.  Except for\n"
+"                          OCTAVE_HOME and OCTAVE_EXEC_HOME, users may not\n"
+"                          override these variables.\n"
+"\n"
+"                          If OCTAVE_HOME or OCTAVE_EXEC_HOME are set in\n"
+"                          the environment, then other variables are adjusted\n"
+"                          accordingly with OCTAVE_HOME or OCTAVE_EXEC_HOME\n"
+"                          substituted for the original value of the directory\n"
+"                          specified by the --prefix or --exec-prefix options\n"
+"                          that were used when Octave was configured.\n"
+"\n"
+"                            API_VERSION                 LOCALFCNFILEDIR\n"
+"                            ARCHLIBDIR                  LOCALOCTFILEDIR\n"
+"                            BINDIR                      LOCALSTARTUPFILEDIR\n"
+"                            CANONICAL_HOST_TYPE         LOCALVERARCHLIBDIR\n"
+"                            DATADIR                     LOCALVERFCNFILEDIR\n"
+"                            DATAROOTDIR                 LOCALVEROCTFILEDIR\n"
+"                            DEFAULT_PAGER               MAN1DIR\n"
+"                            EXEC_PREFIX                 MAN1EXT\n"
+"                            EXEEXT                      MANDIR\n"
+"                            FCNFILEDIR                  OCTAVE_EXEC_HOME\n"
+"                            IMAGEDIR                    OCTAVE_HOME\n"
+"                            INFODIR                     OCTDATADIR\n"
+"                            INFOFILE                    OCTDOCDIR\n"
+"                            LIBEXECDIR                  OCTFILEDIR\n"
+"                            LOCALAPIARCHLIBDIR          OCTFONTSDIR\n"
+"                            LOCALAPIFCNFILEDIR          STARTUPFILEDIR\n"
+"                            LOCALAPIOCTFILEDIR          VERSION\n"
+"                            LOCALARCHLIBDIR\n"
 "\n"
 "  --link-stand-alone      Link a stand-alone executable file.\n"
 "\n"
@@ -451,6 +553,78 @@
   return (s == "yes" || s == "true");
 }
 
+static std::string
+do_getenv (const std::string& name)
+{
+  char *value = ::getenv (name.c_str ());
+
+  return value ? value : "";
+}
+
+static std::string
+get_temp_directory (void)
+{
+  std::string tempd;
+
+#if defined (__MINGW32__) || defined (_MSC_VER)
+
+  tempd = do_getenv ("TEMP");
+
+  if (tempd.empty ())
+    tempd = do_getenv ("TMP");
+
+#if defined (P_tmpdir)
+  if (tempd.empty ())
+    tempd = P_tmpdir;
+#endif
+
+  // Some versions of MinGW and MSVC either don't define P_tmpdir, or
+  // define it to a single backslash.  In such cases just use C:\temp.
+  if (tempd.empty () || tempd == R"(\)")
+    tempd = R"(c:\temp)";
+
+#else
+
+  tempd = do_getenv ("TMP");
+
+#if defined (P_tmpdir)
+  if (tempd.empty ())
+    tempd = P_tmpdir;
+#else
+  if (tempd.empty ())
+    tempd = "/tmp";
+#endif
+
+#endif
+
+  return tempd;
+}
+
+static std::string
+tmp_objfile_name (void)
+{
+  std::string tmpl = get_temp_directory () + "/oct-XXXXXX.o";
+
+  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.
+
+  octave_mkostemps_wrapper (ctmpl, 2);
+
+  return std::string (ctmpl);
+}
+
+static void
+clean_up_tmp_files (const std::list<std::string>& tmp_files)
+{
+  for (const auto& file : tmp_files)
+    octave_unlink_wrapper (file.c_str ());
+}
+
 int
 main (int argc, char **argv)
 {
@@ -470,16 +644,17 @@
       return 0;
     }
 
-  std::list<std::string> cfiles, ccfiles, f77files;
+  std::list<std::string> cfiles, ccfiles, f77files, tmp_objfiles;
   std::string output_ext = ".oct";
   std::string objfiles, libfiles, octfile, outputfile;
   std::string incflags, defs, ldflags, pass_on_options;
   bool strip = false;
   bool no_oct_file_strip_on_this_platform = is_true ("%NO_OCT_FILE_STRIP%");
-  bool link = true;
+  bool compile_only = false;
   bool link_stand_alone = false;
   bool depend = false;
   bool printonly = false;
+  bool output_file_option = false;
 
   for (int i = 1; i < argc; i++)
     {
@@ -573,6 +748,8 @@
         }
       else if (arg == "-o" || arg == "-output" || arg == "--output")
         {
+          output_file_option = true;
+
           if (i < argc-1)
             {
               arg = argv[++i];
@@ -606,7 +783,7 @@
         }
       else if (arg == "-c" || arg == "-compile" || arg == "--compile")
         {
-          link = false;
+          compile_only = true;
         }
       else if (arg == "-g")
         {
@@ -666,6 +843,14 @@
       defs += " -DMEX_DEBUG";
     }
 
+  if (compile_only && output_file_option
+      && (cfiles.size () + ccfiles.size () + f77files.size ()) > 1)
+    {
+      std::cerr << "mkoctfile: may not use -c and -o with multiple source files"
+                << std::endl;
+      return 1;
+    }
+
   std::string output_option;
 
   if (link_stand_alone)
@@ -677,10 +862,14 @@
     {
       if (! outputfile.empty ())
         {
+          // FIXME: should probably do a better job of finding the
+          // filename extension instead of just looking at the filename
+          // length.
+
           octfile = outputfile;
           size_t len = octfile.length ();
           size_t len_ext = output_ext.length ();
-          if (octfile.substr (len-len_ext) != output_ext)
+          if (len <= len_ext || octfile.substr (len-len_ext) != output_ext)
             octfile += output_ext;
         }
       else
@@ -762,21 +951,24 @@
 
   for (const auto& f : f77files)
     {
-      std::string b = basename (f, true);
-
       if (! vars["F77"].empty ())
         {
           std::string o;
-          if (! outputfile.empty ())
+          if (compile_only)
             {
-              if (link)
-                o = b + ".o";
+              if (! outputfile.empty ())
+                o = outputfile;
               else
-                o = outputfile;
+                o = basename (f, true) + ".o";
             }
           else
-            o = b + ".o";
-          objfiles += (' ' + o);
+            {
+              o = tmp_objfile_name ();
+
+              tmp_objfiles.push_back (o);
+
+              objfiles += (' ' + o);
+            }
 
           std::string cmd
             = (vars["F77"] + " -c " + vars["FPICFLAG"] + ' '
@@ -800,17 +992,22 @@
     {
       if (! vars["CC"].empty ())
         {
-          std::string b = basename (f, true), o;
-          if (! outputfile.empty ())
+          std::string o;
+          if (compile_only)
             {
-              if (link)
-                o = b + ".o";
+              if (! outputfile.empty ())
+                o = outputfile;
               else
-                o = outputfile;
+                o = basename (f, true) + ".o";
             }
           else
-            o = b + ".o";
-          objfiles += (' ' + o);
+            {
+              o = tmp_objfile_name ();
+
+              tmp_objfiles.push_back (o);
+
+              objfiles += (' ' + o);
+            }
 
           std::string cmd
             = (vars["CC"] + " -c " + vars["CPPFLAGS"] + ' '
@@ -835,17 +1032,22 @@
     {
       if (! vars["CXX"].empty ())
         {
-          std::string b = basename (f, true), o;
-          if (! outputfile.empty ())
+          std::string o;
+          if (compile_only)
             {
-              if (link)
-                o = b + ".o";
+              if (! outputfile.empty ())
+                o = outputfile;
               else
-                o = outputfile;
+                o = basename (f, true) + ".o";
             }
           else
-            o = b + ".o";
-          objfiles += (' ' + o);
+            {
+              o = tmp_objfile_name ();
+
+              tmp_objfiles.push_back (o);
+
+              objfiles += (' ' + o);
+            }
 
           std::string cmd
             = (vars["CXX"] + " -c " + vars["CPPFLAGS"] + ' '
@@ -866,57 +1068,74 @@
         }
     }
 
-  if (link && ! objfiles.empty ())
-    {
-      if (link_stand_alone)
-        {
-          if (! vars["LD_CXX"].empty ())
-            {
-              std::string cmd
-                = (vars["LD_CXX"] + ' ' + vars["CPPFLAGS"] + ' '
-                   + vars["ALL_CXXFLAGS"] + ' ' + vars["RDYNAMIC_FLAG"] + ' '
-                   + vars["ALL_LDFLAGS"] + ' ' + pass_on_options + ' '
-                   + output_option + ' ' + objfiles + ' ' + libfiles + ' '
-                   + ldflags + ' ' + vars["LFLAGS"] + " -loctinterp -loctave "
-                   + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]);
+  // If we are only compliling, we are done.
+
+  if (compile_only)
+    return 0;
 
-              int status = run_command (cmd, printonly);
+  if (objfiles.empty ())
+    {
+      std::cerr << "mkoctfile: no objects to link" << std::endl;
+      return 1;
+    }
 
-              if (status)
-                return status;
-            }
-          else
-            {
-              std::cerr
-                << "mkoctfile: no way to link stand-alone executable file"
-                << std::endl;
-              return 1;
-            }
-        }
-      else
+  std::string octave_libs;
+#if defined (OCTAVE_USE_WINDOWS_API) || defined(CROSS)
+  octave_libs = "-loctinterp -loctave";
+#endif
+
+  if (link_stand_alone)
+    {
+      if (! vars["LD_CXX"].empty ())
         {
           std::string cmd
-            = (vars["DL_LD"] + ' ' + vars["ALL_CXXFLAGS"] + ' '
-               + vars["DL_LDFLAGS"] + ' ' + pass_on_options
-               + " -o " + octfile + ' ' + objfiles + ' ' + libfiles + ' '
-               + ldflags + ' ' + vars["LFLAGS"] + " -loctinterp -loctave "
-               + vars["OCT_LINK_OPTS"] + ' ' + vars["OCT_LINK_DEPS"]);
+            = (vars["LD_CXX"] + ' ' + vars["CPPFLAGS"] + ' '
+               + vars["ALL_CXXFLAGS"] + ' ' + vars["RDYNAMIC_FLAG"] + ' '
+               + vars["ALL_LDFLAGS"] + ' ' + pass_on_options + ' '
+               + output_option + ' ' + objfiles + ' ' + libfiles + ' '
+               + ldflags + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' '
+               + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]);
 
           int status = run_command (cmd, printonly);
 
+          clean_up_tmp_files (tmp_objfiles);
+
           if (status)
             return status;
         }
-
-      if (strip)
+      else
         {
-          std::string cmd = "strip " + octfile;
+          std::cerr
+            << "mkoctfile: no way to link stand-alone executable file"
+            << std::endl;
+          return 1;
+        }
+    }
+  else
+    {
+      std::string cmd
+        = (vars["DL_LD"] + ' ' + vars["ALL_CXXFLAGS"] + ' '
+           + vars["DL_LDFLAGS"] + ' ' + pass_on_options
+           + " -o " + octfile + ' ' + objfiles + ' ' + libfiles + ' '
+           + ldflags + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' '
+           + vars["OCT_LINK_OPTS"] + ' ' + vars["OCT_LINK_DEPS"]);
 
-          int status = run_command (cmd, printonly);
+      int status = run_command (cmd, printonly);
+
+      clean_up_tmp_files (tmp_objfiles);
+
+      if (status)
+        return status;
+    }
 
-          if (status)
-            return status;
-        }
+  if (strip)
+    {
+      std::string cmd = "strip " + octfile;
+
+      int status = run_command (cmd, printonly);
+
+      if (status)
+        return status;
     }
 
   return 0;
--- a/src/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/src/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -49,6 +49,11 @@
   OCTAVE_INTERPRETER_TARGETS += %reldir%/octave-gui$(EXEEXT)
 endif
 
+if AMCOND_BUILD_QT_GUI
+  archlib_PROGRAMS += %reldir%/octave-svgconvert
+  OCTAVE_INTERPRETER_TARGETS += %reldir%/octave-svgconvert$(EXEEXT)
+endif
+
 OCTAVE_CORE_LIBS = \
   libinterp/liboctinterp.la \
   liboctave/liboctave.la \
@@ -78,10 +83,6 @@
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
 
-%canon_reldir%_octave_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS)
-
 %canon_reldir%_octave_cli_SOURCES = %reldir%/main-cli.cc
 nodist_%canon_reldir%_octave_cli_SOURCES = %reldir%/octave-build-info.cc
 
@@ -98,10 +99,6 @@
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
 
-%canon_reldir%_octave_cli_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS)
-
 if AMCOND_BUILD_QT_GUI
   %canon_reldir%_octave_gui_SOURCES = %reldir%/main-gui.cc
   nodist_%canon_reldir%_octave_gui_SOURCES = %reldir%/octave-build-info.cc
@@ -123,9 +120,13 @@
   $(OCTAVE_GUI_LINK_OPTS) \
   $(WARN_LDFLAGS)
 
-%canon_reldir%_octave_gui_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS)
+%canon_reldir%_octave_svgconvert_SOURCES = %reldir%/octave-svgconvert.cc
+
+%canon_reldir%_octave_svgconvert_CPPFLAGS = $(QT_CPPFLAGS)
+
+%canon_reldir%_octave_svgconvert_LDADD = $(QT_LIBS)
+
+%canon_reldir%_octave_svgconvert_LDFLAGS = $(QT_LDFLAGS)
 
 %canon_reldir%_mkoctfile_SOURCES =
 
@@ -139,10 +140,6 @@
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
 
-%canon_reldir%_mkoctfile_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS)
-
 %canon_reldir%_octave_config_SOURCES =
 
 nodist_%canon_reldir%_octave_config_SOURCES = %reldir%/octave-config.cc
@@ -156,10 +153,6 @@
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
 
-%canon_reldir%_octave_config_CXXFLAGS = \
-  $(AM_CXXFLAGS) \
-  $(WARN_CXXFLAGS)
-
 DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
 
 mostlyclean-local: src-mostlyclean-local
@@ -184,8 +177,8 @@
 %reldir%/$(host_triplet)-octave-config$(BUILD_EXEEXT): %reldir%/$(host_triplet)-octave-config.cc
 	$(BUILD_CXX) -o %reldir%/$(host_triplet)-octave-config$(BUILD_EXEEXT) -DCROSS=1 $(DEFAULT_INCLUDES) $(BUILD_CXXFLAGS) $(BUILD_LDFLAGS) -I$(srcdir)/src %reldir%/$(host_triplet)-octave-config.cc
 
-%reldir%/$(host_triplet)-octave-config.cc: %reldir%/octave-config.in.cc build-aux/subst-default-vals.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-default-vals.sh)
+%reldir%/$(host_triplet)-octave-config.cc: %reldir%/octave-config.in.cc build-aux/subst-config-vals.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-config-vals.sh)
 
 src-mostlyclean-local:
 	-rm -f $(OCTAVE_CROSS_TOOLS)
@@ -196,14 +189,14 @@
 
 endif
 
-%reldir%/octave-config.cc: %reldir%/octave-config.in.cc build-aux/subst-default-vals.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-default-vals.sh)
+%reldir%/octave-config.cc: %reldir%/octave-config.in.cc build-aux/subst-config-vals.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-config-vals.sh)
 
 %reldir%/mkoctfile.cc: %reldir%/mkoctfile.in.cc build-aux/subst-config-vals.sh | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-config-vals.sh)
 
-%reldir%/main.cc: %reldir%/main.in.cc build-aux/subst-default-vals.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-default-vals.sh)
+%reldir%/main.cc: %reldir%/main.in.cc build-aux/subst-config-vals.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,build-aux/subst-config-vals.sh)
 
 %reldir%/octave-build-info.cc: %reldir%/octave-build-info.in.cc HG-ID | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)$(build-info-commands)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/octave-svgconvert.cc	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,854 @@
+/*
+Copyright (C) 2017 Pantxo Diribarne
+
+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
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+
+#include <QtCore>
+#include <QtXml>
+
+#include <QApplication>
+#include <QFontDatabase>
+#include <QImage>
+#include <QPainter>
+#include <QPrinter>
+#include <QRegExp>
+
+class pdfpainter : public QPainter
+{
+public:
+  pdfpainter (QString fname, QRectF sizepix, double dpi)
+    : m_fname (fname), m_sizef (sizepix), m_dpi (dpi), 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.setFullPage (true);
+    m_printer.setPaperSize (get_rectf ().size (), QPrinter::DevicePixel);
+
+    // Painter settings
+    begin (&m_printer);
+    setViewport (get_rect ());
+    scale (get_scale (), get_scale ());
+  }
+
+  ~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 (); }
+
+private:
+  QString m_fname;
+  QRectF m_sizef;
+  double m_dpi;
+  QPrinter m_printer;
+};
+
+// String conversion functions
+QVector<double> qstr2vectorf (QString str)
+{
+  QVector<double> pts;
+  QStringList coords = str.split (",");
+  for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 1)
+    {
+      double pt = (*p).toDouble ();
+      pts.append (pt);
+    }
+  return pts;
+}
+
+QVector<double> qstr2vectord (QString str)
+{
+  QVector<double> pts;
+  QStringList coords = str.split (",");
+  for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 1)
+    {
+      double pt = (*p).toDouble ();
+      pts.append (pt);
+    }
+
+  return pts;
+}
+
+QVector<QPointF> qstr2ptsvector (QString str)
+{
+  QVector<QPointF> pts;
+  str = str.trimmed ();
+  str.replace (" ", ",");
+  QStringList coords = str.split (",");
+  for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 2)
+    {
+      QPointF pt ((*p).toDouble (), (*(p+1)).toDouble ());
+      pts.append (pt);
+    }
+  return pts;
+}
+
+QVector<QPoint> qstr2ptsvectord (QString str)
+{
+  QVector<QPoint> pts;
+  str = str.trimmed ();
+  str.replace (" ", ",");
+  QStringList coords = str.split (",");
+  for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 2)
+    {
+      QPoint pt ((*p).toDouble (), (*(p+1)).toDouble ());
+      pts.append (pt);
+    }
+  return pts;
+}
+
+// Extract field arguments in a style-like string, e.g. "bla field(1,34,56) bla"
+QString get_field (QString str, QString field)
+{
+  QString retval;
+  QRegExp rx (field + "\\(([^\\)]*)\\)");
+  int pos = 0;
+  pos = rx.indexIn (str, pos);
+  if (pos > -1)
+    retval = rx.cap (1);
+
+  return retval;
+}
+
+// Polygon reconstruction class
+class octave_polygon
+{
+public:
+  octave_polygon (void)
+  { }
+
+  octave_polygon (QPolygonF p)
+  { m_polygons.push_back (p); }
+
+  ~octave_polygon (void) { }
+
+  int count (void) const
+  { return m_polygons.count (); }
+
+  void reset (void)
+  { m_polygons.clear (); }
+
+  QList<QPolygonF> reconstruct (void)
+  {
+    if (m_polygons.isEmpty ())
+      return QList<QPolygonF> ();
+
+    // Once a polygon has been merged to another, it is marked unsuded
+    QVector<bool> unused;
+    for (auto it = m_polygons.begin (); it != m_polygons.end (); it++)
+      unused.push_back (false);
+
+    bool tryagain = (m_polygons.count () > 1);
+
+    while (tryagain)
+      {
+        tryagain = false;
+        for (auto ii = 0; ii < m_polygons.count (); ii++)
+          {
+            if (! unused[ii])
+              {
+                QPolygonF polygon = m_polygons[ii];
+                for (auto jj = ii+1; jj < m_polygons.count (); jj++)
+                  {
+                    if (! unused[jj])
+                      {
+                        QPolygonF newpoly = mergepoly (polygon, m_polygons[jj]);
+                        if (newpoly.count ())
+                          {
+                            polygon = newpoly;
+                            m_polygons[ii] = newpoly;
+                            unused[jj] = true;
+                            tryagain = true;
+                          }
+                      }
+                  }
+              }
+          }
+      }
+
+    // Try to remove cracks in polygons
+    for (auto ii = 0; ii < m_polygons.count (); ii++)
+      {
+        QPolygonF polygon = m_polygons[ii];
+        tryagain = ! unused[ii];
+
+        while (tryagain && polygon.count () > 4)
+          {
+            tryagain = false;
+            QVector<int> del;
+
+            for (auto jj = 1; jj < (polygon.count () - 1); jj++)
+              if (polygon[jj-1] == polygon[jj+1])
+                {
+                  if (! del.contains (jj))
+                    del.push_front (jj);
+
+                  del.push_front (jj+1);
+                }
+
+            for (auto idx : del)
+              polygon.remove (idx);
+
+            if (del.count ())
+              tryagain = true;
+          }
+        m_polygons[ii] = polygon;
+      }
+
+    // FIXME: There may still be residual cracks, we should do something like
+    //   resetloop = 2;
+    //   while (resetloop)
+    //     currface = shift (currface, 1);
+    //     if (currface(1) == currface(3))
+    //       currface([2 3]) = [];
+    //       resetloop = 2;
+    //     else
+    //       resetloop--;
+    //     endif
+    //   endwhile
+
+    QList<QPolygonF> retval;
+    for (int ii = 0; ii < m_polygons.count (); ii++)
+      {
+        QPolygonF polygon = m_polygons[ii];
+        if (! unused[ii] && polygon.count () > 2)
+          retval.push_back (polygon);
+      }
+
+    return retval;
+  }
+
+  static inline
+  bool eq (QPointF p1, QPointF p2)
+  {
+    return ((qAbs (p1.x () - p2.x ()) <=
+             0.00001 * qMin (qAbs (p1.x ()), qAbs (p2.x ())))
+            && (qAbs (p1.y () - p2.y ()) <=
+                0.00001 * qMin (qAbs (p1.y ()), qAbs (p2.y ()))));
+  }
+
+  static
+  QPolygonF mergepoly (QPolygonF poly1, QPolygonF poly2)
+  {
+    // Close polygon contour
+    poly1.push_back (poly1[0]);
+    poly2.push_back (poly2[0]);
+
+    for (int ii = 0; ii < (poly1.size () - 1); ii++)
+      {
+        for (int jj = 0; jj < (poly2.size () - 1); jj++)
+          {
+            bool forward = (eq (poly1[ii], poly2[jj])
+                            && eq (poly1[ii+1], poly2[jj+1]));
+            bool backward = ! forward && (eq (poly1[ii], poly2[jj+1])
+                                          && eq (poly1[ii+1], poly2[jj]));
+
+            if (forward || backward)
+              {
+                // Unclose contour
+                poly1.pop_back ();
+                poly2.pop_back ();
+
+                QPolygonF merged;
+                for (int kk = 0; kk < (ii+1); kk++)
+                  merged.push_back (poly1[kk]);
+
+                // Shift vertices and eliminate the common edge
+                std::rotate (poly2.begin (), poly2.begin () + jj, poly2.end ());
+                poly2.erase (poly2.begin ());
+                poly2.erase (poly2.begin ());
+
+                if (forward)
+                  for (int kk = poly2.size (); kk > 0; kk--)
+                    merged.push_back (poly2[kk-1]);
+                else
+                  for (int kk = 0; kk < poly2.size (); kk++)
+                    merged.push_back (poly2[kk]);
+
+                for (int kk = ii+1; kk < poly1.size (); kk++)
+                  merged.push_back (poly1[kk]);
+
+                // Return row vector
+                QPolygonF out (merged.size ());
+                for (int kk = 0; kk < merged.size (); kk++)
+                  out[kk] = merged[kk];
+
+                return out;
+              }
+          }
+      }
+    return QPolygonF ();
+  }
+
+  void add (QPolygonF p)
+  {
+    if (m_polygons.count () == 0)
+        m_polygons.push_back (p);
+    else
+      {
+        QPolygonF tmp = mergepoly (m_polygons.back (), p);
+        if (tmp.count ())
+          m_polygons.back () = tmp;
+        else
+          m_polygons.push_back (p);
+      }
+  }
+
+private:
+  QList<QPolygonF> m_polygons;
+};
+
+void draw (QDomElement& parent_elt, pdfpainter& painter)
+{
+  QDomNodeList nodes = parent_elt.childNodes ();
+
+  static QString clippath_id;
+  static QMap< QString, QVector<QPoint> > clippath;
+
+  // tspan elements must have access to the font and position extracted from
+  // their parent text element
+  static QFont font;
+  static double dx = 0, dy = 0;
+
+  for (int i = 0; i < nodes.count (); i++)
+    {
+      QDomNode node = nodes.at (i);
+      if (! node.isElement ())
+        continue;
+
+      QDomElement elt = node.toElement ();
+
+      if (elt.tagName () == "clipPath")
+        {
+          clippath_id = "#" + elt.attribute ("id");
+          draw (elt, painter);
+          clippath_id = QString ();
+        }
+      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"));
+
+          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);
+
+          int sz = elt.attribute ("font-size").toInt ();
+          if (sz > 0)
+            font.setPixelSize (sz);
+
+          painter.setFont (font);
+
+          // 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 = 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;
+                }
+            }
+
+          draw (elt, painter);
+          painter.restore ();
+        }
+      else if (elt.tagName () == "tspan")
+        {
+          // Font
+          QFont saved_font(font);
+
+          QString str = elt.attribute ("font-family");
+          if (! str.isEmpty ())
+            font.setFamily (elt.attribute ("font-family"));
+
+          str = elt.attribute ("font-weight");
+          if (! str.isEmpty ())
+            {
+              if (str != "normal")
+                font.setWeight (QFont::Bold);
+              else
+                font.setWeight (QFont::Normal);
+            }
+
+          int sz = elt.attribute ("font-size").toInt ();
+          if (sz > 0)
+            font.setPixelSize (sz);
+
+          painter.setFont (font);
+
+          // Color is specified in rgb
+          str = get_field (elt.attribute ("fill"), "rgb");
+          if (! str.isEmpty ())
+            {
+              QStringList clist = str.split (",");
+              painter.setPen (QColor (clist[0].toInt (), clist[1].toInt (),
+                                      clist[2].toInt ()));
+            }
+
+          QStringList xx = elt.attribute ("x").split (" ");
+          int y = elt.attribute ("y").toInt ();
+          str = elt.text ();
+          if (! str.isEmpty ())
+            {
+              int ii = 0;
+              foreach (QString s,  xx)
+                if (ii < str.size ())
+                  painter.drawText (s.toInt ()-dx, y-dy, str.at (ii++));
+            }
+
+          draw (elt, painter);
+          font = saved_font;
+        }
+      else if (elt.tagName () == "polyline")
+        {
+          // Color
+          QColor c (elt.attribute ("stroke"));
+          QString str = elt.attribute ("stroke-opacity");
+          if (! str.isEmpty () && str.toDouble () != 1.0
+              && str.toDouble () >= 0.0)
+            c.setAlphaF (str.toDouble ());
+
+          QPen pen;
+          pen.setColor (c);
+
+          // Line properies
+          str = elt.attribute ("stroke-width");
+          if (! str.isEmpty ())
+            {
+              double w = str.toDouble () * painter.get_scale ();
+              if (w > 0)
+                pen.setWidthF (w / painter.get_scale ());
+            }
+
+          str = elt.attribute ("stroke-linecap");
+          pen.setCapStyle (Qt::SquareCap);
+          if (str == "round")
+            pen.setCapStyle (Qt::RoundCap);
+          else if (str == "butt")
+            pen.setCapStyle (Qt::FlatCap);
+
+          str = elt.attribute ("stroke-linejoin");
+          pen.setJoinStyle (Qt::MiterJoin);
+          if (str == "round")
+            pen.setJoinStyle (Qt::RoundJoin);
+          else if (str == "bevel")
+            pen.setJoinStyle (Qt::BevelJoin);
+
+          str = elt.attribute ("stroke-dasharray");
+          pen.setStyle (Qt::SolidLine);
+          if (! str.isEmpty ())
+            {
+              QVector<double> pat = qstr2vectord (str);
+              if (pat.count () != 2 || pat[1] != 0)
+                {
+                  // Express pattern in linewidth units
+                  for (auto& p : pat)
+                    p /= pen.widthF ();
+
+                  pen.setDashPattern (pat);
+                }
+            }
+
+          painter.setPen (pen);
+          painter.drawPolyline (qstr2ptsvector (elt.attribute ("points")));
+        }
+      else if (elt.tagName () == "image")
+        {
+          // Images are represented as a base64 stream of png formated data
+          QString href_att = elt.attribute ("xlink:href");
+          QString prefix ("data:image/png;base64,");
+          QByteArray data =
+            QByteArray::fromBase64(href_att.mid (prefix.length ())
+                                   .toLatin1 ());
+          QImage img;
+          if (img.loadFromData (data, "PNG"))
+            {
+              QRect pos(elt.attribute ("x").toInt (),
+                        elt.attribute ("y").toInt (),
+                        elt.attribute ("width").toInt (),
+                        elt.attribute ("height").toInt ());
+
+              // Translate
+              painter.save ();
+              QString str = get_field (elt.attribute ("transform"), "matrix");
+              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);
+                  painter.setTransform (tform);
+                }
+
+              painter.setRenderHint (QPainter::Antialiasing, false);
+              painter.drawImage (pos, img);
+              painter.setRenderHint (QPainter::Antialiasing, true);
+              painter.restore  ();
+            }
+        }
+      else if (elt.tagName () == "polygon")
+        {
+          if (! clippath_id.isEmpty ())
+            clippath[clippath_id] = qstr2ptsvectord (elt.attribute ("points"));
+          else
+            {
+              QString str = elt.attribute ("fill");
+              if (! str.isEmpty ())
+                {
+                  QColor color (str);
+
+                  str = elt.attribute ("fill-opacity");
+                  if (! str.isEmpty () && str.toDouble () != 1.0
+                      && str.toDouble () >= 0.0)
+                    color.setAlphaF (str.toDouble ());
+
+                  QPolygonF p (qstr2ptsvector (elt.attribute ("points")));
+
+                  if (p.count () > 2)
+                    {
+                      painter.setBrush (color);
+                      painter.setPen (Qt::NoPen);
+
+                      painter.setRenderHint (QPainter::Antialiasing, false);
+                      painter.drawPolygon (p);
+                      painter.setRenderHint (QPainter::Antialiasing, true);
+                    }
+                }
+            }
+        }
+    }
+}
+
+// Append a list of reconstructed child polygons to a QDomElement and remove
+// the original nodes
+
+void replace_polygons (QDomElement& parent_elt, QList<QDomNode> orig,
+                       QList<QPolygonF> polygons)
+{
+  if (! orig.count () || (orig.count () == polygons.count ()))
+    return;
+
+  QDomNode last = orig.last ();
+  for (int ii = 0; ii < polygons.count (); ii++)
+    {
+      QPolygonF polygon = polygons[ii];
+
+      QDomNode node = last.cloneNode ();
+
+      QString pts;
+
+      for (int jj = 0; jj < polygon.count (); jj++)
+        {
+          pts += QString ("%1,%2 ").arg (polygon[jj].x ())
+            .arg (polygon[jj].y ());
+        }
+
+      node.toElement ().setAttribute ("points", pts.trimmed ());
+
+      if (! last.isNull ())
+        last = parent_elt.insertAfter (node, last);
+    }
+
+  for (int ii = 0; ii < orig.count (); ii++)
+    parent_elt.removeChild (orig.at (ii));
+}
+
+void reconstruct_polygons (QDomElement& parent_elt)
+{
+  QDomNodeList nodes = parent_elt.childNodes ();
+  QColor current_color;
+  QList<QDomNode> replaced_nodes;
+  octave_polygon current_polygon;
+
+  // Collection of child nodes to be removed and polygons to be added
+  QList< QPair<QList<QDomNode>,QList<QPolygonF> > > collection;
+
+  for (int ii = 0; ii < nodes.count (); ii++)
+    {
+      QDomNode node = nodes.at (ii);
+      if (! node.isElement ())
+        continue;
+
+      QDomElement elt = node.toElement ();
+
+      if (elt.tagName () == "polygon")
+        {
+          QString str = elt.attribute ("fill");
+          if (! str.isEmpty ())
+            {
+              QColor color (str);
+              str = elt.attribute ("fill-opacity");
+              if (! str.isEmpty ())
+                {
+                  double alpha = str.toDouble ();
+                  if (alpha != 1.0 && str.toDouble () >= 0.0)
+                    color.setAlphaF (alpha);
+                }
+
+              if (! current_polygon.count ())
+                current_color = color;
+
+              if (color != current_color)
+                {
+                  // Reconstruct the previous series of triangle
+                  QList<QPolygonF> polygons = current_polygon.reconstruct ();
+                  collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> >
+                                        (replaced_nodes, polygons));
+
+                  replaced_nodes.clear ();
+                  current_polygon.reset ();
+
+                  current_color = color;
+                }
+
+              QPolygonF p (qstr2ptsvector (elt.attribute ("points")));
+              current_polygon.add (p);
+              replaced_nodes.push_back (node);
+            }
+        }
+      else
+        {
+          if (current_polygon.count ())
+            {
+              QList<QPolygonF> polygons = current_polygon.reconstruct ();
+              collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> >
+                                    (replaced_nodes, polygons));
+              replaced_nodes.clear ();
+              current_polygon.reset ();
+            }
+          reconstruct_polygons (elt);
+        }
+    }
+
+  // Finish
+  collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> >
+                        (replaced_nodes, current_polygon.reconstruct ()));
+
+  for (int ii = 0; ii < collection.count (); ii++)
+    replace_polygons (parent_elt, collection[ii].first, collection[ii].second);
+}
+
+int main(int argc, char *argv[])
+{
+  const char *doc = "See \"octave-svgconvert -h\"";
+  const char *help =
+"Usage:\n\
+octave-svgconvert infile fmt dpi font reconstruct outfile\n\n\
+Convert svg file to pdf, or svg. All arguments are mandatory:\n\
+* infile: input svg file or \"-\" to indicate that the input svg file should be \
+read from stdin\n\
+* fmt: format of the output file. May be one of pdf or svg\n\
+* dpi: device dependent resolution in screen pixel per inch\n\
+* font: specify a file name for the default FreeSans font\n\
+* reconstruct: specify wether to reconstruct triangle to polygons (0 or 1)\n\
+* outfile: output file name\n";
+  
+  if (strcmp (argv[1], "-h") == 0)
+    {
+      std::cout << help;
+      return 0;
+    }
+  else if (argc != 7)
+    {
+      std::cerr << help;
+      return -1;
+    }
+
+  // Open svg file
+  QFile file;
+  if (strcmp (argv[1], "-") != 0)
+    {
+      // Read from file
+      file.setFileName (argv[1]);
+      if (! file.open (QIODevice::ReadOnly | QIODevice::Text))
+        {
+          std::cerr << "Unable to open file " << argv[1] << "\n";
+          std::cerr << help;
+          return -1;
+        }
+    }
+  else
+    {
+      // Read from stdin
+      if (! file.open (stdin, QIODevice::ReadOnly | QIODevice::Text))
+        {
+          std::cerr << "Unable read from stdin\n";
+          std::cerr << doc;
+          return -1;
+        }
+    }
+
+  // Create a DOM document and load the svg file
+  QDomDocument document;
+  QString msg;
+  if(! document.setContent (&file, false, &msg))
+    {
+      std::cerr << "Failed to parse XML contents" << std::endl
+                << msg.toStdString ();
+      std::cerr << doc;
+      file.close();
+      return -1;
+    }
+
+  // Format
+  if (strcmp (argv[2], "pdf") != 0 && strcmp (argv[2], "svg") != 0)
+    {
+      std::cerr << "Unhandled output file format " << argv[2] << "\n";
+      std::cerr << doc;
+      return -1;
+    }
+
+  // Resolution
+  double dpi = QString (argv[3]).toDouble ();
+  if (dpi <= 0.0)
+    {
+      std::cerr << "DPI must be positive\n";
+      return -1;
+    }
+
+
+  // Get the viewport from the root element
+  QDomElement root = document.firstChildElement();
+  double x0, y0, dx, dy;
+  QString s = root.attribute ("viewBox");
+  QTextStream (&s) >> x0 >> y0 >> dx >> dy;
+  QRectF vp (x0, y0, dx, dy);
+
+  // Setup application and add default FreeSans font if needed
+  QApplication a (argc, argv);
+
+  // When printing to PDF we may need the default FreeSans font
+  if (! strcmp (argv[2], "pdf"))
+    {
+      QFont font ("FreeSans");
+      if (! font.exactMatch ())
+        {
+          QString fontpath (argv[4]);
+          if (! fontpath.isEmpty ())
+            {
+              int id = QFontDatabase::addApplicationFont (fontpath);
+              if (id < 0)
+                std::cerr << "warning: print: " 
+                  "Unable to add default font to database\n";
+            }
+          else
+            std::cerr << "warning: print: FreeSans font not found\n";
+        }
+    }
+
+  // First render in a temporary file
+  QTemporaryFile fout;
+  if (! fout.open ())
+    {
+      std::cerr << "Could not open temporary file\n";
+      return -1;
+    }
+
+  // Do basic polygons reconstruction
+  if (QString (argv[5]).toInt ())
+    reconstruct_polygons (root);
+
+  // Draw
+  if (! strcmp (argv[2], "pdf"))
+    {
+      // PDF painter
+      pdfpainter painter (fout.fileName (), vp, dpi);
+
+      draw (root, painter);
+      painter.finish ();
+    }
+  else
+    {
+      // Return modified svg document
+      QTextStream out (&fout);
+      out << document.toString ();
+    }
+
+  // Delete output file before writing with new data
+  if (QFile::exists (argv[6]))
+    if (! QFile::remove (argv[6]))
+      {
+        std::cerr << "Unable to replace existing file " << argv[6] << "\n";
+        return -1;
+      }
+
+  fout.copy (argv[6]);
+
+  return 0;
+}
--- a/test/args.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/args.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -220,7 +220,7 @@
 %!function f (x = @sin)
 %!  finfo = functions (x);
 %!  fname = finfo.function;
-%!  assert (isa (x, "function_handle") && strcmp (fname, "sin"));
+%!  assert (is_function_handle (x) && strcmp (fname, "sin"));
 %!endfunction
 %!test
 %! f()
@@ -229,7 +229,7 @@
 %!function f (x = @(x) x.^2)
 %!  finfo = functions (x);
 %!  ftype = finfo.type;
-%!  assert (isa (x, "function_handle") && strcmp (ftype, "anonymous"));
+%!  assert (is_function_handle (x) && strcmp (ftype, "anonymous"));
 %!endfunction
 %!test
 %! f()
--- a/test/bug-35448/bug-35448.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-35448/bug-35448.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -21,9 +21,11 @@
 %! gfun = @fB;
 %! y = fA (e);
 %! assert (y, e);
+%! clear -global gfun;  # cleanup after test
 
 %!test
 %! global gfun
 %! gfun = @fC;
 %! y = fA (e);
 %! assert (y, e);
+%! clear -global gfun;  # cleanup after test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-45969/bug-45969.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,36 @@
+%!test
+%! ascii_filename = tempname ();
+%! binary_filename = tempname ();
+%! a = 2;
+%! b = 10;
+%! c = 20;
+%! f1 = @ (f, x) f (x) + a;
+%! f2 = @ (y) f1 (@ (z) z^2 + b * y, y) + c;
+%! f2_arg = 5;
+%! unwind_protect
+%!   save (ascii_filename, "f2");
+%!   save ("-binary", binary_filename, "f2");
+%!   ascii = load (ascii_filename);
+%!   binary = load (binary_filename);
+%!   assert (f2 (f2_arg), ascii.f2 (f2_arg));
+%!   assert (f2 (f2_arg), binary.f2 (f2_arg));
+%! unwind_protect_cleanup
+%!   unlink (ascii_filename);
+%!   unlink (binary_filename);
+%! end_unwind_protect
+
+%!testif HAVE_HDF5
+%! hdf5_filename = tempname ();
+%! a = 2;
+%! b = 10;
+%! c = 20;
+%! f1 = @ (f, x) f (x) + a;
+%! f2 = @ (y) f1 (@ (z) z^2 + b * y, y) + c;
+%! f2_arg = 5;
+%! unwind_protect
+%!   save ("-hdf5", hdf5_filename, "f2");
+%!   hdf5 = load (hdf5_filename);
+%!   assert (f2 (f2_arg), hdf5.f2 (f2_arg));
+%! unwind_protect_cleanup
+%!   unlink (hdf5_filename);
+%! end_unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-45969/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,4 @@
+bug_45969_TEST_FILES = \
+  test/bug-45969/bug-45969.tst
+
+TEST_FILES += $(bug_45969_TEST_FILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-45972/bug-45972.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,26 @@
+%!test
+%! ascii_filename = tempname ();
+%! binary_filename = tempname ();
+%! f = @ (x, y, varargin) x + y + varargin{1};
+%! unwind_protect
+%!   save ("-text", ascii_filename, "f");
+%!   save ("-binary", binary_filename, "f");
+%!   ascii = load (ascii_filename);
+%!   binary = load (binary_filename);
+%!   assert (f (1, 2, 3), ascii.f (1, 2, 3));
+%!   assert (f (1, 2, 3), binary.f (1, 2, 3));
+%! unwind_protect_cleanup
+%!   unlink (ascii_filename);
+%!   unlink (binary_filename);
+%! end_unwind_protect
+
+%!testif HAVE_HDF5
+%! hdf5_filename = tempname ();
+%! f = @ (x, y, varargin) x + y + varargin{1};
+%! unwind_protect
+%!   save ("-hdf5", hdf5_filename, "f");
+%!   hdf5 = load (hdf5_filename);
+%!   assert (f (1, 2, 3), hdf5.f (1, 2, 3));
+%! unwind_protect_cleanup
+%!   unlink (hdf5_filename);
+%! end_unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-45972/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,4 @@
+bug_45972_TEST_FILES = \
+  %reldir%/bug-45972.tst
+
+TEST_FILES += $(bug_45972_TEST_FILES)
--- a/test/bug-49379/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-49379/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -1,3 +1,5 @@
 bug_49379_TEST_FILES = \
   %reldir%/bug-49379.tst \
-  %reldir%/class_bug49379.tst
+  %reldir%/class_bug49379.m
+
+TEST_FILES += $(bug_49379_TEST_FILES)
--- a/test/bug-50035/bug-50035.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-50035/bug-50035.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -29,3 +29,4 @@
 %! assert (in_name, "x");
 %! bug50035 ()
 %! assert (in_name, "ans");
+%! clear -global in_name;  # cleanup after test
--- a/test/bug-52722/bug-52722.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-52722/bug-52722.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -1,2 +1,3 @@
 %!test
 %! include_globals
+%! clear -global a b c;  # cleanup after test
--- a/test/bug-53027/bug-53027.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-53027/bug-53027.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -23,18 +23,22 @@
 %! assert (X, 1);
 %! clear X
 %! assert (exist ("X"), 0);
+%! clear -global X;  # cleanup after test
 
 %!test <*53027>
 %! [a, b] = ntest53027a ();
 %! assert ([a, b], [0, 0])
+%! clear -global x;  # cleanup after test
 
 %!test <*53027>
 %! [a, b] = ntest53027b ();
 %! assert ([a, b], [0, 0])
+%! clear -global x;  # cleanup after test
 
 %!test <*53027>
 %! [a, b] = ntest53027c ();
 %! assert ([a, b], [0, 0])
+%! clear -global x;  # cleanup after test
 
 ## Previous bugs have caused segfaults when executing script twice.
 %!test <*53027>
@@ -48,3 +52,4 @@
 %! assert (isglobal ("a") && isglobal ("c"))
 %! assert (! exist ("b"))
 %! assert (isempty (xx) && ! isglobal ("xx"))
+%! clear -global a b c;
--- a/test/bug-53579.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-53579.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -19,3 +19,4 @@
 %! assert (igaa);
 %! assert (igbb);
 %! assert (xx, 5);
+%! clear -global aa bb;  # cleanup after test
--- a/test/bug-53599.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/bug-53599.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -21,3 +21,4 @@
 %! global gval
 %! gval = 42;
 %! assert (sggval (), 42);
+%! clear -global gval;  # cleanup after test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-54490.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,17 @@
+%!function out = bug54490 ()
+%!  global k;
+%!  k = 1;
+%!  out = 3;
+%!endfunction
+
+%!test
+%! global k;
+%! k = 2;
+%! a = [5, 6];
+%! a(k) = bug54490 ();
+%! assert (a, [5, 3]);
+%! k = 2;
+%! a = [5, 6];
+%! [a(k)] = bug54490 ();
+%! assert (a, [5, 3]);
+%! clear -global k;  # cleanup after test
--- a/test/deprecate-props.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/deprecate-props.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -31,36 +31,6 @@
 %!  endif
 %!endfunction
 
-## patch/surface "normalmode" deprecated in 4.2, remove from version 5.
-%!test
-%! hf = figure ("visible", "off");
-%! unwind_protect
-%!   hp = patch ();
-%!   testprop (hp, "normalmode", "5.0");
-%! unwind_protect_cleanup
-%!   close (hf);
-%! end_unwind_protect
-
-%! hf = figure ("visible", "off");
-%! unwind_protect
-%!   hs = surface ();
-%!   testprop (hs, "normalmode", "5.0");
-%! unwind_protect_cleanup
-%!   close (hf);
-%! end_unwind_protect
-
-## axes, "zero" value for "x/yaxislocation" deprecated in 4.2, remove
-## from version 5.
-%!test
-%! hf = figure ("visible", "off");
-%! unwind_protect
-%!   ha = axes ();
-%!   testprop (ha, "xaxislocation", "5.0", "zero");
-%!   testprop (ha, "yaxislocation", "5.0", "zero");
-%! unwind_protect_cleanup
-%!   close (hf);
-%! end_unwind_protect
-
 ## annotation rectangle "edgecolor" deprecated in 4.4, remove from version 6.
 %!test
 %! hf = figure ("visible", "off");
--- a/test/diag-perm.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/diag-perm.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -77,7 +77,7 @@
 %! P1 = eye (1) (:, [1]);
 %! A1 = 1;
 %! P = eye (n) (:, randperm (n));
-%! A = rand (n-3, n, .5);
+%! A = rand (n-3, n);
 %! assert (typeinfo (A * P1), "matrix");
 %! assert (full (A * P1), full (A) * P1);
 %! assert (typeinfo (P1 * A), "matrix");
--- a/test/func.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/func.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -163,9 +163,9 @@
 %!test
 %! __fntestfunc__ ("flipud", m3);
 %!test
-%! __fntestfunc__ ("flipdim", m1, 2);
+%! __fntestfunc__ ("flip", m1, 2);
 %!test
-%! __fntestfunc__ ("flipdim", m3, 2);
+%! __fntestfunc__ ("flip", m3, 2);
 %!test
 %! __fntestfunc__ ("transpose", m1);
 %!test
--- a/test/global.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/global.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -19,6 +19,7 @@
 %!test
 %! global G = 1;
 %! assert (G,1);
+%! clear -global G;  # cleanup after test
 
 %!function f ()
 %!  global G;
@@ -27,6 +28,7 @@
 %!test
 %! global G = 1;
 %! f;
+%! clear -global G;  # cleanup after test
 
 %!function f ()
 %!  fail ("G");
@@ -34,6 +36,7 @@
 %!test
 %! global G = 1;
 %! f ();
+%! clear -global G;  # cleanup after test
 
 %!function f ()
 %!  global H = 1;
@@ -41,6 +44,7 @@
 %!test
 %! f;
 %! fail ("H");
+%! clear -global H;  # cleanup after test
 
 %!function f ()
 %!  global H = 1;
@@ -50,6 +54,7 @@
 %!  fail ("H");
 %!test
 %! g ();
+%! clear -global H;  # cleanup after test
 
 %!function f ()
 %!  global H = 1;
@@ -61,6 +66,7 @@
 %!test
 %! f ();
 %! g ();
+%! clear -global H;  # cleanup after test
 
 %!test
 %!function f ()
@@ -68,6 +74,7 @@
 %!endfunction
 %!test
 %! fail ("H");
+%! clear -global H;  # cleanup after test
 
 %!function f ()
 %!  global H = 1;
@@ -80,6 +87,7 @@
 %! f;
 %! clear H;
 %! g;
+%! clear -global H;  # cleanup after test
 
 %!function r = f ()
 %!  x = 1;
@@ -100,6 +108,7 @@
 %! assert (f (), 1);
 %! global x
 %! assert (x, 1);
+%! clear -global x;  # cleanup after test
 
 %!function r = f ()
 %!  x = 1;
@@ -120,6 +129,7 @@
 %! assert (f (), 1);
 %! global x
 %! assert (x, 1);
+%! clear -global x;  # cleanup after test
 
 %!test
 %! warning ("off", "Octave:global-local-conflict", "local");
@@ -133,3 +143,4 @@
 %! assert (x, 42);
 %! clear global x      ## clears global and local value
 %! assert (exist ("x"), 0);
+%! clear -global x;  # cleanup after test
--- a/test/index.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/index.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -76,7 +76,7 @@
 %!error a(0)
 %!assert (a(2), 3)
 
-%% Additional tests
+## Additional tests
 
 %!shared a, b
 %! a = [1,2;3,4];
@@ -496,8 +496,7 @@
 %! x([], false, :) = [];
 %! assert (x, y);
 
-
-  ##  Test indexing of unnamed constants
+##  Test indexing of unnamed constants
 %!error <index \(0\): subscripts must be>     1(0)
 %!error <index \(-1\): subscripts must be>    1(-1)
 %!error <index \(_,0.5\): subscripts>                 {}(1,0.5)
@@ -532,11 +531,11 @@
 %!error <a null assignment can only have one non-colon index>   abc(3,5) = []
 %!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5
 
-%! ##  Test diagonal matrices, and access of function results
+##  Test diagonal matrices, and access of function results
 %!error <index \(_,_,5\): but object has size 3x3> eye(3)(2,3,5)
 %!error <index \(-2,_\): subscripts>               eye(4)(-2,3)
 
-%! ##  Test cells
+##  Test cells
 %!shared abc
 %! abc = {1, 2; 3, 4};
 %!error <abc\(_,0.3,_\): subscripts>  abc(2,0.3,5)
@@ -544,13 +543,13 @@
 %!error <abc\(-2,_,_,_\): subscripts> abc{-2,1,1,1}
 %!error <abc\(0,_,_,_\): subscripts>  abc(0,1,1,1) = 1
 
-%! ##  Test permutation matrices
+##  Test permutation matrices
 %!shared abc
 %! abc = eye(3)([3 1 2],:);
 %!error <abc\([Nn][aA][Nn]\): subscripts>         abc(NA)
 %!error <abc\(_,_,_,[Ii][nN][Ff],_\): subscripts> abc(1,1,1,Inf,1)
 
-%! ##  Test sparse matrices
+##  Test sparse matrices
 %!shared abc
 %! abc = sparse(3,3);
 %!error <abc\(-1\): subscripts>                abc(-1)
@@ -560,29 +559,27 @@
 %!error <sparse indexing needs 1 or 2 indices> abc(0,0,0,0)
 %!error <abc\(4,_\): but abc has size 3x3>     abc(4,1)
 
-%! ##  Test ranges
+##  Test ranges
 %!shared abc
 %! abc = 1:10;
 %!error <abc\(-1\): subscripts>             abc(-1)
 %!error <abc\(-1,_\): subscripts>           abc(-1,1)
 %!error <abc\(4,_\): but abc has size 1x10> abc(4,1)
 
-%! ##  Test complex
+##  Test complex
 %!shared abc, z
 %! 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\+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)
+%!error <abc\(_,0-2i\): subscripts must be real>    abc(2,0-2*i)
 
-## bug #35841
-%!test
+%!test <*35841>
 %! a(1,1,1).b(1) = 2;
 %! a(1,1,1).b(1) = 3;
 
-## bug #39789
-%!test
+%!test <*39789>
 %! c = cell(1,1,1);
 %! c{1,1,1} = zeros(5, 2);
 %! c{1,1,1}(:, 1) = 1;
--- a/test/io.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/io.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -177,6 +177,9 @@
 %!    endfor
 %!  endif
 %!
+%!  ## Cleanup after test
+%!  clear -global a1;
+%!
 %!  ret = 1;
 %!endfunction
 
@@ -190,6 +193,7 @@
 %! endfor
 %!
 %! assert (save_status && load_status);
+%! clear -global a1;  # cleanup after test
 
 %!testif HAVE_HDF5
 %!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/bug-51725.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,20 @@
+## Copyright (C) 2018 John W. Eaton
+##
+## 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/>.
+
+%!assert (bug_51725 (), [])
+%!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/bug-54096.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,22 @@
+## Copyright (C) 2018 John W. Eaton
+##
+## 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/>.
+
+%!test
+%! s = bug_54096 ();
+%! assert (s, struct ("field", []));
+%! assert (s.field, []);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/bug_51725.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,10 @@
+#include "mex.h"
+
+void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+  if (nlhs > 0)
+    plhs[0] = mxCreateDoubleMatrix (0, 0, mxREAL);
+
+  if (nlhs > 2)
+    plhs[2] = mxCreateDoubleMatrix (0, 0, mxREAL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/bug_54096.c	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,19 @@
+#include "mex.h"
+
+static const char* field_names[] = {"field"};
+
+void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+  mxArray *tmp_val;
+
+  plhs[0] = mxCreateStructMatrix (1, 1, 1, field_names);
+
+  mxSetFieldByNumber (plhs[0], 0, 0, NULL);
+
+  tmp_val = mxGetFieldByNumber (plhs[0], 0, 0);
+
+  if (tmp_val)
+    mexErrMsgTxt ("struct elements set to NULL should be NULL internally");
+
+  /* But in the interpreter, they should appear as [].  */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,49 @@
+mex_TEST_FILES = \
+  %reldir%/bug-54096.tst \
+  %reldir%/bug-51725.tst \
+  $(MEX_TEST_SRC)
+
+MEX_TEST_SRC = \
+  %reldir%/bug_54096.c \
+  %reldir%/bug_51725.c
+
+MEX_TEST_FUNCTIONS = $(MEX_TEST_SRC:%.c=%.mex)
+
+## Since these definitions for MKOCTFILE and MKMEXFILE are only used
+## here, defining them in this file is probably OK.  If there are ever
+## used elsewhre, maybe then they could be moved to build-aux/module.mk
+## or the main Makefile.am file.  The MKOCTFILE variables are included
+## for completeness, in case we someday want to test building .oct
+## files as well.
+
+AM_V_mkmexfile = $(am__v_mkmexfile_@AM_V@)
+am__v_mkmexfile_ = $(am__v_mkmexfile_@AM_DEFAULT_V@)
+am__v_mkmexfile_0 = @echo "  MKMEXFILE     " $@;
+am__v_mkmexfile_1 =
+
+AM_VOPT_mkmexfile = $(am__vopt_mkmexfile_@AM_V@)
+am__vopt_mkmexfile_ = $(am__vopt_mkmexfile_@AM_DEFAULT_V@)
+am__vopt_mkmexfile_0 =
+am__vopt_mkmexfile_1 = -v
+
+## And probably many others...
+MKOCTFILECPPFLAGS = \
+  -I$(top_srcdir)/libinterp/corefcn \
+  -Ilibinterp/corefcn
+
+MKOCTFILE = $(top_builddir)/src/mkoctfile $(MKOCTFILECPPFLAGS)
+
+MKMEXFILECPPFLAGS = \
+  -I$(top_srcdir)/libinterp/corefcn \
+  -Ilibinterp/corefcn
+
+MKMEXFILE = $(top_builddir)/src/mkoctfile --mex $(MKMEXFILECPPFLAGS)
+
+$(MEX_TEST_FUNCTIONS) : %.mex : %.c | %reldir%/$(octave_dirstamp)
+	$(AM_V_mkmexfile)$(MKMEXFILE) $(AM_VOPT_mkmexfile) $< -o $@ || rm -f $@
+
+DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
+
+## Until we decide how to handle installing the executable MEX files,
+## don't install them or the associated test files.
+noinst_TEST_FILES += $(mex_TEST_FILES)
--- a/test/module.mk	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -14,6 +14,7 @@
   %reldir%/bug-49904.tst \
   %reldir%/bug-53579.tst \
   %reldir%/bug-53599.tst \
+  %reldir%/bug-54490.tst \
   %reldir%/colormaps.tst \
   %reldir%/command.tst \
   %reldir%/complex.tst \
@@ -57,6 +58,7 @@
 include %reldir%/bug-38691/module.mk
 include %reldir%/bug-41723/module.mk
 include %reldir%/bug-44940/module.mk
+include %reldir%/bug-45972/module.mk
 include %reldir%/bug-46660/module.mk
 include %reldir%/bug-49379/module.mk
 include %reldir%/bug-50014/module.mk
@@ -76,11 +78,13 @@
 include %reldir%/ctor-vs-method/module.mk
 include %reldir%/fcn-handle-derived-resolution/module.mk
 include %reldir%/local-functions/module.mk
+include %reldir%/mex/module.mk
 include %reldir%/nest/module.mk
 include %reldir%/publish/module.mk
+include %reldir%/pkg/module.mk
 
 define run-octave-tests
-  ( cd %reldir% && $(SHELL) ../run-octave $(RUN_OCTAVE_OPTIONS) $(1) --norc --silent --no-history $(abs_top_srcdir)/%reldir%/fntests.m $(abs_top_srcdir)/%reldir% ) && \
+  ( cd %reldir% && $(SHELL) ../run-octave $(RUN_OCTAVE_OPTIONS) $(1) --norc --silent --no-history -p $(abs_top_builddir)/%reldir%/mex $(abs_top_srcdir)/%reldir%/fntests.m $(abs_top_srcdir)/%reldir% ) && \
   if $(AM_V_P); then \
     echo ""; \
     if [ -f %reldir%/fntests.log ]; then \
@@ -93,7 +97,7 @@
   fi
 endef
 
-check-local: $(GENERATED_TEST_FILES) | $(OCTAVE_INTERPRETER_TARGETS) %reldir%/$(octave_dirstamp)
+check-local: $(GENERATED_TEST_FILES) $(MEX_TEST_FUNCTIONS) | $(OCTAVE_INTERPRETER_TARGETS) %reldir%/$(octave_dirstamp)
 	$(AM_V_at)$(call run-octave-tests)
 
 if AMCOND_HAVE_LLVM
@@ -190,7 +194,9 @@
   %reldir%/mk-sparse-tst.sh \
   %reldir%/mk_bc_overloads_expected.m \
   %reldir%/show-failures.awk \
-  $(TEST_FILES)
+  $(TEST_FILES) \
+  $(noinst_TEST_FILES) \
+  $(MEX_TEST_SRC)
 
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
 
@@ -211,6 +217,7 @@
 	rm -f $(%canon_reldir%_CLEANFILES)
 	rm -rf $(GENERATED_BC_OVERLOADS_DIRS)
 	rm -rf $(COVERAGE_DIR)
+	rm -rf $(MEX_TEST_FUNCTIONS)
 
 test-distclean: test-clean
 	rm -f $(%canon_reldir%_DISTCLEANFILES)
--- a/test/nest/nest.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/nest/nest.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -22,7 +22,9 @@
 ## It relies on the function files defined in the nest/ directory.
 ################################################################################
 
-%!assert (recursive_nest (), 25)
+%!test
+%! assert (recursive_nest (), 25)
+%! clear -global recursive_nest_inc;  # cleanup after test
 
 %!assert (recursive_nest2 (), 20)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/COPYING	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,719 @@
+Appendix G GNU GENERAL PUBLIC LICENSE
+*************************************
+
+                        Version 3, 29 June 2007
+
+     Copyright (C) 2007 Free Software Foundation, Inc. `http://fsf.org/'
+
+     Everyone is permitted to copy and distribute verbatim copies of this
+     license document, but changing it is not allowed.
+
+Preamble
+========
+
+The GNU General Public License is a free, copyleft license for software
+and other kinds of works.
+
+   The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains
+free software for all its users.  We, the Free Software Foundation, use
+the GNU General Public License for most of our software; it applies
+also to any other work released this way by its authors.  You can apply
+it to your programs, too.
+
+   When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+   To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you
+have certain responsibilities if you distribute copies of the software,
+or if you modify it: responsibilities to respect the freedom of others.
+
+   For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+   Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+   For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+   Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the
+manufacturer can do so.  This is fundamentally incompatible with the
+aim of protecting users' freedom to change the software.  The
+systematic pattern of such abuse occurs in the area of products for
+individuals to use, which is precisely where it is most unacceptable.
+Therefore, we have designed this version of the GPL to prohibit the
+practice for those products.  If such problems arise substantially in
+other domains, we stand ready to extend this provision to those domains
+in future versions of the GPL, as needed to protect the freedom of
+users.
+
+   Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+   The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS
+====================
+
+  0. Definitions.
+
+     "This License" refers to version 3 of the GNU General Public
+     License.
+
+     "Copyright" also means copyright-like laws that apply to other
+     kinds of works, such as semiconductor masks.
+
+     "The Program" refers to any copyrightable work licensed under this
+     License.  Each licensee is addressed as "you".  "Licensees" and
+     "recipients" may be individuals or organizations.
+
+     To "modify" a work means to copy from or adapt all or part of the
+     work in a fashion requiring copyright permission, other than the
+     making of an exact copy.  The resulting work is called a "modified
+     version" of the earlier work or a work "based on" the earlier work.
+
+     A "covered work" means either the unmodified Program or a work
+     based on the Program.
+
+     To "propagate" a work means to do anything with it that, without
+     permission, would make you directly or secondarily liable for
+     infringement under applicable copyright law, except executing it
+     on a computer or modifying a private copy.  Propagation includes
+     copying, distribution (with or without modification), making
+     available to the public, and in some countries other activities as
+     well.
+
+     To "convey" a work means any kind of propagation that enables other
+     parties to make or receive copies.  Mere interaction with a user
+     through a computer network, with no transfer of a copy, is not
+     conveying.
+
+     An interactive user interface displays "Appropriate Legal Notices"
+     to the extent that it includes a convenient and prominently visible
+     feature that (1) displays an appropriate copyright notice, and (2)
+     tells the user that there is no warranty for the work (except to
+     the extent that warranties are provided), that licensees may
+     convey the work under this License, and how to view a copy of this
+     License.  If the interface presents a list of user commands or
+     options, such as a menu, a prominent item in the list meets this
+     criterion.
+
+  1. Source Code.
+
+     The "source code" for a work means the preferred form of the work
+     for making modifications to it.  "Object code" means any
+     non-source form of a work.
+
+     A "Standard Interface" means an interface that either is an
+     official standard defined by a recognized standards body, or, in
+     the case of interfaces specified for a particular programming
+     language, one that is widely used among developers working in that
+     language.
+
+     The "System Libraries" of an executable work include anything,
+     other than the work as a whole, that (a) is included in the normal
+     form of packaging a Major Component, but which is not part of that
+     Major Component, and (b) serves only to enable use of the work
+     with that Major Component, or to implement a Standard Interface
+     for which an implementation is available to the public in source
+     code form.  A "Major Component", in this context, means a major
+     essential component (kernel, window system, and so on) of the
+     specific operating system (if any) on which the executable work
+     runs, or a compiler used to produce the work, or an object code
+     interpreter used to run it.
+
+     The "Corresponding Source" for a work in object code form means all
+     the source code needed to generate, install, and (for an executable
+     work) run the object code and to modify the work, including
+     scripts to control those activities.  However, it does not include
+     the work's System Libraries, or general-purpose tools or generally
+     available free programs which are used unmodified in performing
+     those activities but which are not part of the work.  For example,
+     Corresponding Source includes interface definition files
+     associated with source files for the work, and the source code for
+     shared libraries and dynamically linked subprograms that the work
+     is specifically designed to require, such as by intimate data
+     communication or control flow between those subprograms and other
+     parts of the work.
+
+     The Corresponding Source need not include anything that users can
+     regenerate automatically from other parts of the Corresponding
+     Source.
+
+     The Corresponding Source for a work in source code form is that
+     same work.
+
+  2. Basic Permissions.
+
+     All rights granted under this License are granted for the term of
+     copyright on the Program, and are irrevocable provided the stated
+     conditions are met.  This License explicitly affirms your unlimited
+     permission to run the unmodified Program.  The output from running
+     a covered work is covered by this License only if the output,
+     given its content, constitutes a covered work.  This License
+     acknowledges your rights of fair use or other equivalent, as
+     provided by copyright law.
+
+     You may make, run and propagate covered works that you do not
+     convey, without conditions so long as your license otherwise
+     remains in force.  You may convey covered works to others for the
+     sole purpose of having them make modifications exclusively for
+     you, or provide you with facilities for running those works,
+     provided that you comply with the terms of this License in
+     conveying all material for which you do not control copyright.
+     Those thus making or running the covered works for you must do so
+     exclusively on your behalf, under your direction and control, on
+     terms that prohibit them from making any copies of your
+     copyrighted material outside their relationship with you.
+
+     Conveying under any other circumstances is permitted solely under
+     the conditions stated below.  Sublicensing is not allowed; section
+     10 makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+     No covered work shall be deemed part of an effective technological
+     measure under any applicable law fulfilling obligations under
+     article 11 of the WIPO copyright treaty adopted on 20 December
+     1996, or similar laws prohibiting or restricting circumvention of
+     such measures.
+
+     When you convey a covered work, you waive any legal power to forbid
+     circumvention of technological measures to the extent such
+     circumvention is effected by exercising rights under this License
+     with respect to the covered work, and you disclaim any intention
+     to limit operation or modification of the work as a means of
+     enforcing, against the work's users, your or third parties' legal
+     rights to forbid circumvention of technological measures.
+
+  4. Conveying Verbatim Copies.
+
+     You may convey verbatim copies of the Program's source code as you
+     receive it, in any medium, provided that you conspicuously and
+     appropriately publish on each copy an appropriate copyright notice;
+     keep intact all notices stating that this License and any
+     non-permissive terms added in accord with section 7 apply to the
+     code; keep intact all notices of the absence of any warranty; and
+     give all recipients a copy of this License along with the Program.
+
+     You may charge any price or no price for each copy that you convey,
+     and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+     You may convey a work based on the Program, or the modifications to
+     produce it from the Program, in the form of source code under the
+     terms of section 4, provided that you also meet all of these
+     conditions:
+
+       a. The work must carry prominent notices stating that you
+          modified it, and giving a relevant date.
+
+       b. The work must carry prominent notices stating that it is
+          released under this License and any conditions added under
+          section 7.  This requirement modifies the requirement in
+          section 4 to "keep intact all notices".
+
+       c. You must license the entire work, as a whole, under this
+          License to anyone who comes into possession of a copy.  This
+          License will therefore apply, along with any applicable
+          section 7 additional terms, to the whole of the work, and all
+          its parts, regardless of how they are packaged.  This License
+          gives no permission to license the work in any other way, but
+          it does not invalidate such permission if you have separately
+          received it.
+
+       d. If the work has interactive user interfaces, each must display
+          Appropriate Legal Notices; however, if the Program has
+          interactive interfaces that do not display Appropriate Legal
+          Notices, your work need not make them do so.
+
+     A compilation of a covered work with other separate and independent
+     works, which are not by their nature extensions of the covered
+     work, and which are not combined with it such as to form a larger
+     program, in or on a volume of a storage or distribution medium, is
+     called an "aggregate" if the compilation and its resulting
+     copyright are not used to limit the access or legal rights of the
+     compilation's users beyond what the individual works permit.
+     Inclusion of a covered work in an aggregate does not cause this
+     License to apply to the other parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+     You may convey a covered work in object code form under the terms
+     of sections 4 and 5, provided that you also convey the
+     machine-readable Corresponding Source under the terms of this
+     License, in one of these ways:
+
+       a. Convey the object code in, or embodied in, a physical product
+          (including a physical distribution medium), accompanied by the
+          Corresponding Source fixed on a durable physical medium
+          customarily used for software interchange.
+
+       b. Convey the object code in, or embodied in, a physical product
+          (including a physical distribution medium), accompanied by a
+          written offer, valid for at least three years and valid for
+          as long as you offer spare parts or customer support for that
+          product model, to give anyone who possesses the object code
+          either (1) a copy of the Corresponding Source for all the
+          software in the product that is covered by this License, on a
+          durable physical medium customarily used for software
+          interchange, for a price no more than your reasonable cost of
+          physically performing this conveying of source, or (2) access
+          to copy the Corresponding Source from a network server at no
+          charge.
+
+       c. Convey individual copies of the object code with a copy of
+          the written offer to provide the Corresponding Source.  This
+          alternative is allowed only occasionally and noncommercially,
+          and only if you received the object code with such an offer,
+          in accord with subsection 6b.
+
+       d. Convey the object code by offering access from a designated
+          place (gratis or for a charge), and offer equivalent access
+          to the Corresponding Source in the same way through the same
+          place at no further charge.  You need not require recipients
+          to copy the Corresponding Source along with the object code.
+          If the place to copy the object code is a network server, the
+          Corresponding Source may be on a different server (operated
+          by you or a third party) that supports equivalent copying
+          facilities, provided you maintain clear directions next to
+          the object code saying where to find the Corresponding Source.
+          Regardless of what server hosts the Corresponding Source, you
+          remain obligated to ensure that it is available for as long
+          as needed to satisfy these requirements.
+
+       e. Convey the object code using peer-to-peer transmission,
+          provided you inform other peers where the object code and
+          Corresponding Source of the work are being offered to the
+          general public at no charge under subsection 6d.
+
+
+     A separable portion of the object code, whose source code is
+     excluded from the Corresponding Source as a System Library, need
+     not be included in conveying the object code work.
+
+     A "User Product" is either (1) a "consumer product", which means
+     any tangible personal property which is normally used for personal,
+     family, or household purposes, or (2) anything designed or sold for
+     incorporation into a dwelling.  In determining whether a product
+     is a consumer product, doubtful cases shall be resolved in favor of
+     coverage.  For a particular product received by a particular user,
+     "normally used" refers to a typical or common use of that class of
+     product, regardless of the status of the particular user or of the
+     way in which the particular user actually uses, or expects or is
+     expected to use, the product.  A product is a consumer product
+     regardless of whether the product has substantial commercial,
+     industrial or non-consumer uses, unless such uses represent the
+     only significant mode of use of the product.
+
+     "Installation Information" for a User Product means any methods,
+     procedures, authorization keys, or other information required to
+     install and execute modified versions of a covered work in that
+     User Product from a modified version of its Corresponding Source.
+     The information must suffice to ensure that the continued
+     functioning of the modified object code is in no case prevented or
+     interfered with solely because modification has been made.
+
+     If you convey an object code work under this section in, or with,
+     or specifically for use in, a User Product, and the conveying
+     occurs as part of a transaction in which the right of possession
+     and use of the User Product is transferred to the recipient in
+     perpetuity or for a fixed term (regardless of how the transaction
+     is characterized), the Corresponding Source conveyed under this
+     section must be accompanied by the Installation Information.  But
+     this requirement does not apply if neither you nor any third party
+     retains the ability to install modified object code on the User
+     Product (for example, the work has been installed in ROM).
+
+     The requirement to provide Installation Information does not
+     include a requirement to continue to provide support service,
+     warranty, or updates for a work that has been modified or
+     installed by the recipient, or for the User Product in which it
+     has been modified or installed.  Access to a network may be denied
+     when the modification itself materially and adversely affects the
+     operation of the network or violates the rules and protocols for
+     communication across the network.
+
+     Corresponding Source conveyed, and Installation Information
+     provided, in accord with this section must be in a format that is
+     publicly documented (and with an implementation available to the
+     public in source code form), and must require no special password
+     or key for unpacking, reading or copying.
+
+  7. Additional Terms.
+
+     "Additional permissions" are terms that supplement the terms of
+     this License by making exceptions from one or more of its
+     conditions.  Additional permissions that are applicable to the
+     entire Program shall be treated as though they were included in
+     this License, to the extent that they are valid under applicable
+     law.  If additional permissions apply only to part of the Program,
+     that part may be used separately under those permissions, but the
+     entire Program remains governed by this License without regard to
+     the additional permissions.
+
+     When you convey a copy of a covered work, you may at your option
+     remove any additional permissions from that copy, or from any part
+     of it.  (Additional permissions may be written to require their own
+     removal in certain cases when you modify the work.)  You may place
+     additional permissions on material, added by you to a covered work,
+     for which you have or can give appropriate copyright permission.
+
+     Notwithstanding any other provision of this License, for material
+     you add to a covered work, you may (if authorized by the copyright
+     holders of that material) supplement the terms of this License
+     with terms:
+
+       a. Disclaiming warranty or limiting liability differently from
+          the terms of sections 15 and 16 of this License; or
+
+       b. Requiring preservation of specified reasonable legal notices
+          or author attributions in that material or in the Appropriate
+          Legal Notices displayed by works containing it; or
+
+       c. Prohibiting misrepresentation of the origin of that material,
+          or requiring that modified versions of such material be
+          marked in reasonable ways as different from the original
+          version; or
+
+       d. Limiting the use for publicity purposes of names of licensors
+          or authors of the material; or
+
+       e. Declining to grant rights under trademark law for use of some
+          trade names, trademarks, or service marks; or
+
+       f. Requiring indemnification of licensors and authors of that
+          material by anyone who conveys the material (or modified
+          versions of it) with contractual assumptions of liability to
+          the recipient, for any liability that these contractual
+          assumptions directly impose on those licensors and authors.
+
+     All other non-permissive additional terms are considered "further
+     restrictions" within the meaning of section 10.  If the Program as
+     you received it, or any part of it, contains a notice stating that
+     it is governed by this License along with a term that is a further
+     restriction, you may remove that term.  If a license document
+     contains a further restriction but permits relicensing or
+     conveying under this License, you may add to a covered work
+     material governed by the terms of that license document, provided
+     that the further restriction does not survive such relicensing or
+     conveying.
+
+     If you add terms to a covered work in accord with this section, you
+     must place, in the relevant source files, a statement of the
+     additional terms that apply to those files, or a notice indicating
+     where to find the applicable terms.
+
+     Additional terms, permissive or non-permissive, may be stated in
+     the form of a separately written license, or stated as exceptions;
+     the above requirements apply either way.
+
+  8. Termination.
+
+     You may not propagate or modify a covered work except as expressly
+     provided under this License.  Any attempt otherwise to propagate or
+     modify it is void, and will automatically terminate your rights
+     under this License (including any patent licenses granted under
+     the third paragraph of section 11).
+
+     However, if you cease all violation of this License, then your
+     license from a particular copyright holder is reinstated (a)
+     provisionally, unless and until the copyright holder explicitly
+     and finally terminates your license, and (b) permanently, if the
+     copyright holder fails to notify you of the violation by some
+     reasonable means prior to 60 days after the cessation.
+
+     Moreover, your license from a particular copyright holder is
+     reinstated permanently if the copyright holder notifies you of the
+     violation by some reasonable means, this is the first time you have
+     received notice of violation of this License (for any work) from
+     that copyright holder, and you cure the violation prior to 30 days
+     after your receipt of the notice.
+
+     Termination of your rights under this section does not terminate
+     the licenses of parties who have received copies or rights from
+     you under this License.  If your rights have been terminated and
+     not permanently reinstated, you do not qualify to receive new
+     licenses for the same material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+     You are not required to accept this License in order to receive or
+     run a copy of the Program.  Ancillary propagation of a covered work
+     occurring solely as a consequence of using peer-to-peer
+     transmission to receive a copy likewise does not require
+     acceptance.  However, nothing other than this License grants you
+     permission to propagate or modify any covered work.  These actions
+     infringe copyright if you do not accept this License.  Therefore,
+     by modifying or propagating a covered work, you indicate your
+     acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+     Each time you convey a covered work, the recipient automatically
+     receives a license from the original licensors, to run, modify and
+     propagate that work, subject to this License.  You are not
+     responsible for enforcing compliance by third parties with this
+     License.
+
+     An "entity transaction" is a transaction transferring control of an
+     organization, or substantially all assets of one, or subdividing an
+     organization, or merging organizations.  If propagation of a
+     covered work results from an entity transaction, each party to that
+     transaction who receives a copy of the work also receives whatever
+     licenses to the work the party's predecessor in interest had or
+     could give under the previous paragraph, plus a right to
+     possession of the Corresponding Source of the work from the
+     predecessor in interest, if the predecessor has it or can get it
+     with reasonable efforts.
+
+     You may not impose any further restrictions on the exercise of the
+     rights granted or affirmed under this License.  For example, you
+     may not impose a license fee, royalty, or other charge for
+     exercise of rights granted under this License, and you may not
+     initiate litigation (including a cross-claim or counterclaim in a
+     lawsuit) alleging that any patent claim is infringed by making,
+     using, selling, offering for sale, or importing the Program or any
+     portion of it.
+
+ 11. Patents.
+
+     A "contributor" is a copyright holder who authorizes use under this
+     License of the Program or a work on which the Program is based.
+     The work thus licensed is called the contributor's "contributor
+     version".
+
+     A contributor's "essential patent claims" are all patent claims
+     owned or controlled by the contributor, whether already acquired or
+     hereafter acquired, that would be infringed by some manner,
+     permitted by this License, of making, using, or selling its
+     contributor version, but do not include claims that would be
+     infringed only as a consequence of further modification of the
+     contributor version.  For purposes of this definition, "control"
+     includes the right to grant patent sublicenses in a manner
+     consistent with the requirements of this License.
+
+     Each contributor grants you a non-exclusive, worldwide,
+     royalty-free patent license under the contributor's essential
+     patent claims, to make, use, sell, offer for sale, import and
+     otherwise run, modify and propagate the contents of its
+     contributor version.
+
+     In the following three paragraphs, a "patent license" is any
+     express agreement or commitment, however denominated, not to
+     enforce a patent (such as an express permission to practice a
+     patent or covenant not to sue for patent infringement).  To
+     "grant" such a patent license to a party means to make such an
+     agreement or commitment not to enforce a patent against the party.
+
+     If you convey a covered work, knowingly relying on a patent
+     license, and the Corresponding Source of the work is not available
+     for anyone to copy, free of charge and under the terms of this
+     License, through a publicly available network server or other
+     readily accessible means, then you must either (1) cause the
+     Corresponding Source to be so available, or (2) arrange to deprive
+     yourself of the benefit of the patent license for this particular
+     work, or (3) arrange, in a manner consistent with the requirements
+     of this License, to extend the patent license to downstream
+     recipients.  "Knowingly relying" means you have actual knowledge
+     that, but for the patent license, your conveying the covered work
+     in a country, or your recipient's use of the covered work in a
+     country, would infringe one or more identifiable patents in that
+     country that you have reason to believe are valid.
+
+     If, pursuant to or in connection with a single transaction or
+     arrangement, you convey, or propagate by procuring conveyance of, a
+     covered work, and grant a patent license to some of the parties
+     receiving the covered work authorizing them to use, propagate,
+     modify or convey a specific copy of the covered work, then the
+     patent license you grant is automatically extended to all
+     recipients of the covered work and works based on it.
+
+     A patent license is "discriminatory" if it does not include within
+     the scope of its coverage, prohibits the exercise of, or is
+     conditioned on the non-exercise of one or more of the rights that
+     are specifically granted under this License.  You may not convey a
+     covered work if you are a party to an arrangement with a third
+     party that is in the business of distributing software, under
+     which you make payment to the third party based on the extent of
+     your activity of conveying the work, and under which the third
+     party grants, to any of the parties who would receive the covered
+     work from you, a discriminatory patent license (a) in connection
+     with copies of the covered work conveyed by you (or copies made
+     from those copies), or (b) primarily for and in connection with
+     specific products or compilations that contain the covered work,
+     unless you entered into that arrangement, or that patent license
+     was granted, prior to 28 March 2007.
+
+     Nothing in this License shall be construed as excluding or limiting
+     any implied license or other defenses to infringement that may
+     otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+     If conditions are imposed on you (whether by court order,
+     agreement or otherwise) that contradict the conditions of this
+     License, they do not excuse you from the conditions of this
+     License.  If you cannot convey a covered work so as to satisfy
+     simultaneously your obligations under this License and any other
+     pertinent obligations, then as a consequence you may not convey it
+     at all.  For example, if you agree to terms that obligate you to
+     collect a royalty for further conveying from those to whom you
+     convey the Program, the only way you could satisfy both those
+     terms and this License would be to refrain entirely from conveying
+     the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+     Notwithstanding any other provision of this License, you have
+     permission to link or combine any covered work with a work licensed
+     under version 3 of the GNU Affero General Public License into a
+     single combined work, and to convey the resulting work.  The terms
+     of this License will continue to apply to the part which is the
+     covered work, but the special requirements of the GNU Affero
+     General Public License, section 13, concerning interaction through
+     a network will apply to the combination as such.
+
+ 14. Revised Versions of this License.
+
+     The Free Software Foundation may publish revised and/or new
+     versions of the GNU General Public License from time to time.
+     Such new versions will be similar in spirit to the present
+     version, but may differ in detail to address new problems or
+     concerns.
+
+     Each version is given a distinguishing version number.  If the
+     Program specifies that a certain numbered version of the GNU
+     General Public License "or any later version" applies to it, you
+     have the option of following the terms and conditions either of
+     that numbered version or of any later version published by the
+     Free Software Foundation.  If the Program does not specify a
+     version number of the GNU General Public License, you may choose
+     any version ever published by the Free Software Foundation.
+
+     If the Program specifies that a proxy can decide which future
+     versions of the GNU General Public License can be used, that
+     proxy's public statement of acceptance of a version permanently
+     authorizes you to choose that version for the Program.
+
+     Later license versions may give you additional or different
+     permissions.  However, no additional obligations are imposed on any
+     author or copyright holder as a result of your choosing to follow a
+     later version.
+
+ 15. Disclaimer of Warranty.
+
+     THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+     APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE
+     COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE
+     RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+     SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+     NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+     IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+     WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES
+     AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
+     FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+     CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+     THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+     BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+     PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
+     THE POSSIBILITY OF SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+     If the disclaimer of warranty and limitation of liability provided
+     above cannot be given local legal effect according to their terms,
+     reviewing courts shall apply local law that most closely
+     approximates an absolute waiver of all civil liability in
+     connection with the Program, unless a warranty or assumption of
+     liability accompanies a copy of the Program in return for a fee.
+
+
+END OF TERMS AND CONDITIONS
+===========================
+
+How to Apply These Terms to Your New Programs
+=============================================
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+   To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+     ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
+     Copyright (C) YEAR NAME OF AUTHOR
+
+     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
+     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
+     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 `http://www.gnu.org/licenses/'.
+
+   Also add information on how to contact you by electronic and paper
+mail.
+
+   If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+     PROGRAM Copyright (C) YEAR NAME OF AUTHOR
+     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+     This is free software, and you are welcome to redistribute it
+     under certain conditions; type `show c' for details.
+
+   The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, your
+program's commands might be different; for a GUI interface, you would
+use an "about box".
+
+   You should also get your employer (if you work as a programmer) or
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  For more information on this, and how to apply and follow
+the GNU GPL, see `http://www.gnu.org/licenses/'.
+
+   The GNU General Public License does not permit incorporating your
+program into proprietary programs.  If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library.  If this is what you want to do, use the
+GNU Lesser General Public License instead of this License.  But first,
+please read `http://www.gnu.org/philosophy/why-not-lgpl.html'.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/DESCRIPTION	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,12 @@
+Name: mfile_basic_test
+Version: 0.1.0
+Date: 2017-12-07
+Author: hopefully various authors
+Maintainer: hopefully some of those authors.
+Title: Basic Example Package
+Description: Basic package structure with only m-files.
+Depends: octave (>= 4.2.1)
+License: GPLv3+
+# BuildRequires:
+# SystemRequirements:
+# Url: external homepage
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/INDEX	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,3 @@
+mfile-basic-example-package >> Basic Example Package.
+Example m-file
+ example_mfile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/NEWS	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,4 @@
+mfile-basic-example-package 0.1.0
+---------------------------------
+
+* Initial version
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/doc/example-package.txi	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,89 @@
+\input texinfo
+@c %**start of header
+@setfilename example-package.info
+@settitle example-package_doc
+@c %**end of header
+
+@c Nowadays the predined function index has entries for each @deftypefn
+@c in additiont to each @findex.
+@defcodeindex mfn
+
+@copying
+Manual for the example-package for Octave.
+
+Copyright @copyright{} 2017-2018 @email{Olaf Till <i7tiol@@t-online.de>}
+
+You can redistribute this documentation 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 documentation 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 documentation; if not, see <http://www.gnu.org/licenses/>.
+@end copying
+
+@include macros.texi
+
+@titlepage
+@title Manual for the example-package for Octave
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@c No table of contents. The table would occupy most of the top node in
+@c html and IMHO misleads the user to use the table instead of the menu
+@c structure of the nodes, which would let some information unused.
+@c
+@c @contents
+
+@c ------------------------------------------------------------------
+
+@node Top
+@top Manual for the example-package for Octave
+
+This documentation applies to version @PACKAGEVERSION of the
+example-package.
+
+This is a template simple m-file based package for users.
+
+Normally, a package manual should be structured and should contain more
+than just the helptexts of the functions.
+
+@menu
+Functions
+* example_mfile::                     Placeholder for an mfile.
+Indices
+* Function index::                    Index of functions.
+* Concept index::                     Concept index.
+@end menu
+
+@c ------------------------------------------------------------------
+
+@node example_mfile
+@chapter Placeholder for an mfile
+@mfnindex example_mfile
+
+@c include function helptext here
+@DOCSTRING(example_mfile)
+
+@c ------------------------------------------------------------------
+
+@node Function index
+@unnumbered Index of functions in example-package
+
+@printindex mfn
+
+@c ------------------------------------------------------------------
+
+@node Concept index
+@unnumbered Concept index
+
+@printindex cp
+
+@bye
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/doc/macros.texi	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,88 @@
+@c Copyright (C) 2012-2018 John W. Eaton
+@c
+@c This file is part of Octave.
+@c
+@c Octave is free software; you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by the
+@c Free Software Foundation; either version 3 of the License, or (at
+@c your option) any later version.
+@c
+@c Octave is distributed in the hope that it will be useful, but WITHOUT
+@c ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+@c FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+@c for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with Octave; see the file COPYING.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@c The following macro marks words that aspell should ignore during
+@c spellchecking.  Within Texinfo it has no effect as it merely replaces
+@c the macro call with the argument itself.
+
+@macro nospell {arg}
+\arg\
+@end macro
+
+@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"'
+@ifinfo
+@rmacro qcode{arg}
+\arg\
+@end rmacro
+@end ifinfo
+@ifnotinfo
+@rmacro qcode{arg}
+@code{\arg\}
+@end rmacro
+@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
+@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 behavior.
+
+@macro seealso {args}
+@iftex
+@vskip 2pt
+@end iftex
+@ifnottex
+
+@end ifnottex
+@ifnotinfo
+@noindent
+@strong{See also:} \args\.
+@end ifnotinfo
+@ifinfo
+@noindent
+See also: \args\.
+@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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_basic_test/inst/example_mfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,36 @@
+## Copyright (C) 2017-2018 Olaf Till <i7tiol@t-online.de>
+##
+## 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 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
+## 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 <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{ret} =} example_mfile (@var{arg})
+## Placeholder for an mfile function.
+##
+## @var{arg}: argument. @var{ret}: returned value.
+##
+## Although this file is so short, a license text is contained as an
+## example.
+##
+## @seealso{example_open, example_close, example_do_something}
+## @end deftypefn
+
+function ret = example_mfile (arg)
+
+  if (nargin () != 1)
+    print_usage ();
+  endif
+
+  ret = arg;
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_minimal_test/COPYING	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,719 @@
+Appendix G GNU GENERAL PUBLIC LICENSE
+*************************************
+
+                        Version 3, 29 June 2007
+
+     Copyright (C) 2007 Free Software Foundation, Inc. `http://fsf.org/'
+
+     Everyone is permitted to copy and distribute verbatim copies of this
+     license document, but changing it is not allowed.
+
+Preamble
+========
+
+The GNU General Public License is a free, copyleft license for software
+and other kinds of works.
+
+   The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains
+free software for all its users.  We, the Free Software Foundation, use
+the GNU General Public License for most of our software; it applies
+also to any other work released this way by its authors.  You can apply
+it to your programs, too.
+
+   When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+   To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you
+have certain responsibilities if you distribute copies of the software,
+or if you modify it: responsibilities to respect the freedom of others.
+
+   For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+   Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+   For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+   Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the
+manufacturer can do so.  This is fundamentally incompatible with the
+aim of protecting users' freedom to change the software.  The
+systematic pattern of such abuse occurs in the area of products for
+individuals to use, which is precisely where it is most unacceptable.
+Therefore, we have designed this version of the GPL to prohibit the
+practice for those products.  If such problems arise substantially in
+other domains, we stand ready to extend this provision to those domains
+in future versions of the GPL, as needed to protect the freedom of
+users.
+
+   Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+   The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS
+====================
+
+  0. Definitions.
+
+     "This License" refers to version 3 of the GNU General Public
+     License.
+
+     "Copyright" also means copyright-like laws that apply to other
+     kinds of works, such as semiconductor masks.
+
+     "The Program" refers to any copyrightable work licensed under this
+     License.  Each licensee is addressed as "you".  "Licensees" and
+     "recipients" may be individuals or organizations.
+
+     To "modify" a work means to copy from or adapt all or part of the
+     work in a fashion requiring copyright permission, other than the
+     making of an exact copy.  The resulting work is called a "modified
+     version" of the earlier work or a work "based on" the earlier work.
+
+     A "covered work" means either the unmodified Program or a work
+     based on the Program.
+
+     To "propagate" a work means to do anything with it that, without
+     permission, would make you directly or secondarily liable for
+     infringement under applicable copyright law, except executing it
+     on a computer or modifying a private copy.  Propagation includes
+     copying, distribution (with or without modification), making
+     available to the public, and in some countries other activities as
+     well.
+
+     To "convey" a work means any kind of propagation that enables other
+     parties to make or receive copies.  Mere interaction with a user
+     through a computer network, with no transfer of a copy, is not
+     conveying.
+
+     An interactive user interface displays "Appropriate Legal Notices"
+     to the extent that it includes a convenient and prominently visible
+     feature that (1) displays an appropriate copyright notice, and (2)
+     tells the user that there is no warranty for the work (except to
+     the extent that warranties are provided), that licensees may
+     convey the work under this License, and how to view a copy of this
+     License.  If the interface presents a list of user commands or
+     options, such as a menu, a prominent item in the list meets this
+     criterion.
+
+  1. Source Code.
+
+     The "source code" for a work means the preferred form of the work
+     for making modifications to it.  "Object code" means any
+     non-source form of a work.
+
+     A "Standard Interface" means an interface that either is an
+     official standard defined by a recognized standards body, or, in
+     the case of interfaces specified for a particular programming
+     language, one that is widely used among developers working in that
+     language.
+
+     The "System Libraries" of an executable work include anything,
+     other than the work as a whole, that (a) is included in the normal
+     form of packaging a Major Component, but which is not part of that
+     Major Component, and (b) serves only to enable use of the work
+     with that Major Component, or to implement a Standard Interface
+     for which an implementation is available to the public in source
+     code form.  A "Major Component", in this context, means a major
+     essential component (kernel, window system, and so on) of the
+     specific operating system (if any) on which the executable work
+     runs, or a compiler used to produce the work, or an object code
+     interpreter used to run it.
+
+     The "Corresponding Source" for a work in object code form means all
+     the source code needed to generate, install, and (for an executable
+     work) run the object code and to modify the work, including
+     scripts to control those activities.  However, it does not include
+     the work's System Libraries, or general-purpose tools or generally
+     available free programs which are used unmodified in performing
+     those activities but which are not part of the work.  For example,
+     Corresponding Source includes interface definition files
+     associated with source files for the work, and the source code for
+     shared libraries and dynamically linked subprograms that the work
+     is specifically designed to require, such as by intimate data
+     communication or control flow between those subprograms and other
+     parts of the work.
+
+     The Corresponding Source need not include anything that users can
+     regenerate automatically from other parts of the Corresponding
+     Source.
+
+     The Corresponding Source for a work in source code form is that
+     same work.
+
+  2. Basic Permissions.
+
+     All rights granted under this License are granted for the term of
+     copyright on the Program, and are irrevocable provided the stated
+     conditions are met.  This License explicitly affirms your unlimited
+     permission to run the unmodified Program.  The output from running
+     a covered work is covered by this License only if the output,
+     given its content, constitutes a covered work.  This License
+     acknowledges your rights of fair use or other equivalent, as
+     provided by copyright law.
+
+     You may make, run and propagate covered works that you do not
+     convey, without conditions so long as your license otherwise
+     remains in force.  You may convey covered works to others for the
+     sole purpose of having them make modifications exclusively for
+     you, or provide you with facilities for running those works,
+     provided that you comply with the terms of this License in
+     conveying all material for which you do not control copyright.
+     Those thus making or running the covered works for you must do so
+     exclusively on your behalf, under your direction and control, on
+     terms that prohibit them from making any copies of your
+     copyrighted material outside their relationship with you.
+
+     Conveying under any other circumstances is permitted solely under
+     the conditions stated below.  Sublicensing is not allowed; section
+     10 makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+     No covered work shall be deemed part of an effective technological
+     measure under any applicable law fulfilling obligations under
+     article 11 of the WIPO copyright treaty adopted on 20 December
+     1996, or similar laws prohibiting or restricting circumvention of
+     such measures.
+
+     When you convey a covered work, you waive any legal power to forbid
+     circumvention of technological measures to the extent such
+     circumvention is effected by exercising rights under this License
+     with respect to the covered work, and you disclaim any intention
+     to limit operation or modification of the work as a means of
+     enforcing, against the work's users, your or third parties' legal
+     rights to forbid circumvention of technological measures.
+
+  4. Conveying Verbatim Copies.
+
+     You may convey verbatim copies of the Program's source code as you
+     receive it, in any medium, provided that you conspicuously and
+     appropriately publish on each copy an appropriate copyright notice;
+     keep intact all notices stating that this License and any
+     non-permissive terms added in accord with section 7 apply to the
+     code; keep intact all notices of the absence of any warranty; and
+     give all recipients a copy of this License along with the Program.
+
+     You may charge any price or no price for each copy that you convey,
+     and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+     You may convey a work based on the Program, or the modifications to
+     produce it from the Program, in the form of source code under the
+     terms of section 4, provided that you also meet all of these
+     conditions:
+
+       a. The work must carry prominent notices stating that you
+          modified it, and giving a relevant date.
+
+       b. The work must carry prominent notices stating that it is
+          released under this License and any conditions added under
+          section 7.  This requirement modifies the requirement in
+          section 4 to "keep intact all notices".
+
+       c. You must license the entire work, as a whole, under this
+          License to anyone who comes into possession of a copy.  This
+          License will therefore apply, along with any applicable
+          section 7 additional terms, to the whole of the work, and all
+          its parts, regardless of how they are packaged.  This License
+          gives no permission to license the work in any other way, but
+          it does not invalidate such permission if you have separately
+          received it.
+
+       d. If the work has interactive user interfaces, each must display
+          Appropriate Legal Notices; however, if the Program has
+          interactive interfaces that do not display Appropriate Legal
+          Notices, your work need not make them do so.
+
+     A compilation of a covered work with other separate and independent
+     works, which are not by their nature extensions of the covered
+     work, and which are not combined with it such as to form a larger
+     program, in or on a volume of a storage or distribution medium, is
+     called an "aggregate" if the compilation and its resulting
+     copyright are not used to limit the access or legal rights of the
+     compilation's users beyond what the individual works permit.
+     Inclusion of a covered work in an aggregate does not cause this
+     License to apply to the other parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+     You may convey a covered work in object code form under the terms
+     of sections 4 and 5, provided that you also convey the
+     machine-readable Corresponding Source under the terms of this
+     License, in one of these ways:
+
+       a. Convey the object code in, or embodied in, a physical product
+          (including a physical distribution medium), accompanied by the
+          Corresponding Source fixed on a durable physical medium
+          customarily used for software interchange.
+
+       b. Convey the object code in, or embodied in, a physical product
+          (including a physical distribution medium), accompanied by a
+          written offer, valid for at least three years and valid for
+          as long as you offer spare parts or customer support for that
+          product model, to give anyone who possesses the object code
+          either (1) a copy of the Corresponding Source for all the
+          software in the product that is covered by this License, on a
+          durable physical medium customarily used for software
+          interchange, for a price no more than your reasonable cost of
+          physically performing this conveying of source, or (2) access
+          to copy the Corresponding Source from a network server at no
+          charge.
+
+       c. Convey individual copies of the object code with a copy of
+          the written offer to provide the Corresponding Source.  This
+          alternative is allowed only occasionally and noncommercially,
+          and only if you received the object code with such an offer,
+          in accord with subsection 6b.
+
+       d. Convey the object code by offering access from a designated
+          place (gratis or for a charge), and offer equivalent access
+          to the Corresponding Source in the same way through the same
+          place at no further charge.  You need not require recipients
+          to copy the Corresponding Source along with the object code.
+          If the place to copy the object code is a network server, the
+          Corresponding Source may be on a different server (operated
+          by you or a third party) that supports equivalent copying
+          facilities, provided you maintain clear directions next to
+          the object code saying where to find the Corresponding Source.
+          Regardless of what server hosts the Corresponding Source, you
+          remain obligated to ensure that it is available for as long
+          as needed to satisfy these requirements.
+
+       e. Convey the object code using peer-to-peer transmission,
+          provided you inform other peers where the object code and
+          Corresponding Source of the work are being offered to the
+          general public at no charge under subsection 6d.
+
+
+     A separable portion of the object code, whose source code is
+     excluded from the Corresponding Source as a System Library, need
+     not be included in conveying the object code work.
+
+     A "User Product" is either (1) a "consumer product", which means
+     any tangible personal property which is normally used for personal,
+     family, or household purposes, or (2) anything designed or sold for
+     incorporation into a dwelling.  In determining whether a product
+     is a consumer product, doubtful cases shall be resolved in favor of
+     coverage.  For a particular product received by a particular user,
+     "normally used" refers to a typical or common use of that class of
+     product, regardless of the status of the particular user or of the
+     way in which the particular user actually uses, or expects or is
+     expected to use, the product.  A product is a consumer product
+     regardless of whether the product has substantial commercial,
+     industrial or non-consumer uses, unless such uses represent the
+     only significant mode of use of the product.
+
+     "Installation Information" for a User Product means any methods,
+     procedures, authorization keys, or other information required to
+     install and execute modified versions of a covered work in that
+     User Product from a modified version of its Corresponding Source.
+     The information must suffice to ensure that the continued
+     functioning of the modified object code is in no case prevented or
+     interfered with solely because modification has been made.
+
+     If you convey an object code work under this section in, or with,
+     or specifically for use in, a User Product, and the conveying
+     occurs as part of a transaction in which the right of possession
+     and use of the User Product is transferred to the recipient in
+     perpetuity or for a fixed term (regardless of how the transaction
+     is characterized), the Corresponding Source conveyed under this
+     section must be accompanied by the Installation Information.  But
+     this requirement does not apply if neither you nor any third party
+     retains the ability to install modified object code on the User
+     Product (for example, the work has been installed in ROM).
+
+     The requirement to provide Installation Information does not
+     include a requirement to continue to provide support service,
+     warranty, or updates for a work that has been modified or
+     installed by the recipient, or for the User Product in which it
+     has been modified or installed.  Access to a network may be denied
+     when the modification itself materially and adversely affects the
+     operation of the network or violates the rules and protocols for
+     communication across the network.
+
+     Corresponding Source conveyed, and Installation Information
+     provided, in accord with this section must be in a format that is
+     publicly documented (and with an implementation available to the
+     public in source code form), and must require no special password
+     or key for unpacking, reading or copying.
+
+  7. Additional Terms.
+
+     "Additional permissions" are terms that supplement the terms of
+     this License by making exceptions from one or more of its
+     conditions.  Additional permissions that are applicable to the
+     entire Program shall be treated as though they were included in
+     this License, to the extent that they are valid under applicable
+     law.  If additional permissions apply only to part of the Program,
+     that part may be used separately under those permissions, but the
+     entire Program remains governed by this License without regard to
+     the additional permissions.
+
+     When you convey a copy of a covered work, you may at your option
+     remove any additional permissions from that copy, or from any part
+     of it.  (Additional permissions may be written to require their own
+     removal in certain cases when you modify the work.)  You may place
+     additional permissions on material, added by you to a covered work,
+     for which you have or can give appropriate copyright permission.
+
+     Notwithstanding any other provision of this License, for material
+     you add to a covered work, you may (if authorized by the copyright
+     holders of that material) supplement the terms of this License
+     with terms:
+
+       a. Disclaiming warranty or limiting liability differently from
+          the terms of sections 15 and 16 of this License; or
+
+       b. Requiring preservation of specified reasonable legal notices
+          or author attributions in that material or in the Appropriate
+          Legal Notices displayed by works containing it; or
+
+       c. Prohibiting misrepresentation of the origin of that material,
+          or requiring that modified versions of such material be
+          marked in reasonable ways as different from the original
+          version; or
+
+       d. Limiting the use for publicity purposes of names of licensors
+          or authors of the material; or
+
+       e. Declining to grant rights under trademark law for use of some
+          trade names, trademarks, or service marks; or
+
+       f. Requiring indemnification of licensors and authors of that
+          material by anyone who conveys the material (or modified
+          versions of it) with contractual assumptions of liability to
+          the recipient, for any liability that these contractual
+          assumptions directly impose on those licensors and authors.
+
+     All other non-permissive additional terms are considered "further
+     restrictions" within the meaning of section 10.  If the Program as
+     you received it, or any part of it, contains a notice stating that
+     it is governed by this License along with a term that is a further
+     restriction, you may remove that term.  If a license document
+     contains a further restriction but permits relicensing or
+     conveying under this License, you may add to a covered work
+     material governed by the terms of that license document, provided
+     that the further restriction does not survive such relicensing or
+     conveying.
+
+     If you add terms to a covered work in accord with this section, you
+     must place, in the relevant source files, a statement of the
+     additional terms that apply to those files, or a notice indicating
+     where to find the applicable terms.
+
+     Additional terms, permissive or non-permissive, may be stated in
+     the form of a separately written license, or stated as exceptions;
+     the above requirements apply either way.
+
+  8. Termination.
+
+     You may not propagate or modify a covered work except as expressly
+     provided under this License.  Any attempt otherwise to propagate or
+     modify it is void, and will automatically terminate your rights
+     under this License (including any patent licenses granted under
+     the third paragraph of section 11).
+
+     However, if you cease all violation of this License, then your
+     license from a particular copyright holder is reinstated (a)
+     provisionally, unless and until the copyright holder explicitly
+     and finally terminates your license, and (b) permanently, if the
+     copyright holder fails to notify you of the violation by some
+     reasonable means prior to 60 days after the cessation.
+
+     Moreover, your license from a particular copyright holder is
+     reinstated permanently if the copyright holder notifies you of the
+     violation by some reasonable means, this is the first time you have
+     received notice of violation of this License (for any work) from
+     that copyright holder, and you cure the violation prior to 30 days
+     after your receipt of the notice.
+
+     Termination of your rights under this section does not terminate
+     the licenses of parties who have received copies or rights from
+     you under this License.  If your rights have been terminated and
+     not permanently reinstated, you do not qualify to receive new
+     licenses for the same material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+     You are not required to accept this License in order to receive or
+     run a copy of the Program.  Ancillary propagation of a covered work
+     occurring solely as a consequence of using peer-to-peer
+     transmission to receive a copy likewise does not require
+     acceptance.  However, nothing other than this License grants you
+     permission to propagate or modify any covered work.  These actions
+     infringe copyright if you do not accept this License.  Therefore,
+     by modifying or propagating a covered work, you indicate your
+     acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+     Each time you convey a covered work, the recipient automatically
+     receives a license from the original licensors, to run, modify and
+     propagate that work, subject to this License.  You are not
+     responsible for enforcing compliance by third parties with this
+     License.
+
+     An "entity transaction" is a transaction transferring control of an
+     organization, or substantially all assets of one, or subdividing an
+     organization, or merging organizations.  If propagation of a
+     covered work results from an entity transaction, each party to that
+     transaction who receives a copy of the work also receives whatever
+     licenses to the work the party's predecessor in interest had or
+     could give under the previous paragraph, plus a right to
+     possession of the Corresponding Source of the work from the
+     predecessor in interest, if the predecessor has it or can get it
+     with reasonable efforts.
+
+     You may not impose any further restrictions on the exercise of the
+     rights granted or affirmed under this License.  For example, you
+     may not impose a license fee, royalty, or other charge for
+     exercise of rights granted under this License, and you may not
+     initiate litigation (including a cross-claim or counterclaim in a
+     lawsuit) alleging that any patent claim is infringed by making,
+     using, selling, offering for sale, or importing the Program or any
+     portion of it.
+
+ 11. Patents.
+
+     A "contributor" is a copyright holder who authorizes use under this
+     License of the Program or a work on which the Program is based.
+     The work thus licensed is called the contributor's "contributor
+     version".
+
+     A contributor's "essential patent claims" are all patent claims
+     owned or controlled by the contributor, whether already acquired or
+     hereafter acquired, that would be infringed by some manner,
+     permitted by this License, of making, using, or selling its
+     contributor version, but do not include claims that would be
+     infringed only as a consequence of further modification of the
+     contributor version.  For purposes of this definition, "control"
+     includes the right to grant patent sublicenses in a manner
+     consistent with the requirements of this License.
+
+     Each contributor grants you a non-exclusive, worldwide,
+     royalty-free patent license under the contributor's essential
+     patent claims, to make, use, sell, offer for sale, import and
+     otherwise run, modify and propagate the contents of its
+     contributor version.
+
+     In the following three paragraphs, a "patent license" is any
+     express agreement or commitment, however denominated, not to
+     enforce a patent (such as an express permission to practice a
+     patent or covenant not to sue for patent infringement).  To
+     "grant" such a patent license to a party means to make such an
+     agreement or commitment not to enforce a patent against the party.
+
+     If you convey a covered work, knowingly relying on a patent
+     license, and the Corresponding Source of the work is not available
+     for anyone to copy, free of charge and under the terms of this
+     License, through a publicly available network server or other
+     readily accessible means, then you must either (1) cause the
+     Corresponding Source to be so available, or (2) arrange to deprive
+     yourself of the benefit of the patent license for this particular
+     work, or (3) arrange, in a manner consistent with the requirements
+     of this License, to extend the patent license to downstream
+     recipients.  "Knowingly relying" means you have actual knowledge
+     that, but for the patent license, your conveying the covered work
+     in a country, or your recipient's use of the covered work in a
+     country, would infringe one or more identifiable patents in that
+     country that you have reason to believe are valid.
+
+     If, pursuant to or in connection with a single transaction or
+     arrangement, you convey, or propagate by procuring conveyance of, a
+     covered work, and grant a patent license to some of the parties
+     receiving the covered work authorizing them to use, propagate,
+     modify or convey a specific copy of the covered work, then the
+     patent license you grant is automatically extended to all
+     recipients of the covered work and works based on it.
+
+     A patent license is "discriminatory" if it does not include within
+     the scope of its coverage, prohibits the exercise of, or is
+     conditioned on the non-exercise of one or more of the rights that
+     are specifically granted under this License.  You may not convey a
+     covered work if you are a party to an arrangement with a third
+     party that is in the business of distributing software, under
+     which you make payment to the third party based on the extent of
+     your activity of conveying the work, and under which the third
+     party grants, to any of the parties who would receive the covered
+     work from you, a discriminatory patent license (a) in connection
+     with copies of the covered work conveyed by you (or copies made
+     from those copies), or (b) primarily for and in connection with
+     specific products or compilations that contain the covered work,
+     unless you entered into that arrangement, or that patent license
+     was granted, prior to 28 March 2007.
+
+     Nothing in this License shall be construed as excluding or limiting
+     any implied license or other defenses to infringement that may
+     otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+     If conditions are imposed on you (whether by court order,
+     agreement or otherwise) that contradict the conditions of this
+     License, they do not excuse you from the conditions of this
+     License.  If you cannot convey a covered work so as to satisfy
+     simultaneously your obligations under this License and any other
+     pertinent obligations, then as a consequence you may not convey it
+     at all.  For example, if you agree to terms that obligate you to
+     collect a royalty for further conveying from those to whom you
+     convey the Program, the only way you could satisfy both those
+     terms and this License would be to refrain entirely from conveying
+     the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+     Notwithstanding any other provision of this License, you have
+     permission to link or combine any covered work with a work licensed
+     under version 3 of the GNU Affero General Public License into a
+     single combined work, and to convey the resulting work.  The terms
+     of this License will continue to apply to the part which is the
+     covered work, but the special requirements of the GNU Affero
+     General Public License, section 13, concerning interaction through
+     a network will apply to the combination as such.
+
+ 14. Revised Versions of this License.
+
+     The Free Software Foundation may publish revised and/or new
+     versions of the GNU General Public License from time to time.
+     Such new versions will be similar in spirit to the present
+     version, but may differ in detail to address new problems or
+     concerns.
+
+     Each version is given a distinguishing version number.  If the
+     Program specifies that a certain numbered version of the GNU
+     General Public License "or any later version" applies to it, you
+     have the option of following the terms and conditions either of
+     that numbered version or of any later version published by the
+     Free Software Foundation.  If the Program does not specify a
+     version number of the GNU General Public License, you may choose
+     any version ever published by the Free Software Foundation.
+
+     If the Program specifies that a proxy can decide which future
+     versions of the GNU General Public License can be used, that
+     proxy's public statement of acceptance of a version permanently
+     authorizes you to choose that version for the Program.
+
+     Later license versions may give you additional or different
+     permissions.  However, no additional obligations are imposed on any
+     author or copyright holder as a result of your choosing to follow a
+     later version.
+
+ 15. Disclaimer of Warranty.
+
+     THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+     APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE
+     COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE
+     RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+     SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+     NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+     IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+     WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES
+     AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
+     FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+     CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
+     THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+     BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+     PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
+     THE POSSIBILITY OF SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+     If the disclaimer of warranty and limitation of liability provided
+     above cannot be given local legal effect according to their terms,
+     reviewing courts shall apply local law that most closely
+     approximates an absolute waiver of all civil liability in
+     connection with the Program, unless a warranty or assumption of
+     liability accompanies a copy of the Program in return for a fee.
+
+
+END OF TERMS AND CONDITIONS
+===========================
+
+How to Apply These Terms to Your New Programs
+=============================================
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+   To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+     ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
+     Copyright (C) YEAR NAME OF AUTHOR
+
+     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
+     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
+     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 `http://www.gnu.org/licenses/'.
+
+   Also add information on how to contact you by electronic and paper
+mail.
+
+   If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+     PROGRAM Copyright (C) YEAR NAME OF AUTHOR
+     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+     This is free software, and you are welcome to redistribute it
+     under certain conditions; type `show c' for details.
+
+   The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, your
+program's commands might be different; for a GUI interface, you would
+use an "about box".
+
+   You should also get your employer (if you work as a programmer) or
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  For more information on this, and how to apply and follow
+the GNU GPL, see `http://www.gnu.org/licenses/'.
+
+   The GNU General Public License does not permit incorporating your
+program into proprietary programs.  If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library.  If this is what you want to do, use the
+GNU Lesser General Public License instead of this License.  But first,
+please read `http://www.gnu.org/philosophy/why-not-lgpl.html'.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_minimal_test/DESCRIPTION	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,13 @@
+Name: mfile_minimal_test
+Version: 0.1.0
+Date: 2017-12-08
+Author: hopefully various authors
+Maintainer: hopefully some of those authors.
+Title: Example Minimal Package
+Description: Minimal package structure with only m-files.
+Depends: octave (>= 4.2.1)
+License: GPLv3+
+Categories: Test
+# BuildRequires:
+# SystemRequirements:
+# Url: external homepage
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/mfile_minimal_test/inst/example_mfile.m	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,36 @@
+## Copyright (C) 2017-2018 Olaf Till <i7tiol@t-online.de>
+##
+## 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 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
+## 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 <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{ret} =} example_mfile (@var{arg})
+## Placeholder for an mfile function.
+##
+## @var{arg}: argument. @var{ret}: returned value.
+##
+## Although this file is so short, a license text is contained as an
+## example.
+##
+## @seealso{example_open, example_close, example_do_something}
+## @end deftypefn
+
+function ret = example_mfile (arg)
+
+  if (nargin () != 1)
+    print_usage ();
+  endif
+
+  ret = arg;
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/module.mk	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,14 @@
+pkg_TEST_FILES = \
+    %reldir%/pkg.tst \
+    %reldir%/mfile_basic_test/INDEX \
+    %reldir%/mfile_basic_test/NEWS \
+    %reldir%/mfile_basic_test/DESCRIPTION \
+    %reldir%/mfile_basic_test/doc/macros.texi \
+    %reldir%/mfile_basic_test/doc/example-package.txi \
+    %reldir%/mfile_basic_test/COPYING \
+    %reldir%/mfile_basic_test/inst/example_mfile.m \
+    %reldir%/mfile_minimal_test/DESCRIPTION \
+    %reldir%/mfile_minimal_test/COPYING \
+    %reldir%/mfile_minimal_test/inst/example_mfile.m
+
+TEST_FILES += $(pkg_TEST_FILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/pkg/pkg.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -0,0 +1,154 @@
+## Copyright (C) 2018 JuanPi Carbajal
+##
+## 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/>.
+
+############################################################
+## Test suite for pkg.m
+## Tests are organized first by action, and then by options.
+## All actions should be tested, and ideally all options are tested.
+############################################################
+
+%!shared old_prefix, old_archprefix, old_local_list, old_global_list, prefix, restorecfg, restorecache, restoreglobalcache, rmtmpdir, mfile_pkg_name, mfile_pkg_tgz
+
+%!testif HAVE_Z
+%! ## Do all tests in a temporary directory
+%! [old_prefix, old_archprefix] = pkg ("prefix");
+%! restorecfg = onCleanup (@() pkg ("prefix", old_prefix, old_archprefix));
+%! old_local_list = pkg ("local_list");
+%! restorecache = onCleanup (@() pkg ("local_list", old_local_list));
+%! old_global_list = pkg ("global_list");
+%! restoreglobalcache = onCleanup (@() pkg ("global_list", old_global_list));
+%! prefix = tempname ();
+%! [status] = mkdir (prefix);
+%! if (! status)
+%!   error ("pkg.tst: Could not create temporary directory for pkg testing");
+%!   return;  # abort further testing
+%! endif
+%! 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"));
+%!
+%! ## Create tar.gz file packages of testing directories in prefix directory
+%! mfile_pkg_name = {"mfile_basic_test", "mfile_minimal_test"};
+%! mfile_pkg_tar = fullfile (prefix, strcat (mfile_pkg_name, ".tar"));
+%! mfile_pkg_tgz = strcat (mfile_pkg_tar, ".gz");
+%! for i = 1:numel (mfile_pkg_name)
+%!   tar (mfile_pkg_tar{i}, mfile_pkg_name{i});
+%!   gzip (mfile_pkg_tar{i});
+%! endfor
+
+## Avoids printing to stdout when installing
+%!function silent_pkg_install (varargin)
+%!  evalc (["pkg install", sprintf(" %s", varargin{:})]);
+%!endfunction
+
+## Action install/uninstall
+%!testif HAVE_Z
+%! for i = 1:numel (mfile_pkg_name)
+%!   silent_pkg_install (mfile_pkg_tgz{i});
+%!   pkg ("uninstall", mfile_pkg_name{i});
+%! endfor
+%!
+%!error pkg ("install", "nonexistent.zip")
+
+# -local
+%!testif HAVE_Z
+%! for i = 1:numel (mfile_pkg_name)
+%!   silent_pkg_install ("-local", mfile_pkg_tgz{i});
+%!   pkg ("uninstall", mfile_pkg_name{i});
+%! endfor
+
+# -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
+#%!test
+#%! silent_pkg_install ("-forge", "dataframe");
+#%! pkg ("uninstall", "dataframe");
+
+# -nodeps
+## FIXME: Need test
+
+# -verbose
+## FIXME: Need test
+
+## Action load/unload (within install/uninstall)
+%!testif HAVE_Z
+%! for i = 1:numel (mfile_pkg_name)
+%!  name = mfile_pkg_name{i};
+%!  silent_pkg_install ("-local", mfile_pkg_tgz{i});
+%!  unwind_protect
+%!    pkg ("load", name);
+%!    pkg ("unload", name);
+%!  unwind_protect_cleanup
+%!    pkg ("uninstall", name);
+%!  end_unwind_protect
+%! endfor
+%!
+%!error <package foobar is not installed> pkg ("load", "foobar");
+
+# -nodeps
+## FIXME: Need test
+
+# -verbose
+## FIXME: Need test
+
+## Action list
+%!test
+%! [user_packages, system_packages] = pkg ("list");
+
+# -forge
+#%!test
+#%! oct_forge_pkgs = pkg ("list", "-forge");
+
+## Action describe
+%!testif HAVE_Z
+%! silent_pkg_install ("-local", mfile_pkg_tgz{1});
+%! [desc, flag] = pkg ("describe", mfile_pkg_name{1});
+%! ## FIXME: this only tests that the describe command runs,
+%! ##        not that the output is in anyway correct.
+%! pkg ("uninstall", mfile_pkg_name{1});
+
+# -verbose
+## FIXME: Need test
+
+## Action prefix
+%!test
+%! pfx_old = pkg ("prefix");
+%! unwind_protect
+%!   pfx_new = pkg ("prefix", pwd ());
+%!   assert (pfx_new, pwd ());
+%! unwind_protect_cleanup
+%!   pfx = pkg ("prefix", pfx_old);
+%! end_unwind_protect
+
+## Action build
+## FIXME: Need test
+# pkg build -verbose /tmp image-*
+
+## Action rebuild
+## FIXME: Need test
+# pkg rebuild signal
+
+## Future commands
+%!error pkg ("whereis", "myfunc.m")
+%!error pkg ("whereis", "-forge", "myfunc.m")
+
+############################################################
+## End of Tests
+############################################################
--- a/test/prefer.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/prefer.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -95,8 +95,8 @@
 %! print_empty_dimensions (0);
 %! a = cell (1, 1);
 %! b = type ("-q", "a");
-%! assert (!isempty (findstr (b{1}, "[]")));
-%! assert (isempty (findstr (b{1} ,"[](0x0)")));
+%! assert (! isempty (strfind (b{1}, "[]")));
+%! assert (isempty (strfind (b{1} ,"[](0x0)")));
 %! print_empty_dimensions (ped);
 
 %!test
@@ -104,7 +104,7 @@
 %! print_empty_dimensions (1);
 %! a = cell (1, 1);
 %! b = type ("-q", "a");
-%! assert (!isempty (findstr (b{1}, "[](0x0)")));
+%! assert (! isempty (strfind (b{1}, "[](0x0)")));
 %! print_empty_dimensions (ped);
 
 %!assert (all (size (inv ([])) == [0, 0]))
--- a/test/range.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/range.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -107,11 +107,52 @@
 %!assert (signbit (sort (r, "descend")), logical ([0 0 0 1]))
 %!assert (signbit (sort (rrev, "ascend")), logical ([1 0 0 0]))
 
+## Test mathematical operations (also, non-finite values and 0)
+%!shared r
+%! r = 1:5;
+
+%!assert (-r, -1:-1:-5)
+%!assert (1 + r, 2:6)
+%!assert (Inf + r, Inf (1,5))
+%!assert (NaN + r, NaN (1,5))
+%!assert (r + 1, 2:6)
+%!assert (r + Inf, Inf (1,5))
+%!assert (r + NaN, NaN (1,5))
+%!assert (1 - r, 0:-1:-4)
+%!assert (Inf - r, Inf (1,5))
+%!assert (NaN - r, NaN (1,5))
+%!assert (r - 1, 0:4)
+%!assert (r - Inf, -Inf (1,5))
+%!assert (r - NaN, NaN (1,5))
+%!assert (2 * r, 2:2:10)
+%!assert (0 * r, zeros (1,5))
+%!assert (Inf * r, Inf (1,5))
+%!assert (NaN * r, NaN (1,5))
+%!assert (r * 2, 2:2:10)
+%!assert (r * 0, zeros (1,5))
+%!assert (r * Inf, Inf (1,5))
+%!assert (r * NaN, NaN (1,5))
+
 ## Test sorting of ranges (bug #45739)
-
 %!shared r, rrev
 %! r = 1:2:10;
 %! rrev = 10:-2:1;
 
-%!assert (sort (r, "descend"), [9 7 5 3 1])
-%!assert (sort (rrev, "ascend"), [2 4 6 8 10])
+%!assert <*45739> (sort (r, "descend"), [9 7 5 3 1])
+%!assert <*45739> (sort (rrev, "ascend"), [2 4 6 8 10])
+
+## Test final value within eps of an integer (bug #46859)
+%!test <*46859>
+%! rng = 1 : (1001/250)/(1/250);
+%! assert (rng(end), 1001);
+
+%!test <*46859>
+%! rng = 2000: -1 : (1001/250)/(1/250);
+%! assert (rng(end), 1001);
+
+## This is not Matlab compatible (stops at 1000 with 999 elements)
+## Octave prefers the more intuitive "pure math" approach where
+## (1001/250) / (1/250) => (1001/250)*(250/1) => 1001.
+%!test <*46859>
+%! rng = 1 : (1001/250)/(1/250);
+%! assert (numel (1000));
--- a/test/unwind.tst	Tue Dec 04 10:12:41 2018 -0800
+++ b/test/unwind.tst	Thu Dec 20 17:18:56 2018 -0500
@@ -55,3 +55,4 @@
 %!test
 %! global g = -1;
 %! fail ("y = f (3);", "mismatch");
+%! clear -global g;  # cleanup after test