changeset 24491:d8fb16ab0992

maint: move non-numeric m-files from general/ to miscellaneous/ dir. * scripts/miscellaneous/fieldnames.m, scripts/miscellaneous/grabcode.m, scripts/miscellaneous/inputParser.m, scripts/miscellaneous/isdir.m, scripts/miscellaneous/loadobj.m, scripts/miscellaneous/methods.m, scripts/miscellaneous/nargchk.m, scripts/miscellaneous/narginchk.m, scripts/miscellaneous/nargoutchk.m, scripts/miscellaneous/nthargout.m, scripts/miscellaneous/private/__publish_html_output__.m, scripts/miscellaneous/private/__publish_latex_output__.m, scripts/miscellaneous/publish.m, scripts/miscellaneous/saveobj.m, scripts/miscellaneous/validateattributes.m: Moved from scripts/general dir. * scripts/general/module.mk, scripts/miscellaneous/module.mk: Update build system.
author Rik <rik@octave.org>
date Thu, 28 Dec 2017 16:14:37 -0800
parents e8d0573279b2
children c83e37384b4f
files scripts/general/fieldnames.m scripts/general/grabcode.m scripts/general/inputParser.m scripts/general/isdir.m scripts/general/loadobj.m scripts/general/methods.m scripts/general/module.mk scripts/general/nargchk.m scripts/general/narginchk.m scripts/general/nargoutchk.m scripts/general/nthargout.m scripts/general/private/__publish_html_output__.m scripts/general/private/__publish_latex_output__.m scripts/general/publish.m scripts/general/saveobj.m scripts/general/validateattributes.m scripts/miscellaneous/fieldnames.m scripts/miscellaneous/grabcode.m scripts/miscellaneous/inputParser.m scripts/miscellaneous/isdir.m scripts/miscellaneous/loadobj.m scripts/miscellaneous/methods.m scripts/miscellaneous/module.mk scripts/miscellaneous/nargchk.m scripts/miscellaneous/narginchk.m scripts/miscellaneous/nargoutchk.m scripts/miscellaneous/nthargout.m scripts/miscellaneous/private/__publish_html_output__.m scripts/miscellaneous/private/__publish_latex_output__.m scripts/miscellaneous/publish.m scripts/miscellaneous/saveobj.m scripts/miscellaneous/validateattributes.m
diffstat 32 files changed, 4151 insertions(+), 4151 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/general/fieldnames.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-## Copyright (C) 2012-2017 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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{names} =} fieldnames (@var{struct})
-## @deftypefnx {} {@var{names} =} fieldnames (@var{obj})
-## @deftypefnx {} {@var{names} =} fieldnames (@var{javaobj})
-## @deftypefnx {} {@var{names} =} fieldnames ("@var{javaclassname}")
-## Return a cell array of strings with the names of the fields in the
-## specified input.
-##
-## When the input is a structure @var{struct}, the names are the elements of
-## the structure.
-##
-## When the input is an Octave object @var{obj}, the names are the public
-## properties of the object.
-##
-## When the input is a Java object @var{javaobj} or a string containing the
-## name of a Java class @var{javaclassname}, the names are the public fields
-## (data members) of the object or class.
-## @seealso{numfields, isfield, orderfields, struct, methods}
-## @end deftypefn
-
-function names = fieldnames (obj)
-
-  if (nargin != 1)
-    print_usage ();
-  endif
-
-  if (isstruct (obj) || isobject (obj))
-    ## Call internal C++ function for structs or Octave objects
-    names = __fieldnames__ (obj);
-  elseif (isjava (obj) || ischar (obj))
-    ## FIXME: Function prototype that accepts java obj exists, but doesn't
-    ##        work if obj is java.lang.String.  Convert obj to classname.
-    ## FIXME: this is now working for objects whose class is in the dynamic
-    ##        classpath but will continue to fail if such classnames are used
-    ##        instead (see bug #42710).
-    if (isa (obj, "java.lang.String"))
-      obj = class (obj);
-    endif
-    names_str = javaMethod ("getFields", "org.octave.ClassHelper", obj);
-    names = ostrsplit (names_str, ';');
-  else
-    error ("fieldnames: Invalid input argument");
-  endif
-
-endfunction
-
-
-## test preservation of fieldname order
-%!test
-%! x(3).d=1;  x(2).a=2;  x(1).b=3;  x(2).c=3;
-%! assert (fieldnames (x), {"d"; "a"; "b"; "c"});
-
-## test empty structure
-%!test
-%! s = struct ();
-%! assert (fieldnames (s), cell (0, 1));
-
-## test Java classname by passing classname
-%!testif HAVE_JAVA; usejava ("jvm")
-%! names = fieldnames ("java.lang.Double");
-%! assert (any (strcmp (names, "MAX_VALUE")));
-
-## test Java classname by passing java object
-%!testif HAVE_JAVA; usejava ("jvm")
-%! names = fieldnames (javaObject ("java.lang.Double", 10));
-%! assert (any (strcmp (names, "MAX_VALUE")));
-%! assert (all (ismember ({"POSITIVE_INFINITY", "NEGATIVE_INFINITY", ...
-%!                         "NaN", "MAX_VALUE", "MIN_NORMAL", "MIN_VALUE", ...
-%!                         "MAX_EXPONENT", "MIN_EXPONENT", "SIZE", "TYPE"},
-%!                        names)));
-
-%!testif HAVE_JAVA; usejava ("jvm")
-%! names = fieldnames (javaObject ("java.lang.String", "Hello"));
-%! assert (any (strcmp (names, "CASE_INSENSITIVE_ORDER")));
--- a/scripts/general/grabcode.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-## Copyright (C) 2016-2017 Kai T. Ohlhus <k.ohlhus@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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {} grabcode (@var{url})
-## @deftypefnx {} {} grabcode (@var{filename})
-## @deftypefnx {} {@var{code_str} =} grabcode (@dots{})
-##
-## Grab the code from a report created by the @code{publish} function.
-##
-## The grabbed code inside the published report must be enclosed by the
-## strings @samp{##### SOURCE BEGIN #####} and @samp{##### SOURCE END #####}.
-## The @code{publish} function creates this format automatically.
-##
-## If no return value is requested the code is saved to a temporary file and
-## opened in the default editor.  NOTE: The temporary file must be saved under
-## a new or the code will be lost.
-##
-## If an output is requested the grabbed code will be returned as string
-## @var{code_str}.
-##
-## Example:
-##
-## @example
-## @group
-## publish ("my_script.m");
-## grabcode ("html/my_script.html");
-## @end group
-## @end example
-##
-## The example above publishes @file{my_script.m} to the default location
-## @file{html/my_script.html}.  Next, the published Octave script is grabbed to
-## edit its content in a new temporary file.
-##
-## @seealso{publish}
-## @end deftypefn
-
-function code_str = grabcode (url)
-
-  if (nargin != 1)
-    print_usage ();
-  endif
-
-  if (exist (url) == 2)
-    ## URL is a local file
-    oct_code = fileread (url);
-  else
-    ## Otherwise, try to read remote URL
-    [oct_code, success, message] = urlread (url);
-    if (! success)
-      error (["grabcode: " message]);
-    endif
-  endif
-
-  ## Extract relevant part
-  oct_code = regexp (oct_code, ...
-    '##### SOURCE BEGIN #####\n(.*)##### SOURCE END #####', "once", "tokens");
-  oct_code = oct_code{1};
-
-  if (nargout == 1)
-    code_str = oct_code;
-  else
-    ## Open temporary file in editor
-    fname = [tempname() ".m"];
-    fid = fopen (fname, "w");
-    if (fid < 0)
-      error ("grabcode: could not open temporary file");
-    endif
-    fprintf (fid, "%s", oct_code);
-    fclose (fid);
-    edit (fname);
-    warndlg (["grabcode: Make sure to save the temporary file\n\n\t", ...
-              fname, "\n\nto a location of your choice. ", ...
-              "Otherwise all grabbed code will be lost!"]);
-  endif
-
-endfunction
-
-
-## Test input validation
-%!error grabcode ()
-%!error grabcode (1,2)
--- a/scripts/general/inputParser.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,826 +0,0 @@
-## Copyright (C) 2011-2017 Carnë Draug
-##
-## 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{p} =} inputParser ()
-## Create object @var{p} of the inputParser class.
-##
-## This class is designed to allow easy parsing of function arguments.  The
-## class supports four types of arguments:
-##
-## @enumerate
-## @item mandatory (see @command{addRequired});
-##
-## @item optional (see @command{addOptional});
-##
-## @item named (see @command{addParameter});
-##
-## @item switch (see @command{addSwitch}).
-## @end enumerate
-##
-## After defining the function API with these methods, the supplied arguments
-## can be parsed with the @command{parse} method and the parsing results
-## accessed with the @command{Results} accessor.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.Parameters
-## Return list of parameter names already defined.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.Results
-## Return structure with argument names as fieldnames and corresponding values.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.Unmatched
-## Return structure similar to @command{Results}, but for unmatched parameters.
-## See the @command{KeepUnmatched} property.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.UsingDefaults
-## Return cell array with the names of arguments that are using default values.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.CaseSensitive = @var{boolean}
-## Set whether matching of argument names should be case sensitive.  Defaults
-## to false.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.FunctionName = @var{name}
-## Set function name to be used in error messages; Defaults to empty string.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.KeepUnmatched = @var{boolean}
-## Set whether an error should be given for non-defined arguments.  Defaults to
-## false.  If set to true, the extra arguments can be accessed through
-## @code{Unmatched} after the @code{parse} method.  Note that since
-## @command{Switch} and @command{Parameter} arguments can be mixed, it is
-## not possible to know the unmatched type.  If argument is found unmatched
-## it is assumed to be of the @command{Parameter} type and it is expected to
-## be followed by a value.
-##
-## @end deftypefn
-## @deftypefn {} {} inputParser.StructExpand = @var{boolean}
-## Set whether a structure can be passed to the function instead of
-## parameter/value pairs.  Defaults to true.
-##
-## The following example shows how to use this class:
-##
-## @example
-## @group
-## function check (varargin)
-## @c The next two comments need to be indented by one for alignment
-##   p = inputParser ();                      # create object
-##   p.FunctionName = "check";                # set function name
-##   p.addRequired ("pack", @@ischar);         # mandatory argument
-##   p.addOptional ("path", pwd(), @@ischar);  # optional argument
-##
-##   ## create a function handle to anonymous functions for validators
-##   val_mat = @@(x) isvector (x) && all (x <= 1) && all (x >= 0);
-##   p.addOptional ("mat", [0 0], val_mat);
-##
-##   ## create two arguments of type "Parameter"
-##   val_type = @@(x) any (strcmp (x, @{"linear", "quadratic"@}));
-##   p.addParameter ("type", "linear", val_type);
-##   val_verb = @@(x) any (strcmp (x, @{"low", "medium", "high"@}));
-##   p.addParameter ("tolerance", "low", val_verb);
-##
-##   ## create a switch type of argument
-##   p.addSwitch ("verbose");
-##
-##   p.parse (varargin@{:@});  # Run created parser on inputs
-##
-##   ## the rest of the function can access inputs by using p.Results.
-##   ## for example, get the tolerance input with p.Results.tolerance
-## endfunction
-## @end group
-## @end example
-##
-## @example
-## @group
-## check ("mech");           # valid, use defaults for other arguments
-## check ();                 # error, one argument is mandatory
-## check (1);                # error, since ! ischar
-## check ("mech", "~/dev");  # valid, use defaults for other arguments
-##
-## check ("mech", "~/dev", [0 1 0 0], "type", "linear");  # valid
-##
-## ## following is also valid.  Note how the Switch argument type can
-## ## be mixed into or before the Parameter argument type (but it
-## ## must still appear after any Optional argument).
-## check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high");
-##
-## ## following returns an error since not all optional arguments,
-## ## `path' and `mat', were given before the named argument `type'.
-## check ("mech", "~/dev", "type", "linear");
-## @end group
-## @end example
-##
-## @emph{Note 1}: A function can have any mixture of the four API types but
-## they must appear in a specific order.  @command{Required} arguments must be
-## first and can be followed by any @command{Optional} arguments.  Only
-## the @command{Parameter} and @command{Switch} arguments may be mixed
-## together and they must appear at the end.
-##
-## @emph{Note 2}: If both @command{Optional} and @command{Parameter} arguments
-## are mixed in a function API then once a string Optional argument fails to
-## validate it will be considered the end of the @command{Optional}
-## arguments.  The remaining arguments will be compared against any
-## @command{Parameter} or @command{Switch} arguments.
-##
-## @seealso{nargin, validateattributes, validatestring, varargin}
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn  {} {} addOptional (@var{argname}, @var{default})
-## @deftypefnx {} {} addOptional (@var{argname}, @var{default}, @var{validator})
-## Add new optional argument to the object @var{parser} of the class
-## inputParser to implement an ordered arguments type of API
-##
-## @var{argname} must be a string with the name of the new argument.  The order
-## in which new arguments are added with @command{addOptional}, represents the
-## expected order of arguments.
-##
-## @var{default} will be the value used when the argument is not specified.
-##
-## @var{validator} is an optional anonymous function to validate the given
-## values for the argument with name @var{argname}.  Alternatively, a
-## function name can be used.
-##
-## See @command{help inputParser} for examples.
-##
-## @emph{Note}: if a string argument does not validate, it will be considered a
-## ParamValue key.  If an optional argument is not given a validator, anything
-## will be valid, and so any string will be considered will be the value of the
-## optional argument (in @sc{matlab}, if no validator is given and argument is
-## a string it will also be considered a ParamValue key).
-##
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn  {} {} addParameter (@var{argname}, @var{default})
-## @deftypefnx {} {} addParameter (@var{argname}, @var{default}, @var{validator})
-## Add new parameter to the object @var{parser} of the class inputParser to
-## implement a name/value pair type of API.
-##
-## @var{argname} must be a string with the name of the new parameter.
-##
-## @var{default} will be the value used when the parameter is not specified.
-##
-## @var{validator} is an optional function handle to validate the given values
-## for the parameter with name @var{argname}.  Alternatively, a function name
-## can be used.
-##
-## See @command{help inputParser} for examples.
-##
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn  {} {} addParamValue (@var{argname}, @var{default})
-## @deftypefnx {} {} addParamValue (@var{argname}, @var{default}, @var{validator})
-## Add new parameter to the object @var{parser} of the class inputParser to
-## implement a name/value pair type of API.
-##
-## This is an alias for @command{addParameter} method without the
-## @qcode{"PartialMatchPriority"} option.  See it for the help text.
-##
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn  {} {} addRequired (@var{argname})
-## @deftypefnx {} {} addRequired (@var{argname}, @var{validator})
-## Add new mandatory argument to the object @var{parser} of inputParser class.
-##
-## This method belongs to the inputParser class and implements an ordered
-## arguments type of API.
-##
-## @var{argname} must be a string with the name of the new argument.  The order
-## in which new arguments are added with @command{addrequired}, represents the
-## expected order of arguments.
-##
-## @var{validator} is an optional function handle to validate the given values
-## for the argument with name @var{argname}.  Alternatively, a function name
-## can be used.
-##
-## See @command{help inputParser} for examples.
-##
-## @emph{Note}: this can be used together with the other type of arguments but
-## it must be the first (see @command{@@inputParser}).
-##
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn {} {} addSwitch (@var{argname})
-## Add new switch type of argument to the object @var{parser} of inputParser
-## class.
-##
-## This method belongs to the inputParser class and implements a switch
-## arguments type of API.
-##
-## @var{argname} must be a string with the name of the new argument.  Arguments
-## of this type can be specified at the end, after @code{Required} and
-## @code{Optional}, and mixed between the @code{Parameter}.  They default to
-## false.  If one of the arguments supplied is a string like @var{argname},
-## then after parsing the value of @var{parse}.Results.@var{argname} will be
-## true.
-##
-## See @command{help inputParser} for examples.
-##
-## @end deftypefn
-
-## -*- texinfo -*-
-## @deftypefn {} {} parse (@var{varargin})
-## Parses and validates list of arguments according to object @var{parser} of
-## the class inputParser.
-##
-## After parsing, the results can be accessed with the @command{Results}
-## accessor.  See @command{help inputParser} for a more complete description.
-##
-## @end deftypefn
-
-## Author: Carnë Draug <carandraug@octave.org>
-
-classdef inputParser < handle
-  properties
-    ## FIXME: set input checking for these properties
-    CaseSensitive = false;
-    FunctionName  = "";
-    KeepUnmatched = false;
-    PartialMatching = false; # FIXME: unimplemented (and default should be true)
-    StructExpand    = true;
-  endproperties
-
-  properties (SetAccess = protected)
-    Parameters    = cell ();
-    Results       = struct ();
-    Unmatched     = struct ();
-    UsingDefaults = cell ();
-  endproperties
-
-  properties (Access = protected)
-    ## Since Required and Optional are ordered, they get a cell array of
-    ## structs with the fields "name", "def" (default), and "val" (validator).
-    Required = cell ();
-    Optional = cell ();
-    ## Parameter and Switch are unordered so we have a struct whose fieldnames
-    ## are the argname, and values are a struct with fields "def" and "val"
-    Parameter = struct ();
-    Switch    = struct ();
-
-    ## List of Parameter and Switch names to ease searches
-    ParameterNames = cell ();
-    SwitchNames    = cell ();
-
-    ## When checking for fieldnames in a Case Insensitive way, this variable
-    ## holds the correct identifier for the last searched named using the
-    ## is_argname method.
-    last_name = "";
-  endproperties
-
-  properties (Access = protected, Constant = true)
-    ## Default validator, always returns scalar true.
-    def_val = @() true;
-  endproperties
-
-  methods
-    function set.PartialMatching (this, val)
-      if (val)
-        error ("inputParser: PartialMatching is not yet implemented");
-      endif
-    endfunction
-
-    function addRequired (this, name, val = inputParser.def_val)
-      if (nargin < 2 || nargin > 3)
-        print_usage ();
-      elseif (numel (this.Optional) || numfields (this.Parameter)
-              || numfields (this.Switch))
-        error (["inputParser.addRequired: can't have a Required argument " ...
-                "after Optional, Parameter, or Switch"]);
-      endif
-      this.validate_name ("Required", name);
-      this.Required{end+1} = struct ("name", name, "val", val);
-    endfunction
-
-    function addOptional (this, name, def, val = inputParser.def_val)
-      if (nargin < 3 || nargin > 4)
-        print_usage ();
-      elseif (numfields (this.Parameter) || numfields (this.Switch))
-        error (["inputParser.Optional: can't have Optional arguments " ...
-                "after Parameter or Switch"]);
-      endif
-      this.validate_name ("Optional", name);
-      this.Optional{end+1} = struct ("name", name, "def", def, "val", val);
-    endfunction
-
-    function addParamValue (this, name, def, val = inputParser.def_val)
-      if (nargin < 3 || nargin > 4)
-        print_usage ();
-      endif
-      this.addParameter (name, def, val);
-    endfunction
-
-    function addParameter (this, name, def, varargin)
-      if (nargin < 3 || nargin > 6)
-        print_usage ();
-      endif
-
-      n_opt = numel (varargin);
-
-      if (n_opt == 0 || n_opt == 2)
-        val = inputParser.def_val;
-      else # n_opt is 1 or 3
-        val = varargin{1};
-      endif
-
-      if (n_opt == 0 || n_opt == 1)
-        match_priority = 1;
-      else # n_opt is 2 or 3
-        if (! strcmpi (varargin{end-1}, "PartialMatchPriority"))
-          error ("inputParser.addParameter: unrecognized option");
-        endif
-        match_priority = varargin{end};
-        validateattributes (match_priority, {"numeric"}, {"positive", "integer"},
-                            "inputParser.addParameter",
-                            "PartialMatchPriority");
-      endif
-
-      this.validate_name ("Parameter", name);
-      this.Parameter.(name).def = def;
-      this.Parameter.(name).val = val;
-    endfunction
-
-    function addSwitch (this, name)
-      if (nargin != 2)
-        print_usage ();
-      endif
-      this.validate_name ("Switch", name);
-      this.Switch.(name).def = false;
-    endfunction
-
-    function parse (this, varargin)
-      this.Results = struct ();
-      this.Unmatched = struct ();
-      this.UsingDefaults = cell ();
-      if (numel (varargin) < numel (this.Required))
-        if (this.FunctionName)
-          print_usage (this.FunctionName);
-        else
-          this.error ("inputParser.parse: not enough input arguments");
-        endif
-      endif
-      pnargin = numel (varargin);
-
-      this.ParameterNames = fieldnames (this.Parameter);
-      this.SwitchNames    = fieldnames (this.Switch);
-
-      ## Evaluate the Required arguments first
-      nReq = numel (this.Required);
-      for idx = 1:nReq
-        req = this.Required{idx};
-        this.validate_arg (req.name, req.val, varargin{idx});
-      endfor
-
-      vidx = nReq;  # current index in varargin
-
-      ## Search for a list of Optional arguments
-      idx  = 0;     # current index on the array of Optional
-      nOpt = numel (this.Optional);
-      while (vidx < pnargin && idx < nOpt)
-        opt = this.Optional{++idx};
-        in  = varargin{++vidx};
-        if ((this.is_argname ("Parameter", in) && vidx < pnargin)
-            || this.is_argname ("Switch", in))
-          ## This looks like an optional parameter/value pair or a
-          ## switch, not an positional option.  This does mean that
-          ## positional options cannot be strings named like parameter
-          ## keys.  See bug #50752.
-          idx -= 1;
-          vidx -= 1;
-          break
-        endif
-        try
-          valid_option = opt.val (in);
-        catch
-          valid_option = false;
-        end_try_catch
-        if (! valid_option)
-          ## If it does not match there's two options:
-          ##    1) input is actually wrong and we should error;
-          ##    2) it's a Parameter or Switch name and we should use
-          ##       the default for the rest;
-          ##    3) it's a struct with the Parameter pairs.
-          if (ischar (in) || (this.StructExpand && isstruct (in)
-                              && isscalar (in)))
-            idx -= 1;
-            vidx -= 1;
-            break
-          else
-            this.error (sprintf (["failed validation of %s\n", ...
-                                  "Validation function: %s"],
-                                 toupper (opt.name), disp(opt.val)));
-          endif
-        endif
-        this.Results.(opt.name) = in;
-      endwhile
-
-      ## Fill in with defaults of missing Optional
-      while (idx++ < nOpt)
-        opt = this.Optional{idx};
-        this.UsingDefaults{end+1} = opt.name;
-        this.Results.(opt.name) = opt.def;
-      endwhile
-
-      ## Search unordered Options (Switch and Parameter)
-      while (vidx++ < pnargin)
-        name = varargin{vidx};
-
-        if (this.StructExpand && isstruct (name) && isscalar (name))
-          expanded_options = [fieldnames(name) struct2cell(name)]'(:);
-          n_new_args = numel (expanded_options) -1;
-          pnargin += n_new_args;
-          varargin(vidx+n_new_args+1:pnargin) = varargin(vidx+1:end);
-          varargin(vidx:vidx+n_new_args) = expanded_options;
-          name = varargin{vidx};
-        endif
-
-        if (! ischar (name))
-          this.error ("non-string for Parameter name or Switch");
-        endif
-
-        if (this.is_argname ("Parameter", name))
-          if (vidx++ > pnargin)
-            this.error (sprintf ("no matching value for option '%s'",
-                                 toupper (name)));
-          endif
-          this.validate_arg (this.last_name,
-                             this.Parameter.(this.last_name).val,
-                             varargin{vidx});
-        elseif (this.is_argname ("Switch", name))
-          this.Results.(this.last_name) = true;
-        else
-          if (vidx++ < pnargin && this.KeepUnmatched)
-            this.Unmatched.(name) = varargin{vidx};
-          else
-            this.error (sprintf ("argument '%s' is not a valid parameter",
-                                 toupper (name)));
-          endif
-        endif
-      endwhile
-      ## Add them to the UsingDefaults list
-      this.add_missing ("Parameter");
-      this.add_missing ("Switch");
-
-    endfunction
-
-    function disp (this)
-      if (nargin != 1)
-        print_usage ();
-      endif
-      printf ("inputParser object with properties:\n\n");
-      b2s = @(x) ifelse (any (x), "true", "false");
-      printf (["   CaseSensitive   : %s\n   FunctionName    : %s\n" ...
-               "   KeepUnmatched   : %s\n   PartialMatching : %s\n" ...
-               "   StructExpand    : %s\n\n"],
-               b2s (this.CaseSensitive), b2s (this.FunctionName),
-               b2s (this.KeepUnmatched), b2s (this.PartialMatching),
-               b2s (this.StructExpand));
-      printf ("Defined parameters:\n\n   {%s}\n",
-              strjoin (this.Parameters, ", "));
-    endfunction
-  endmethods
-
-  methods (Access = private)
-    function validate_name (this, type, name)
-      if (! isvarname (name))
-        error ("inputParser.add%s: NAME is an invalid identifier", method);
-      elseif (any (strcmpi (this.Parameters, name)))
-        ## Even if CaseSensitive is "on", we still shouldn't allow
-        ## two args with the same name.
-        error ("inputParser.add%s: argname '%s' has already been specified",
-               type, name);
-      endif
-      this.Parameters{end+1} = name;
-    endfunction
-
-    function validate_arg (this, name, val, in)
-        if (! val (in))
-          this.error (sprintf ("failed validation of %s with %s",
-                               toupper (name), func2str (val)));
-        endif
-        this.Results.(name) = in;
-    endfunction
-
-    function r = is_argname (this, type, name)
-      if (this.CaseSensitive)
-        r = isfield (this.(type), name);
-        this.last_name = name;
-      else
-        fnames = this.([type "Names"]);
-        l = strcmpi (name, fnames);
-        r = any (l(:));
-        if (r)
-          this.last_name = fnames{l};
-        endif
-      endif
-    endfunction
-
-    function add_missing (this, type)
-      unmatched = setdiff (fieldnames (this.(type)), fieldnames (this.Results));
-      for namec = unmatched(:)'
-        name = namec{1};
-        this.UsingDefaults{end+1} = name;
-        this.Results.(name) = this.(type).(name).def;
-      endfor
-    endfunction
-
-    function error (this, msg)
-      where = "";
-      if (this.FunctionName)
-        where = [this.FunctionName ": "];
-      endif
-      error ("%s%s", where, msg);
-    endfunction
-  endmethods
-
-endclassdef
-
-%!function p = create_p ()
-%!  p = inputParser ();
-%!  p.CaseSensitive = true;
-%!  p.addRequired ("req1", @(x) ischar (x));
-%!  p.addOptional ("op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
-%!  p.addOptional ("op2", 78, @(x) x > 50);
-%!  p.addSwitch ("verbose");
-%!  p.addParameter ("line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
-%!endfunction
-
-## check normal use, only required are given
-%!test
-%! p = create_p ();
-%! p.parse ("file");
-%! r = p.Results;
-%! assert (r.req1, "file");
-%! assert (sort (p.UsingDefaults), sort ({"op1", "op2", "verbose", "line"}));
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "val", 78,    false,     "tree"});
-
-## check normal use, but give values different than defaults
-%!test
-%! p = create_p ();
-%! p.parse ("file", "foo", 80, "line", "circle", "verbose");
-%! r = p.Results;
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "foo", 80,    true,      "circle"});
-
-## check optional is skipped and considered Parameter if unvalidated string
-%!test
-%! p = create_p ();
-%! p.parse ("file", "line", "circle");
-%! r = p.Results;
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "val", 78,    false,     "circle"});
-
-## check case insensitivity
-%!test
-%! p = create_p ();
-%!  p.CaseSensitive = false;
-%! p.parse ("file", "foo", 80, "LiNE", "circle", "vERbOSe");
-%! r = p.Results;
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "foo", 80,    true,      "circle"});
-
-## check KeepUnmatched
-%!test
-%! p = create_p ();
-%! p.KeepUnmatched = true;
-%! p.parse ("file", "foo", 80, "line", "circle", "verbose", "extra", 50);
-%! assert (p.Unmatched.extra, 50);
-
-## check error when missing required
-%!error <not enough input arguments>
-%! p = create_p ();
-%! p.parse ();
-
-## check error when given required does not validate
-%!error <failed validation of >
-%! p = create_p ();
-%! p.parse (50);
-
-## check error when given optional does not validate
-%!error <is not a valid parameter>
-%! p = create_p ();
-%! p.parse ("file", "no-val");
-
-## check error when given Parameter does not validate
-%!error <failed validation of >
-%! p = create_p ();
-%! p.parse ("file", "foo", 51, "line", "round");
-
-## check alternative method (obj, ...) API
-%!function p2 = create_p2 ();
-%!  p2 = inputParser;
-%!  addRequired (p2, "req1", @(x) ischar (x));
-%!  addOptional (p2, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
-%!  addOptional (p2, "op2", 78, @(x) x > 50);
-%!  addSwitch (p2, "verbose");
-%!  addParameter (p2, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
-%!endfunction
-
-## check normal use, only required are given
-%!test
-%! p2 = create_p2 ();
-%! parse (p2, "file");
-%! r = p2.Results;
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "val", 78,    false,     "tree"});
-%! assert (sort (p2.UsingDefaults), sort ({"op1", "op2", "verbose", "line"}));
-
-## check normal use, but give values different than defaults
-%!test
-%! p2 = create_p2 ();
-%! parse (p2, "file", "foo", 80, "line", "circle", "verbose");
-%! r = p2.Results;
-%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
-%!         {"file", "foo", 80,    true,      "circle"});
-
-## We must not perform validation of default values
-%!test <*45837>
-%! p = inputParser;
-%! p.addParameter ("Dir", [], @ischar);
-%! p.parse ();
-%! assert (p.Results.Dir, []);
-
-%!test
-%! p = inputParser;
-%! p.addParameter ("positive", -1, @(x) x > 5);
-%! p.parse ();
-%! assert (p.Results.positive, -1);
-
-## Throw an error on validation of optional argument to check that it
-## is caught without preventing continuation into param/value pairs.
-%!test
-%! p = inputParser ();
-%! p.addOptional ("err", "foo", @error);
-%! p.addParameter ("not_err", "bar", @ischar);
-%! p.parse ("not_err", "qux");
-%! assert (p.Results.err, "foo")
-%! assert (p.Results.not_err, "qux")
-
-
-## With more Parameters to test StructExpand
-%!function p3 = create_p3 ();
-%!  p3 = inputParser;
-%!  addOptional (p3, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
-%!  addOptional (p3, "op2", 78, @(x) x > 50);
-%!  addSwitch (p3, "verbose");
-%!  addParameter (p3, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
-%!  addParameter (p3, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
-%!  addParameter (p3, "style", "tt", @(x) any (strcmp (x, {"tt", "f", "i"})));
-%!endfunction
-
-## Test StructExpand
-%!test
-%! p3 = create_p3 ();
-%! p3.parse (struct ("line", "circle", "color", "green"));
-%! assert (p3.Results, struct ("op1", "val", "op2", 78, "verbose", false,
-%!                             "line", "circle", "color", "green",
-%!                             "style", "tt"))
-
-%!test
-%! p3 = create_p3 ();
-%! p3.parse (struct ("line", "circle", "color", "green"), "line", "tree");
-%! assert (p3.Results.line, "tree")
-%! p3.parse ("line", "tree", struct ("line", "circle", "color", "green"));
-%! assert (p3.Results.line, "circle")
-
-%!test # unmatched parameters with StructExpand
-%! p3 = create_p3 ();
-%! p3.KeepUnmatched = true;
-%! p3.parse (struct ("line", "circle", "color", "green", "bar", "baz"));
-%! assert (p3.Unmatched.bar, "baz")
-
-## The validation for the second optional argument throws an error with
-## a struct so check that we can handle it.
-%!test
-%! p3 = create_p3 ();
-%! p3.parse ("foo", struct ("color", "green"), "line", "tree");
-%! assert (p3.Results.op1, "foo")
-%! assert (p3.Results.line, "tree")
-%! assert (p3.Results.color, "green")
-%! assert (p3.Results.verbose, false)
-
-
-## Some simple tests for addParamValue since all the other ones use add
-## addParameter but they use the same codepath.
-%!test
-%! p = inputParser;
-%! addParameter (p, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
-%! addParameter (p, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
-%! p.parse ("line", "circle");
-%! assert ({p.Results.line, p.Results.color}, {"circle", "red"})
-
-%!test
-%! p = inputParser;
-%! p.addParameter ("foo", "bar", @ischar);
-%! p.parse ();
-%! assert (p.Results, struct ("foo", "bar"))
-%! p.parse ("foo", "qux");
-%! assert (p.Results, struct ("foo", "qux"))
-
-## This behaviour means that a positional option can never be a string
-## that is the name of a parameter key.  This is required for Matlab
-## compatibility.
-%!test <*50752>
-%! p = inputParser ();
-%! p.addOptional ("op1", "val");
-%! p.addParameter ("line", "tree");
-%! p.parse ("line", "circle");
-%! assert (p.Results, struct ("op1", "val", "line", "circle"))
-%!
-%! p = inputParser ();
-%! p.addOptional ("op1", "val1");
-%! p.addOptional ("op2", "val2");
-%! p.addParameter ("line", "tree");
-%! p.parse ("line", "circle");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.op2, "val2")
-%! assert (p.Results.line, "circle")
-%!
-%! ## If there's enough arguments to fill the positional options and
-%! ## param/key, it still skips positional options.
-%! p = inputParser ();
-%! p.addOptional ("op1", "val1");
-%! p.addOptional ("op2", "val2");
-%! p.addParameter ("line", "tree");
-%! p.parse ("line", "circle", "line", "rectangle");
-%! assert (p.Results, struct ("op1", "val1", "op2", "val2",
-%!                            "line", "rectangle"))
-%!
-%! ## Even if the key/param fails validation, it does not backtrack to
-%! ## check if the values are valid positional options.
-%! p = inputParser ();
-%! p.addOptional ("op1", "val1", @ischar);
-%! p.addOptional ("op2", "val2", @isnumeric);
-%! p.addParameter ("line", "circle", @ischar);
-%! fail ('p.parse ("line", 89)', "failed validation of LINE")
-%!
-%! p = inputParser ();
-%! p.addOptional ("op1", "val1");
-%! p.addParamValue ("line", "circle", @ischar);
-%! fail ('p.parse ("line", "line", 89)',
-%!       "non-string for Parameter name or Switch")
-
-%!test <*50752>
-%! ## This fails in Matlab but works in Octave.  It is a bug there
-%! ## that we do not replicate.
-%! p = inputParser ();
-%! p.addOptional ("op1", "val1");
-%! p.addParameter ("line", "circle");
-%! p.parse ("line");
-%! assert (p.Results, struct ("op1", "line", "line", "circle"))
-
-%!test <*50752>
-%! p = inputParser;
-%! p.addOptional ("op1", "val1");
-%! p.addSwitch ("line");
-%! p.parse ("line");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.line, true)
-
-%!test
-%! p = inputParser;
-%! p.addParameter ("a", []);
-%! p.addParameter ("b", []);
-%! p.parse ("a", 1);
-%! p.parse ("b", 1);
-%! assert (p.Results, struct ("a", [], "b", 1));
-%! assert (p.UsingDefaults, {"a"});
-
-%!test
-%! p = inputParser;
-%! p.addParameter ("b", []);
-%! p.KeepUnmatched = true;
-%! p.parse ("a", 1);
-%! p.parse ("b", 1);
-%! assert (p.Results, struct ("b", 1));
-%! assert (p.Unmatched, struct ());
-
-## Test for patch #9241
-%!error<failed validation of A with ischar>
-%! p = inputParser;
-%! p.addParameter ("a", [], @ischar);
-%! p.parse ("a", 1);
--- a/scripts/general/isdir.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-## Copyright (C) 2004-2017 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
-## <http://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)
--- a/scripts/general/loadobj.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-## Copyright (C) 2008-2017 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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {} {@var{b} =} loadobj (@var{a})
-## Method of a class to manipulate an object after loading it from a file.
-##
-## The function @code{loadobj} is called when the object @var{a} is loaded
-## using the @code{load} function.  An example of the use of @code{saveobj}
-## might be to add fields to an object that don't make sense to be saved.
-## For example:
-##
-## @example
-## @group
-## function b = loadobj (a)
-##   b = a;
-##   b.addmissingfield = addfield (b);
-## endfunction
-## @end group
-## @end example
-##
-## @seealso{saveobj, class}
-## @end deftypefn
-
-function b = loadobj (a)
-  error ('loadobj: not defined for class "%s"', class (a));
-endfunction
--- a/scripts/general/methods.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-## Copyright (C) 2012-2017 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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {} methods (@var{obj})
-## @deftypefnx {} {} methods ("@var{classname}")
-## @deftypefnx {} {@var{mtds} =} methods (@dots{})
-## List the names of the public methods for the object @var{obj} or the
-## named class @var{classname}.
-##
-## @var{obj} may be an Octave class object or a Java object.
-## @var{classname} may be the name of an Octave class or a Java class.
-##
-## When called with no output arguments, @code{methods} prints the list of
-## method names to the screen.  Otherwise, the output argument @var{mtds}
-## contains the list in a cell array of strings.
-## @seealso{fieldnames}
-## @end deftypefn
-
-function mtds = methods (obj)
-
-  if (nargin != 1)
-    print_usage ();
-  endif
-
-  if (isobject (obj))
-    ## Call internal C++ function for Octave objects
-    mtds_list = __methods__ (obj);
-  elseif (ischar (obj))
-    ## Could be a classname for an Octave class or Java class.
-    ## Try Octave class first.
-    mtds_list = __methods__ (obj);
-    if (isempty (mtds_list))
-      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
-      mtds_list = ostrsplit (mtds_str, ';');
-    endif
-  elseif (isjava (obj))
-    ## FIXME: Function prototype accepts java obj, but doesn't work if obj
-    ##        is e.g., java.lang.String.  Convert obj to classname then.
-    try
-      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
-    catch
-      obj = class (obj);
-      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
-    end_try_catch
-    mtds_list = strsplit (mtds_str, ';');
-  else
-    error ("methods: Invalid input argument");
-  endif
-
-  if (nargout == 0)
-    classname = ifelse (ischar (obj), obj, class (obj));
-    printf ("Methods for class %s:\n", classname);
-    disp (list_in_columns (mtds_list));
-  else
-    mtds = mtds_list;
-  endif
-
-endfunction
-
-
-## test Octave classname
-%!test
-%! mtds = methods ("ftp");
-%! assert (mtds{1}, "ascii");
-
-## test Java classname
-%!testif HAVE_JAVA; usejava ("jvm")
-%! mtds = methods ("java.lang.Double");
-%! search = strfind (mtds, "java.lang.Double valueOf");
-%! assert (! isempty ([search{:}]));
--- a/scripts/general/module.mk	Thu Dec 28 15:56:09 2017 -0800
+++ b/scripts/general/module.mk	Thu Dec 28 16:14:37 2017 -0800
@@ -3,8 +3,6 @@
   %reldir%/private
 
 %canon_reldir%_PRIVATE_FCN_FILES = \
-  %reldir%/private/__publish_html_output__.m \
-  %reldir%/private/__publish_latex_output__.m \
   %reldir%/private/__splinen__.m
 
 %canon_reldir%_FCN_FILES = \
@@ -30,15 +28,12 @@
   %reldir%/deg2rad.m \
   %reldir%/del2.m \
   %reldir%/divergence.m \
-  %reldir%/fieldnames.m \
   %reldir%/flip.m \
   %reldir%/flipdim.m \
   %reldir%/fliplr.m \
   %reldir%/flipud.m \
-  %reldir%/grabcode.m \
   %reldir%/gradient.m \
   %reldir%/idivide.m \
-  %reldir%/inputParser.m \
   %reldir%/int2str.m \
   %reldir%/integral.m \
   %reldir%/integral2.m \
@@ -48,23 +43,15 @@
   %reldir%/interp3.m \
   %reldir%/interpft.m \
   %reldir%/interpn.m \
-  %reldir%/isdir.m \
   %reldir%/isequal.m \
   %reldir%/isequaln.m \
-  %reldir%/loadobj.m \
   %reldir%/logspace.m \
-  %reldir%/methods.m \
-  %reldir%/nargchk.m \
-  %reldir%/narginchk.m \
-  %reldir%/nargoutchk.m \
   %reldir%/nextpow2.m \
-  %reldir%/nthargout.m \
   %reldir%/num2str.m \
   %reldir%/pol2cart.m \
   %reldir%/polyarea.m \
   %reldir%/postpad.m \
   %reldir%/prepad.m \
-  %reldir%/publish.m \
   %reldir%/quad2d.m \
   %reldir%/quadgk.m \
   %reldir%/quadl.m \
@@ -76,7 +63,6 @@
   %reldir%/repmat.m \
   %reldir%/rot90.m \
   %reldir%/rotdim.m \
-  %reldir%/saveobj.m \
   %reldir%/shift.m \
   %reldir%/shiftdim.m \
   %reldir%/sortrows.m \
@@ -85,7 +71,6 @@
   %reldir%/subsindex.m \
   %reldir%/trapz.m \
   %reldir%/triplequad.m \
-  %reldir%/validateattributes.m \
   %reldir%/xor.m
 
 %canon_reldir%dir = $(fcnfiledir)/general
--- a/scripts/general/nargchk.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-## Copyright (C) 2008-2017 Bill Denney
-##
-## 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{msgstr} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs})
-## @deftypefnx {} {@var{msgstr} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs}, "string")
-## @deftypefnx {} {@var{msgstruct} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs}, "struct")
-## Return an appropriate error message string (or structure) if the number of
-## inputs requested is invalid.
-##
-## This is useful for checking to see that the number of input arguments
-## supplied to a function is within an acceptable range.
-##
-## @strong{Caution}: @code{nargchk} is scheduled for deprecation.  Use
-## @code{narginchk} in all new code.
-## @seealso{narginchk, nargoutchk, error, nargin, nargout}
-## @end deftypefn
-
-## Author: Bill Denney <bill@denney.ws>
-
-function msg = nargchk (minargs, maxargs, nargs, outtype = "string")
-
-  if (nargin < 3 || nargin > 4)
-    print_usage ();
-  elseif (minargs > maxargs)
-    error ("nargchk: MINARGS must be <= MAXARGS");
-  elseif (! any (strcmpi (outtype, {"string", "struct"})))
-    error ('nargchk: output type must be either "string" or "struct"');
-  elseif (! (isscalar (minargs) && isscalar (maxargs) && isscalar (nargs)))
-    error ("nargchk: MINARGS, MAXARGS, and NARGS must be scalars");
-  endif
-
-  msg = struct ("message", "", "identifier", "");
-  if (nargs < minargs)
-    msg.message = "not enough input arguments";
-    msg.identifier = "Octave:nargchk:not-enough-inputs";
-  elseif (nargs > maxargs)
-    msg.message = "too many input arguments";
-    msg.identifier = "Octave:nargchk:too-many-inputs";
-  endif
-
-  if (strcmpi (outtype, "string"))
-    msg = msg.message;
-  elseif (isempty (msg.message))
-    ## Compatability: Matlab returns a 0x1 empty struct when nargchk passes
-    msg = resize (msg, 0, 1);
-  endif
-
-endfunction
-
-
-## Tests
-%!shared stnul, stmin, stmax
-%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1);
-%! stmin = struct ("message", "not enough input arguments",
-%!                 "identifier", "Octave:nargchk:not-enough-inputs");
-%! stmax = struct ("message", "too many input arguments",
-%!                 "identifier", "Octave:nargchk:too-many-inputs");
-%!assert (nargchk (0, 1, 0), "")
-%!assert (nargchk (0, 1, 1), "")
-%!assert (nargchk (1, 1, 0), "not enough input arguments")
-%!assert (nargchk (0, 1, 2), "too many input arguments")
-%!assert (nargchk (0, 1, 2, "string"), "too many input arguments")
-## Struct outputs
-%!assert (nargchk (0, 1, 0, "struct"), stnul)
-%!assert (nargchk (0, 1, 1, "struct"), stnul)
-%!assert (nargchk (1, 1, 0, "struct"), stmin)
-%!assert (nargchk (0, 1, 2, "struct"), stmax)
--- a/scripts/general/narginchk.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-## Copyright (C) 2012-2017 Carnë Draug
-##
-## 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 {} {} narginchk (@var{minargs}, @var{maxargs})
-## Check for correct number of input arguments.
-##
-## Generate an error message if the number of arguments in the calling function
-## is outside the range @var{minargs} and @var{maxargs}.  Otherwise, do
-## nothing.
-##
-## Both @var{minargs} and @var{maxargs} must be scalar numeric values.  Zero,
-## Inf, and negative values are all allowed, and @var{minargs} and
-## @var{maxargs} may be equal.
-##
-## Note that this function evaluates @code{nargin} on the caller.
-##
-## @seealso{nargoutchk, error, nargout, nargin}
-## @end deftypefn
-
-## Author: Carnë Draug <carandraug+dev@gmail.com>
-
-function narginchk (minargs, maxargs)
-
-  if (nargin != 2)
-    print_usage;
-  elseif (! isnumeric (minargs) || ! isscalar (minargs))
-    error ("narginchk: MINARGS must be a numeric scalar");
-  elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
-    error ("narginchk: MAXARGS must be a numeric scalar");
-  elseif (minargs > maxargs)
-    error ("narginchk: MINARGS cannot be larger than MAXARGS");
-  endif
-
-  args = evalin ("caller", "nargin;");
-
-  if (args < minargs)
-    error ("narginchk: not enough input arguments");
-  elseif (args > maxargs)
-    error ("narginchk: too many input arguments");
-  endif
-
-endfunction
-
-
-%!function f (nargs, varargin)
-%! narginchk (nargs(1), nargs(2));
-%!endfunction
-
-%!error <too many input arguments> f([0,0])
-%!error <not enough input arguments> f([3, 3], 1)
-
-%!test
-%! f([1,1]);
-%!test
-%! f([1,5], 2, 3, 4, 5);
--- a/scripts/general/nargoutchk.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-## Copyright (C) 2008-2017 Bill Denney
-## Copyright (C) 2012 Carnë Draug
-##
-## 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  {} {} nargoutchk (@var{minargs}, @var{maxargs})
-## @deftypefnx {} {@var{msgstr} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs})
-## @deftypefnx {} {@var{msgstr} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs}, "string")
-## @deftypefnx {} {@var{msgstruct} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs}, "struct")
-## Check for correct number of output arguments.
-##
-## In the first form, return an error if the number of arguments is not between
-## @var{minargs} and @var{maxargs}.  Otherwise, do nothing.  Note that this
-## function evaluates the value of @code{nargout} on the caller so its value
-## must have not been tampered with.
-##
-## Both @var{minargs} and @var{maxargs} must be numeric scalars.  Zero, Inf,
-## and negative are all valid, and they can have the same value.
-##
-## For backwards compatibility, the other forms return an appropriate error
-## message string (or structure) if the number of outputs requested is
-## invalid.
-##
-## This is useful for checking to that the number of output arguments supplied
-## to a function is within an acceptable range.
-## @seealso{narginchk, error, nargout, nargin}
-## @end deftypefn
-
-## Author: Bill Denney <bill@denney.ws>
-## Author: Carnë Draug <carandraug+dev@gmail.com>
-
-function msg = nargoutchk (minargs, maxargs, nargs, outtype)
-
-  ## before matlab's 2011b, nargoutchk would return an error message (just the
-  ## message in a string).  With 2011b, it no longer returns anything, it
-  ## simply gives an error if the args number is incorrect.
-  ## To try to keep compatibility with both versions, check nargout and nargin
-  ## to guess if the caller is expecting a value (old syntax)
-  ## or none (new syntax).
-
-  if (nargout == 1 && (nargin == 3 || nargin == 4))
-
-    if (minargs > maxargs)
-      error ("nargoutchk: MINARGS must be <= MAXARGS");
-    elseif (nargin == 3)
-      outtype = "string";
-    elseif (! any (strcmpi (outtype, {"string" "struct"})))
-      error ("nargoutchk: output type must be either string or struct");
-    elseif (! (isscalar (minargs) && isscalar (maxargs) && isscalar (nargs)))
-      error ("nargoutchk: MINARGS, MAXARGS, and NARGS must be scalars");
-    endif
-
-    msg = struct ("message", "", "identifier", "");
-    if (nargs < minargs)
-      msg.message = "not enough output arguments";
-      msg.identifier = "Octave:nargoutchk:not-enough-outputs";
-    elseif (nargs > maxargs)
-      msg.message = "too many output arguments";
-      msg.identifier = "Octave:nargoutchk:too-many-outputs";
-    endif
-
-    if (strcmpi (outtype, "string"))
-      msg = msg.message;
-    elseif (isempty (msg.message))
-      ## Compatibility: Matlab returns a 0x1 empty struct when nargoutchk passes
-      msg = resize (msg, 0, 1);
-    endif
-
-  elseif (nargout == 0 && nargin == 2)
-
-    if (! isnumeric (minargs) || ! isscalar (minargs))
-      error ("nargoutchk: MINARGS must be a numeric scalar");
-    elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
-      error ("nargoutchk: MAXARGS must be a numeric scalar");
-    elseif (minargs > maxargs)
-      error ("nargoutchk: MINARGS cannot be larger than MAXARGS");
-    endif
-
-    args = evalin ("caller", "nargout;");
-
-    if (args < minargs)
-      error ("nargoutchk: Not enough output arguments.");
-    elseif (args > maxargs)
-      error ("nargoutchk: Too many output arguments.");
-    endif
-
-  else
-    print_usage;
-  endif
-
-endfunction
-
-
-%!shared stnul, stmin, stmax
-%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1);
-%! stmin = struct ("message", "not enough output arguments",
-%!                 "identifier", "Octave:nargoutchk:not-enough-outputs");
-%! stmax = struct ("message", "too many output arguments",
-%!                 "identifier", "Octave:nargoutchk:too-many-outputs");
-%!assert (nargoutchk (0, 1, 0), "")
-%!assert (nargoutchk (0, 1, 1), "")
-%!assert (nargoutchk (1, 1, 0), "not enough output arguments")
-%!assert (nargoutchk (0, 1, 2), "too many output arguments")
-%!assert (nargoutchk (0, 1, 2, "string"), "too many output arguments")
-## Struct outputs
-%!assert (nargoutchk (0, 1, 0, "struct"), stnul)
-%!assert (nargoutchk (0, 1, 1, "struct"), stnul)
-%!assert (nargoutchk (1, 1, 0, "struct"), stmin)
-%!assert (nargoutchk (0, 1, 2, "struct"), stmax)
--- a/scripts/general/nthargout.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-## Copyright (C) 2012-2017 Jordi Gutiérrez Hermoso
-##
-## 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  {} {} nthargout (@var{n}, @var{func}, @dots{})
-## @deftypefnx {} {} nthargout (@var{n}, @var{ntot}, @var{func}, @dots{})
-## Return the @var{n}th output argument of the function specified by the
-## function handle or string @var{func}.
-##
-## Any additional arguments are passed directly to @var{func}.  The total
-## number of arguments to call @var{func} with can be passed in @var{ntot}; by
-## default @var{ntot} is @var{n}.  The input @var{n} can also be a vector of
-## indices of the output, in which case the output will be a cell array of the
-## requested output arguments.
-##
-## The intended use @code{nthargout} is to avoid intermediate variables.  For
-## example, when finding the indices of the maximum entry of a matrix, the
-## following two compositions of nthargout
-##
-## @example
-## @group
-## @var{m} = magic (5);
-## cell2mat (nthargout ([1, 2], @@ind2sub, size (@var{m}),
-##                      nthargout (2, @@max, @var{m}(:))))
-## @result{} 5   3
-## @end group
-## @end example
-##
-## @noindent
-## are completely equivalent to the following lines:
-##
-## @example
-## @group
-## @var{m} = magic (5);
-## [~, idx] = max (@var{M}(:));
-## [i, j] = ind2sub (size (@var{m}), idx);
-## [i, j]
-## @result{} 5   3
-## @end group
-## @end example
-##
-## It can also be helpful to have all output arguments in a single cell in the
-## following manner:
-##
-## @example
-## @var{USV} = nthargout ([1:3], @@svd, hilb (5));
-## @end example
-##
-## @seealso{nargin, nargout, varargin, varargout, isargout}
-## @end deftypefn
-
-## Author: Jordi Gutiérrez Hermoso
-
-function out = nthargout (n, varargin)
-
-  if (nargin < 2)
-    print_usage ();
-  endif
-
-  if (isa (varargin{1}, "function_handle") || 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})))
-    ntot = varargin{1};
-    func = varargin{2};
-    args = varargin(3:end);
-  else
-    print_usage ();
-  endif
-
-  if (any (n != fix (n))  || ntot != fix (ntot) || any (n <= 0) || ntot <= 0)
-    error ("nthargout: N and NTOT must consist of positive integers");
-  endif
-
-  outargs = cell (1, ntot);
-
-  try
-    [outargs{:}] = feval (func, args{:});
-    if (numel (n) > 1)
-      out = outargs(n);
-    else
-      out = outargs{n};
-    endif
-  catch
-    err = lasterr ();
-    if (strfind ("some elements undefined in return list", err))
-      error ("nthargout: Too many output arguments: %d", ntot);
-    else
-      error (err);
-    endif
-  end_try_catch
-
-endfunction
-
-
-%!shared m
-%! m = magic (5);
-%!assert (nthargout ([1,2], @ind2sub, size (m), nthargout (2, @max, m(:))), {5,3})
-%!assert (nthargout (3, @find, m(m>20)), [23, 24, 25, 21, 22]')
--- a/scripts/general/private/__publish_html_output__.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,430 +0,0 @@
-## Copyright (C) 2016-2017 Kai T. Ohlhus
-##
-## 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{outstr} =} __publish_html_output__ (@var{type}, @var{varargin})
-##
-## Internal function.
-##
-## The first input argument @var{type} defines the required strings
-## (@samp{str}) or cell-strings (@samp{cstr}) in @var{varargin} in order
-## to produce HTML output.
-##
-## @var{type} is one of
-##
-## @itemize @bullet
-## @item
-## @samp{output_file_extension} ()
-##
-## @item
-## @samp{header} (title_str, intro_str, toc_cstr)
-##
-## @item
-## @samp{footer} ()
-##
-## @item
-## @samp{code} (str)
-##
-## @item
-## @samp{code_output} (str)
-##
-## @item
-## @samp{section} (str)
-##
-## @item
-## @samp{preformatted_code} (str)
-##
-## @item
-## @samp{preformatted_text} (str)
-##
-## @item
-## @samp{bulleted_list} (cstr)
-##
-## @item
-## @samp{numbered_list} (cstr)
-##
-## @item
-## @samp{graphic} (str)
-##
-## @item
-## @samp{html} (str)
-##
-## @item
-## @samp{latex} (str)
-##
-## @item
-## @samp{text} (str)
-##
-## @item
-## @samp{blockmath} (str)
-##
-## @item
-## @samp{inlinemath} (str)
-##
-## @item
-## @samp{bold} (str)
-##
-## @item
-## @samp{italic} (str)
-##
-## @item
-## @samp{monospaced} (str)
-##
-## @item
-## @samp{link} (url_str, url_str, str)
-##
-## @item
-## @samp{TM} ()
-##
-## @item
-## @samp{R} ()
-##
-## @item
-## @samp{escape_special_chars} (str)
-## @end itemize
-## @end deftypefn
-
-function outstr = __publish_html_output__ (type, varargin)
-  outstr = feval (["do_" type], varargin{:});
-endfunction
-
-function outstr = do_output_file_extension ()
-  outstr = ".html";
-endfunction
-
-function outstr = do_header (title_str, intro_str, toc_cstr)
-  mathjax_str = sprintf ("%s\n",
-'<script type="text/x-mathjax-config">',
-"MathJax.Hub.Config({",
-"  tex2jax: { inlineMath: [['$','$'], ['\\\\(','\\\\)']] },",
-"  TeX: { equationNumbers: { autoNumber: 'all' } }",
-"});",
-"</script>",
-['<script type="text/javascript" async ', ...
- 'src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?', ...
- 'config=TeX-MML-AM_CHTML"></script>']);
-
-  stylesheet_str = sprintf ("%s\n",
-"<style>",
-"body > * {",
-"  max-width: 42em;",
-"}",
-"body {",
-'  font-family: "Roboto Condensed", sans-serif;',
-"  padding-left: 7.5em;",
-"  padding-right: 7.5em;",
-"}",
-"pre, code {",
-"  max-width: 50em;",
-"  font-family: monospace;",
-"}",
-"pre.oct-code {",
-"  border: 1px solid Grey;",
-"  padding: 5px;",
-"}",
-"pre.oct-code-output {",
-"  margin-left: 2em;",
-"}",
-"span.comment {",
-"  color: ForestGreen;",
-"}",...
-"span.keyword {",
-"  color: Blue;",
-"}",...
-"span.string {",
-"  color: DarkOrchid;",
-"}",...
-"footer {",
-"  margin-top: 2em;",
-"  font-size: 80%;",
-"}",
-"a, a:visited {",
-"  color: Blue;",
-"}",
-"h2 {",
-'  font-family: "Roboto Condensed", serif;',
-"  margin-top: 1.5em;",
-"}",
-"h2 a, h2 a:visited {",
-"  color: Black;",
-"}",
-"</style>");
-
-  outstr = sprintf ("%s\n",
-"<!DOCTYPE html>",
-"<html>",
-"<head>",
-'<meta charset="UTF-8">',
-["<title>" title_str "</title>"],
-mathjax_str,
-stylesheet_str,
-"</head>",
-"<body>",
-["<h1>" title_str "</h1>"],
-intro_str);
-
-  if (! isempty (toc_cstr))
-    for i = 1:numel (toc_cstr)
-      toc_cstr{i} = do_link (["#node" sprintf("%d", i)], toc_cstr{i});
-    endfor
-    outstr = [outstr, "<h2>Contents</h2>", do_bulleted_list(toc_cstr)];
-  endif
-
-  ## Reset section counter
-  do_section ();
-
-endfunction
-
-function outstr = do_footer (m_source_str)
-  outstr = sprintf ("%s\n",
-"",
-"<footer>",
-"<hr>",
-['<a href="http://www.octave.org">Published with GNU Octave ' version() '</a>'],
-"</footer>",
-"<!--",
-"##### SOURCE BEGIN #####",
-m_source_str,
-"##### SOURCE END #####",
-"-->",
-"</body>",
-"</html>");
-endfunction
-
-function outstr = do_code (str)
-  outstr = ["\n", '<pre class="oct-code">' syntax_highlight(str) "</pre>\n"];
-endfunction
-
-function outstr = do_code_output (str)
-  str = do_escape_special_chars (str);
-  outstr = ["\n", '<pre class="oct-code-output">' str "</pre>\n"];
-endfunction
-
-function outstr = do_section (varargin)
-  persistent counter = 1;
-
-  if (nargin == 0)
-    outstr = "";
-    counter = 1;
-    return;
-  endif
-
-  outstr = ['<h2><a id="node' sprintf("%d", counter) '">', ...
-            varargin{1}, ...
-            "</a></h2>"];
-
-  counter++;
-
-endfunction
-
-function outstr = do_preformatted_code (str)
-  outstr = ["\n", '<pre class="pre-code">' syntax_highlight(str) "</pre>\n"];
-endfunction
-
-function outstr = do_preformatted_text (str)
-  str = do_escape_special_chars (str);
-  outstr = ["\n", '<pre class="pre-text">' str "</pre>\n"];
-endfunction
-
-function outstr = do_bulleted_list (cstr)
-  outstr = "\n<ul>\n";
-  for i = 1:numel (cstr)
-    outstr = [outstr, "<li>" cstr{i} "</li>\n"];
-  endfor
-  outstr = [outstr, "</ul>\n"];
-endfunction
-
-function outstr = do_numbered_list (cstr)
-  outstr = "\n<ol>\n";
-  for i = 1:numel (cstr)
-    outstr = [outstr, "<li>" cstr{i} "</li>\n"];
-  endfor
-  outstr = [outstr, "</ol>\n"];
-endfunction
-
-function outstr = do_graphic (str)
-  outstr = ['<img src="' str '" alt="' str '">'];
-endfunction
-
-function outstr = do_html (str)
-  outstr = ["\n" str "\n"];
-endfunction
-
-function outstr = do_latex (str)
-  outstr = "";
-endfunction
-
-function outstr = do_link (url_str, str)
-  outstr = ['<a href="' url_str '">' str "</a>"];
-endfunction
-
-function outstr = do_text (str)
-  outstr = ["\n<p>" str "</p>\n"];
-endfunction
-
-function outstr = do_blockmath (str)
-  outstr = ["$$" str "$$"];
-endfunction
-
-function outstr = do_inlinemath (str)
-  outstr = ["$" str "$"];
-endfunction
-
-function outstr = do_bold (str)
-  outstr = ["<b>" str "</b>"];
-endfunction
-
-function outstr = do_italic (str)
-  outstr = ["<i>" str "</i>"];
-endfunction
-
-function outstr = do_monospaced (str)
-  outstr = ["<code>" str "</code>"];
-endfunction
-
-function outstr = do_TM ()
-  outstr = "&trade;";
-endfunction
-
-function outstr = do_R ()
-  outstr = "&reg;";
-endfunction
-
-function str = do_escape_special_chars (str)
-  str = regexprep (str, '&', '&amp;');
-  str = regexprep (str, '<', '&lt;');
-  str = regexprep (str, '>', '&gt;');
-  ## str = regexprep (str, '"', '&quot;'); ## MATLAB R2017a compatibility.
-endfunction
-
-## SYNTAX_HIGHLIGHT: A primitive parser to highlight syntax via <span> tags.
-## FIXME: Needs to be replaced by a better solution.
-function outstr = syntax_highlight (str)
-  str = do_escape_special_chars (str);
-  outstr = "";
-  placeholder_cstr = {};
-  i = 1;
-  plh = 0;
-
-  while (i <= numel (str))
-    ## Block comment
-    if (any (strncmp (str(i:end), {"%{", "#{"}, 2)))
-      plh_str = ['<span class="comment">', str(i:i+1)];
-      i += 2;
-      while (i <= numel (str)
-             && ! (any (strncmp (str(i:end), {"%}", "#}"}, 2))))
-        plh_str = [plh_str, str(i)];
-        i += 1;
-      endwhile
-      if (i < numel (str))
-        plh_str = [plh_str, str(i:i+1), "</span>"];
-        i += 2;
-      else
-        plh_str = [plh_str, "</span>"];
-      endif
-      plh += 1;
-      placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
-    ## Line comment
-    elseif (str(i) == "#" || str(i) == "%")
-      plh_str = '<span class="comment">';
-      idx = find (str(i:end) == "\n", 1);
-      if (isempty (idx))
-        plh_str = [plh_str, str(i:end)];
-        i = numel (str) + 1;
-      else
-        plh_str = [plh_str, str(i:i+idx-2)];
-        i += idx;
-      endif
-      plh_str = [plh_str, "</span>\n"];
-      plh += 1;
-      placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
-    ## Single quoted string
-    elseif (str(i) == "'")
-      plh_str = "<span class=\"string\">'";
-      i += 1;
-      while (i <= numel (str))
-        ## Ignore escaped string terminations
-        if (strncmp (str(i:end), "''", 2))
-          plh_str = [plh_str, "''"];
-          i += 2;
-        ## Is char a string termination?
-        elseif (str(i) == "'")
-          plh_str = [plh_str, "'"];
-          i += 1;
-          break;
-        ## Is string terminated by line break?
-        elseif (str(i) == "\n")
-          break;
-        ## String content
-        else
-          plh_str = [plh_str, str(i)];
-          i += 1;
-        endif
-      endwhile
-      plh_str = [plh_str, "</span>"];
-      plh += 1;
-      placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
-    ## Double quoted string
-    elseif (str(i) == '"')
-      plh_str = '<span class="string">"';
-      i += 1;
-      while (i <= numel (str))
-        ## Is char a string termination?
-        if (str(i) == '"' && str(i-1) != '\')
-          plh_str = [plh_str, '"'];
-          i += 1;
-          break;
-        ## Is string terminated by line break?
-        elseif (str(i) == "\n")
-          break;
-        ## String content
-        else
-          plh_str = [plh_str, str(i)];
-          i += 1;
-        endif
-      endwhile
-      plh_str = [plh_str, "</span>"];
-      plh += 1;
-      placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
-    else
-      outstr = [outstr, str(i)];
-      i += 1;
-    endif
-  endwhile
-
-  persistent kword_ptn = strjoin (iskeyword (), '|');
-
-  ## FIXME: remove hack for regexprep once bug #38149 is solved
-  outstr = [" ", strrep(outstr, "\n", " \n "), " "];
-  outstr = regexprep (outstr,
-                      ['(\s)(' kword_ptn ')(\s|\()'],
-                      ['$1<span class="keyword">$2</span>$3']);
-  ## FIXME: remove hack for regexprep once bug #38149 is solved
-  outstr = strrep (outstr(2:end-1), " \n ", "\n");
-
-  ## Restore placeholders
-  for i = plh:-1:1
-    outstr = strrep (outstr, [" PUBLISHPLACEHOLDER", sprintf("%d", i), " "],
-                             placeholder_cstr{i});
-  endfor
-
-endfunction
--- a/scripts/general/private/__publish_latex_output__.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,280 +0,0 @@
-## Copyright (C) 2016-2017 Kai T. Ohlhus
-##
-## 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{outstr} =} __publish_latex_output__ (@var{type}, @var{varargin})
-##
-## Internal function.
-##
-## The first input argument @var{type} defines the required strings
-## (@samp{str}) or cell-strings (@samp{cstr}) in @var{varargin} in order
-## to produce @LaTeX{} output.
-##
-## @var{type} is one of
-##
-## @itemize @bullet
-## @item
-## @samp{output_file_extension} ()
-##
-## @item
-## @samp{header} (title_str, intro_str, toc_cstr)
-##
-## @item
-## @samp{footer} ()
-##
-## @item
-## @samp{code} (str)
-##
-## @item
-## @samp{code_output} (str)
-##
-## @item
-## @samp{section} (str)
-##
-## @item
-## @samp{preformatted_code} (str)
-##
-## @item
-## @samp{preformatted_text} (str)
-##
-## @item
-## @samp{bulleted_list} (cstr)
-##
-## @item
-## @samp{numbered_list} (cstr)
-##
-## @item
-## @samp{graphic} (str)
-##
-## @item
-## @samp{html} (str)
-##
-## @item
-## @samp{latex} (str)
-##
-## @item
-## @samp{text} (str)
-##
-## @item
-## @samp{blockmath} (str)
-##
-## @item
-## @samp{inlinemath} (str)
-##
-## @item
-## @samp{bold} (str)
-##
-## @item
-## @samp{italic} (str)
-##
-## @item
-## @samp{monospaced} (str)
-##
-## @item
-## @samp{link} (url_str, url_str, str)
-##
-## @item
-## @samp{TM} ()
-##
-## @item
-## @samp{R} ()
-##
-## @item
-## @samp{escape_special_chars} (str)
-## @end itemize
-## @end deftypefn
-
-function outstr = __publish_latex_output__ (type, varargin)
-  outstr = feval (["do_" type], varargin{:});
-endfunction
-
-function outstr = do_output_file_extension ()
-  outstr = ".tex";
-endfunction
-
-function outstr = do_header (title_str, intro_str, toc_cstr)
-  publish_comment = sprintf ("%s\n",
-"",
-"",
-"% This document was generated by the publish-function",
-["% from GNU Octave " version()],
-"");
-
-  latex_preamble = sprintf ("%s\n",
-"",
-"",
-'\documentclass[10pt]{article}',
-'\usepackage{listings}',
-'\usepackage{mathtools}',
-'\usepackage{amssymb}',
-'\usepackage{graphicx}',
-'\usepackage{hyperref}',
-'\usepackage{xcolor}',
-'\usepackage{titlesec}',
-'\usepackage[utf8]{inputenc}',
-'\usepackage[T1]{fontenc}',
-'\usepackage{lmodern}');
-
-  listings_option = sprintf ("%s\n",
-"",
-"",
-'\lstset{',
-'language=Octave,',
-'numbers=none,',
-'frame=single,',
-'tabsize=2,',
-'showstringspaces=false,',
-'breaklines=true}');
-
-  latex_head = sprintf ("%s\n",
-"",
-"",
-'\titleformat*{\section}{\Huge\bfseries}',
-'\titleformat*{\subsection}{\large\bfseries}',
-'\renewcommand{\contentsname}{\Large\bfseries Contents}',
-'\setlength{\parindent}{0pt}',
-"",
-'\begin{document}',
-"",
-['{\Huge\section*{' title_str '}}'],
-"",
-'\tableofcontents',
-'\vspace*{4em}',
-"");
-
-  outstr = [publish_comment, latex_preamble, listings_option, latex_head];
-
-endfunction
-
-function outstr = do_footer (m_source_str)
-  outstr = ["\n\n" '\end{document}' "\n"];
-endfunction
-
-function outstr = do_code (str)
-  outstr = ['\begin{lstlisting}' "\n", str, "\n" '\end{lstlisting}' "\n"];
-endfunction
-
-function outstr = do_code_output (str)
-  outstr = sprintf ("%s\n",
-'\begin{lstlisting}[language={},xleftmargin=5pt,frame=none]',
-str,
-'\end{lstlisting}');
-endfunction
-
-function outstr = do_section (str)
-  outstr = sprintf ("%s\n",
-"",
-"",
-'\phantomsection',
-['\addcontentsline{toc}{section}{' str '}'],
-['\subsection*{' str '}'],
-"");
-endfunction
-
-function outstr = do_preformatted_code (str)
-  outstr = sprintf ("%s\n",
-'\begin{lstlisting}',
-str,
-'\end{lstlisting}');
-endfunction
-
-function outstr = do_preformatted_text (str)
-  outstr = sprintf ("%s\n",
-'\begin{lstlisting}[language={}]',
-str,
-'\end{lstlisting}');
-endfunction
-
-function outstr = do_bulleted_list (cstr)
-  outstr = ["\n" '\begin{itemize}' "\n"];
-  for i = 1:numel (cstr)
-    outstr = [outstr, '\item ' cstr{i} "\n"];
-  endfor
-  outstr = [outstr, '\end{itemize}' "\n"];
-endfunction
-
-function outstr = do_numbered_list (cstr)
-  outstr = ["\n" '\begin{enumerate}' "\n"];
-  for i = 1:numel (cstr)
-    outstr = [outstr, '\item ' cstr{i} "\n"];
-  endfor
-  outstr = [outstr, "\\end{enumerate}\n"];
-endfunction
-
-function outstr = do_graphic (str)
-  outstr = sprintf ("%s\n",
-'\begin{figure}[!ht]',
-['\includegraphics[width=\textwidth]{' str '}'],
-'\end{figure}');
-endfunction
-
-function outstr = do_html (str)
-  outstr = "";
-endfunction
-
-function outstr = do_latex (str)
-  outstr = ["\n" str "\n"];
-endfunction
-
-function outstr = do_link (url_str, str)
-  outstr = ['\href{' url_str '}{' str '}'];
-endfunction
-
-function outstr = do_text (str)
-  outstr = ["\n\n" str "\n\n"];
-endfunction
-
-function outstr = do_blockmath (str)
-  outstr = ["$$" str "$$"];
-endfunction
-
-function outstr = do_inlinemath (str)
-  outstr = ["$" str "$"];
-endfunction
-
-function outstr = do_bold (str)
-  outstr = ['\textbf{' str '}'];
-endfunction
-
-function outstr = do_italic (str)
-  outstr = ['\textit{' str '}'];
-endfunction
-
-function outstr = do_monospaced (str)
-  outstr = ['\texttt{' str '}'];
-endfunction
-
-function outstr = do_TM ()
-  outstr = '\texttrademark ';
-endfunction
-
-function outstr = do_R ()
-  outstr = '\textregistered ';
-endfunction
-
-function str = do_escape_special_chars (str)
-  ## Escape \, {, }, &, %, #, _, ~, ^, <, >
-  str = regexprep (str, '\\', "\\ensuremath{\\backslash}");
-  str = regexprep (str, '(?<!\\)(\{|\}|&|%|#|_)', '\\$1');
-  ## Revert accidential {} replacements for backslashes
-  str = strrep (str, '\ensuremath\{\backslash\}', '\ensuremath{\backslash}');
-  str = regexprep (str, '(?<!\\)~', "\\ensuremath{\\tilde{\\;}}");
-  str = regexprep (str, '(?<!\\)\^', "\\^{}");
-  str = regexprep (str, '(?<!\\)<', "\\ensuremath{<}");
-  str = regexprep (str, '(?<!\\)>', "\\ensuremath{>}");
-endfunction
--- a/scripts/general/publish.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1071 +0,0 @@
-## Copyright (C) 2016-2017 Kai T. Ohlhus <k.ohlhus@gmail.com>
-## Copyright (C) 2010 Fotios Kasolis <fotios.kasolis@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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {} {} publish (@var{file})
-## @deftypefnx {} {} publish (@var{file}, @var{output_format})
-## @deftypefnx {} {} publish (@var{file}, @var{option1}, @var{value1}, @dots{})
-## @deftypefnx {} {} publish (@var{file}, @var{options})
-## @deftypefnx {} {@var{output_file} =} publish (@var{file}, @dots{})
-##
-## Generate a report from the Octave script file @var{file} in one of several
-## output formats.
-##
-## The generated reports interpret any Publishing Markup in comments, which is
-## explained in detail in the GNU Octave manual.  Assume the following example,
-## using some Publishing Markup, to be the contents of the script file
-## @file{pub_example.m}:
-##
-## @example
-## @group
-## ## Headline title
-## #
-## # Some *bold*, _italic_, or |monospaced| Text with
-## # a <http://www.octave.org link to *GNU Octave*>.
-## ##
-##
-## # "Real" Octave commands to be evaluated
-## sombrero ()
-##
-## %% @sc{matlab} comment style ('%') is supported as well
-## %
-## % * Bulleted list item 1
-## % * Bulleted list item 2
-## %
-## % # Numbered list item 1
-## % # Numbered list item 2
-## @end group
-## @end example
-##
-## To publish this script file, type @code{publish ("pub_example.m")}.
-##
-## With only @var{file} given, a HTML report is generated in a subdirectory
-## @file{html} relative to the current working directory.  The Octave commands
-## are evaluated in a separate context and any figures created while executing
-## the script file are included in the report.  All formatting syntax of
-## @var{file} is treated according to the specified output format and included
-## in the report.
-##
-## Using @code{publish (@var{file}, @var{output_format})} is equivalent to the
-## function call using a structure
-##
-## @example
-## @group
-## @var{options}.format = @var{output_format};
-## publish (@var{file}, @var{options})
-## @end group
-## @end example
-##
-## @noindent
-## which is described below.  The same holds for using option/value pairs
-##
-## @example
-## @group
-## @var{options}.@var{option1} = @var{value1};
-## publish (@var{file}, @var{options})
-## @end group
-## @end example
-##
-## The structure @var{options} can have the following field names.  If a field
-## name is not specified, the default value is used:
-##
-## @itemize @bullet
-## @item
-## @samp{format} --- Output format of the published script file, one of
-##
-## @samp{html} (default), @samp{doc}, @samp{latex}, @samp{ppt},
-## @samp{pdf}, or @samp{xml}.
-##
-## The output formats @samp{doc}, @samp{ppt}, and @samp{xml} are not currently
-## supported.  To generate a @samp{doc} report, open a generated @samp{html}
-## report with your office suite.
-##
-## In Octave custom formats are supported by implementing all callback
-## subfunctions in a function file named
-## @samp{__publish_<custom format>_output__.m}.  To obtain a template for the
-## HTML format type:
-##
-## @example
-## @group
-## edit (fullfile (fileparts (which ("publish")), ...
-##       "private", "__publish_html_output__.m"))
-## @end group
-## @end example
-##
-## @item
-## @samp{outputDir} --- Full path of the directory where the generated report
-## will be located.  If no directory is given, the report is generated in a
-## subdirectory @file{html} relative to the current working directory.
-##
-## @item
-## @samp{stylesheet} --- Not supported, only for @sc{matlab} compatibility.
-##
-## @item
-## @samp{createThumbnail} --- Not supported, only for @sc{matlab}
-## compatibility.
-##
-## @item
-## @samp{figureSnapMethod} --- Not supported, only for @sc{matlab}
-## compatibility.
-##
-## @item
-## @samp{imageFormat} --- Desired format for any images produced while
-## evaluating the code.  The allowed image formats depend on the output format:
-##
-## @itemize @bullet
-## @item @samp{html}, @samp{xml} --- @samp{png} (default), any image format
-## supported by Octave
-##
-## @item @samp{latex} --- @samp{epsc2} (default), any image format supported by
-## Octave
-##
-## @item @samp{pdf} --- @samp{jpg} (default) or @samp{bmp}, note @sc{matlab}
-## uses  @samp{bmp} as default
-##
-## @item @samp{doc} or @samp{ppt} --- @samp{png} (default), @samp{jpg},
-## @samp{bmp}, or @samp{tiff}
-## @end itemize
-##
-## @item
-## @samp{maxWidth} and @samp{maxHeight} --- Maximum width (height) of the
-## produced images in pixels.  An empty value means no restriction.  Both
-## values must be set in order for the option to work properly.
-##
-## @samp{[]} (default), integer value @geq{} 0
-##
-## @item
-## @samp{useNewFigure} --- Use a new figure window for figures created by the
-## evaluated code.  This avoids side effects with already opened figure
-## windows.
-##
-## @samp{true} (default) or @samp{false}
-##
-## @item
-## @samp{evalCode} --- Evaluate code of the Octave source file
-##
-## @samp{true} (default) or @samp{false}
-##
-## @item
-## @samp{catchError} --- Catch errors while evaluating code and continue
-##
-## @samp{true} (default) or @samp{false}
-##
-## @item
-## @samp{codeToEvaluate} --- Octave commands that should be evaluated prior to
-## publishing the script file.  These Octave commands do not appear in the
-## generated report.
-##
-## @item
-## @samp{maxOutputLines} --- Maximum number of output lines from code
-## evaluation which are included in output.
-##
-## @samp{Inf} (default) or integer value > 0
-##
-## @item
-## @samp{showCode} --- Show the evaluated Octave commands in the generated
-## report
-##
-## @samp{true} (default) or @samp{false}
-## @end itemize
-##
-## The option output @var{output_file} is a string with path and file name
-## of the generated report.
-##
-## @seealso{grabcode}
-## @end deftypefn
-
-function output_file = publish (file, varargin)
-
-  if (nargin < 1)
-    print_usage ();
-  endif
-
-  if (exist (file, "file") != 2)
-    error ("publish: FILE does not exist");
-  endif
-
-  ## Check file to be in Octave's load path
-  [file_path, file_name, file_ext] = fileparts (file);
-  if (isempty (file_path))
-    file_path = pwd;
-  endif
-  if (exist ([file_name, file_ext]) != 2)
-    error (["publish: " file " is not in the load path"]);
-  endif
-
-  ## Check file extension and that file is an Octave script
-  file_info = __which__ (file_name);
-  if (! strcmp (file_ext, ".m") || ! strcmp (file_info.type, "script"))
-    error ("publish: only script files can be published");
-  endif
-
-  ## Check file to be parsable
-  __parse_file__ (file);
-
-  ## Get structure with necessary options
-  options = struct ();
-  if (numel (varargin) == 1)
-    ## Call: publish (file, format)
-    if (ischar (varargin{1}))
-      options.format = varargin{1};
-    ## Call: publish (file, options)
-    elseif (isstruct (varargin{1}))
-      options = varargin{1};
-    else
-      error ("publish: second argument must be OUTPUT_FORMAT or OPTIONS");
-    endif
-  ## Call: publish (file, Name1, Value1, Name2, Value2, ...)
-  elseif (rem (numel (varargin), 2) == 0
-          && all (cellfun (@ischar, varargin(1:2:end))))
-    options = cell2struct (varargin(2:2:end), varargin(1:2:end), 2);
-  else
-    error ("publish: invalid arguments");
-  endif
-
-  ## Validate options struct
-
-  ## Options for the output
-  if (! isfield (options, "format"))
-    options.format = "html";
-  else
-    ## FIXME: Implement remaining formats
-    if (any (strcmpi (options.format, {"doc", "ppt", "xml"})))
-      error ('publish: Output format "%s" is not yet supported',
-             options.format);
-    endif
-    ## Supported or custom output format
-    supported_formats = {"html", "doc", "latex", "ppt", "xml", "pdf"};
-    if (! any (strcmpi (options.format, supported_formats)))
-      ## Check existence of custom formatter
-      custom_formatter = ["__publish_", options.format, "_output__"];
-      if (! exist (custom_formatter, "file"))
-        error (['publish: Custom output format "%s" requires the ', ...
-                "formatter function:\n\n\t%s\n\n\t", ...
-                'See "help publish" for more information.'],
-                options.format, custom_formatter);
-      endif
-    else
-      options.format = validatestring (options.format, supported_formats);
-    endif
-  endif
-
-  if (! isfield (options, "outputDir"))
-    ## Matlab R2016a doc says default is "", but specifies to create a
-    ## subdirectory named "html" in the current working directory.
-    options.outputDir = fullfile (file_path, "html");
-  elseif (! ischar (options.outputDir))
-    error ("publish: OUTPUTDIR must be a string");
-  endif
-
-  if (! isfield (options, "stylesheet"))
-    options.stylesheet = "";
-  elseif (! ischar (options.stylesheet))
-    error ("publish: STYLESHEET must be a string");
-  endif
-
-  ## Options for the figures
-  if (! isfield (options, "createThumbnail"))
-    options.createThumbnail = true;
-  elseif (! isscalar (options.createThumbnail)
-          || ! isreal (options.createThumbnail))
-    error ("publish: CREATETHUMBNAIL must be TRUE or FALSE");
-  endif
-
-  if (! isfield (options, "figureSnapMethod"))
-    options.figureSnapMethod = "entireGUIWindow";
-  else
-    options.figureSnapMethod = validatestring (options.figureSnapMethod, ...
-      {"entireGUIWindow", "print", "getframe", "entireFigureWindow"});
-    ## FIXME: implement other SnapMethods
-    warning ("publish: option FIGURESNAPMETHOD currently not supported");
-  endif
-
-  if (! isfield (options, "imageFormat"))
-    switch (options.format)
-      case "latex"
-        options.imageFormat = "epsc2";
-      case "pdf"
-        ## Note: Matlab R2016a uses bmp as default
-        options.imageFormat = "jpg";
-      otherwise
-        options.imageFormat = "png";
-    endswitch
-  elseif (! ischar (options.imageFormat))
-    error ("publish: IMAGEFORMAT must be a string");
-  else
-    ## Check valid imageFormat for chosen format
-    ##   html, latex, and xml accept any imageFormat
-    switch (options.format)
-      case {"doc", "ppt"}
-        options.imageFormat = validatestring (options.imageFormat,
-                                              {"png", "jpg", "bmp", "tiff"});
-      case "pdf"
-        options.imageFormat = validatestring (options.imageFormat,
-                                              {"bmp", "jpg"});
-    endswitch
-  endif
-
-  if (! isfield (options, "maxHeight"))
-    options.maxHeight = [];
-  elseif (! isscalar (options.maxHeight) || options.maxHeight < 1)
-    error ("publish: MAXHEIGHT must be a positive integer");
-  else
-    options.maxHeight = uint64 (options.maxHeight);
-  endif
-
-  if (! isfield (options, "maxWidth"))
-    options.maxWidth = [];
-  elseif (! isscalar (options.maxWidth) || options.maxWidth < 1)
-    error ("publish: MAXWIDTH must be a positive integer");
-  else
-    options.maxWidth = uint64 (options.maxWidth);
-  endif
-
-  if (! isfield (options, "useNewFigure"))
-    options.useNewFigure = true;
-  elseif (! isscalar (options.useNewFigure) || ! isreal (options.useNewFigure))
-    error ("publish: USENEWFIGURE must be TRUE or FALSE");
-  endif
-
-  ## Options for the code
-  if (! isfield (options, "evalCode"))
-    options.evalCode = true;
-  elseif (! isscalar (options.evalCode) || ! isreal (options.evalCode))
-    error ("publish: EVALCODE must be TRUE or FALSE");
-  endif
-
-  if (! isfield (options, "catchError"))
-    options.catchError = true;
-  elseif (! isscalar (options.catchError) || ! isreal (options.catchError))
-    error ("publish: CATCHERROR must be TRUE or FALSE");
-  endif
-
-  if (! isfield (options, "codeToEvaluate"))
-    options.codeToEvaluate = "";
-  elseif (! ischar (options.codeToEvaluate))
-    error ("publish: CODETOEVALUTE must be a string");
-  endif
-
-  if (! isfield (options, "maxOutputLines"))
-    options.maxOutputLines = Inf;
-  elseif (! isscalar (options.maxOutputLines) || options.maxOutputLines < 0)
-    error ("publish: MAXOUTPUTLINES must be an integer >= 0");
-  else
-    options.maxOutputLines = uint64 (options.maxOutputLines);
-  endif
-
-  if (! isfield (options, "showCode"))
-    options.showCode = true;
-  elseif (! isscalar (options.showCode) || ! isreal (options.showCode))
-    error ("publish: SHOWCODE must be TRUE or FALSE");
-  endif
-
-  doc.title = "";
-  doc.intro = "";
-  doc.body = cell ();
-  doc.m_source = deblank (read_file_to_cellstr (file));
-  doc.m_source_file_name = file;
-
-  ## Split code and paragraphs, find formatting
-  doc = parse_m_source (doc);
-
-  ## Create output directory
-  [status, msg] = mkdir (options.outputDir);
-  if (status != 1)
-    error ("publish: cannot create output directory: %s", msg);
-  endif
-
-  if (options.evalCode)
-    doc = eval_code (doc, options);
-  endif
-
-  output_file = create_output (doc, options);
-
-endfunction
-
-
-function doc = parse_m_source (doc)
-  ## PARSE_M_SOURCE First parsing level
-  ##   This function extracts the overall structure (paragraphs and code
-  ##   sections) given in doc.m_source.
-  ##
-  ##   The result is written to doc.body, which then contains a cell
-  ##   vector of structs, either of
-  ##
-  ##     a) {struct ("type", "code", ...
-  ##                 "lines", [a, b], ...
-  ##                 "output", [])}
-  ##     b) {struct ("type", "section", ...
-  ##                 "content", title_str)}
-  ##
-  ##   Second parsing level is invoked for the paragraph contents, resulting
-  ##   in more elements for doc.body.
-
-  if (isempty (doc.m_source))
-    return;  # Nothing to parse
-  endif
-
-  ## Parsing helper functions
-  ##
-  ## 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) == " "));
-  ## 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
-  is_head = @(cstr) is_publish_markup (cstr, 2);
-  ## Checks line of cellstring to be a headline without section break, using
-  ## the cell mode in Matlab (for compatibility), just treated as a new head.
-  is_no_break_head = @(cstr) is_publish_markup (cstr, 3);
-
-  ## Find the indices of paragraphs starting with "%%", "##", or "%%%"
-  par_start_idx = find (cellfun (is_head, doc.m_source)
-                        | cellfun (is_no_break_head, doc.m_source));
-
-  ## If the whole document is code
-  if (isempty (par_start_idx))
-    doc.body{end+1}.type = "code";
-    doc.body{end}.content = strtrim (strjoin (doc.m_source, "\n"));
-    doc.body{end}.lines = [1, length(doc.m_source)];
-    doc.body{end}.output = {};
-    return;
-  endif
-
-  ## Determine continuous range of paragraphs
-  par_end_idx = [par_start_idx(2:end) - 1, length(doc.m_source)];
-  for i = 1:numel (par_end_idx)
-    idx = find (! cellfun (is_paragraph,
-                           doc.m_source(par_start_idx(i) + 1:par_end_idx(i))));
-    if (! isempty (idx))
-      par_end_idx(i) = par_start_idx(i) + idx(1) - 1;
-    endif
-  endfor
-  ## Code sections between paragraphs
-  code_start_idx = par_end_idx(1:end-1) + 1;
-  code_end_idx = par_start_idx(2:end) - 1;
-  ## Code at the beginning?
-  if (par_start_idx(1) > 1)
-    code_start_idx = [1, code_start_idx];
-    code_end_idx = [par_start_idx(1) - 1, code_end_idx];
-  endif
-  ## Code at the end?
-  if (par_end_idx(end) < length (doc.m_source))
-    code_start_idx = [code_start_idx, par_end_idx(end) + 1];
-    code_end_idx = [code_end_idx, length(doc.m_source)];
-  endif
-  ## Remove overlaps
-  idx = code_start_idx > code_end_idx;
-  code_start_idx(idx) = [];
-  code_end_idx(idx) = [];
-  ## Remove empty code blocks
-  idx = [];
-  for i = 1:numel (code_start_idx)
-    if (all (cellfun (@(cstr) isempty (char (cstr)),
-                      doc.m_source(code_start_idx(i):code_end_idx(i)))))
-      idx = [idx, i];
-    endif
-  endfor
-  code_start_idx(idx) = [];
-  code_end_idx(idx) = [];
-
-  ## Try to find a document title and introduction text
-  ##   1. First paragraph must start in first line
-  ##   2. Second paragraph must start before any code
-  title_offset = 0;
-  if (is_head (doc.m_source{1})
-      && ! isempty (par_start_idx)
-      && par_start_idx(1) == 1
-      && (isempty (code_start_idx)
-          || (length (par_start_idx) > 1
-              && par_start_idx(2) < code_start_idx(1))))
-    doc.title = doc.m_source{1};
-    doc.title = doc.title(4:end);
-    content = doc.m_source(2:par_end_idx(1));
-    ## Strip leading "# "
-    content = cellfun (@(c) cellstr (c(3:end)), content);
-    doc.intro = parse_paragraph_content (content);
-    title_offset = 1;
-  endif
-
-  ## Add non-empty paragraphs and code to doc
-  j = 1;
-  i = (1 + title_offset);
-  while (i <= numel (par_start_idx) || j <= numel (code_start_idx))
-    ## Add code while there is code left
-    ##   and code is before the next paragraph or there are no more paragraphs
-    while (j <= numel (code_start_idx)
-           && (i > numel (par_start_idx)
-               || par_start_idx(i) > code_start_idx(j)))
-      doc.body{end+1}.type = "code";
-      lines = [code_start_idx(j), code_end_idx(j)];
-      doc.body{end}.content = ...
-        strtrim (strjoin (doc.m_source(lines(1):lines(2)), "\n"));
-      doc.body{end}.lines = lines;
-      doc.body{end}.output = {};
-      j++;
-    endwhile
-
-    if (i <= numel (par_start_idx))
-      type_str = "section";
-      title_str = doc.m_source{par_start_idx(i)};
-      if (is_head (doc.m_source(par_start_idx(i))))
-        title_str = title_str(4:end);
-      else
-        title_str = title_str(5:end);
-      endif
-      ## Append, if paragraph title is given
-      if (! isempty (title_str))
-        doc.body{end+1}.type = type_str;
-        doc.body{end}.content = title_str;
-      endif
-
-      content = doc.m_source(par_start_idx(i) + 1:par_end_idx(i));
-      ## Strip leading "# "
-      content = cellfun (@(c) cellstr (c(3:end)), content);
-      doc.body = [doc.body, parse_paragraph_content(content)];
-      i++;
-    endif
-  endwhile
-
-endfunction
-
-
-function p_content = parse_paragraph_content (content)
-  ## PARSE_PARAGRAPH_CONTENT second parsing level
-  ##
-  ##   Parses the content of a paragraph (without potential title) and
-  ##   returns a cell vector of structs, that can be appended to doc.body,
-  ##   either of
-  ##
-  ##     a) {struct ("type", "preformatted_code", ...
-  ##                 "content", code_str)}
-  ##     b) {struct ("type", "preformatted_text", ...
-  ##                 "content", text_str)}
-  ##     c) {struct ("type", "bulleted_list", ...
-  ##                 "content", {"item1", "item2", ..})}
-  ##     d) {struct ("type", "numbered_list", ...
-  ##                 "content", {"item1", "item2", ..})}
-  ##     e) {struct ("type", "include", ...
-  ##                 "content", file_str)}
-  ##     f) {struct ("type", "graphic", ...
-  ##                 "content", file_str)}
-  ##     g) {struct ("type", "html", ...
-  ##                 "content", html_str)}
-  ##     h) {struct ("type", "latex", ...
-  ##                 "content", latex_str)}
-  ##     i) {struct ("type", "text", ...
-  ##                 "content", text_str)}
-  ##
-  ##   Option i) might contain:
-  ##
-  ##     * Italic "_", bold "*", and monospaced "|" text
-  ##     * Inline "$" and block "$$" LaTeX math
-  ##     * Links
-  ##     * Trademark symbols
-
-  p_content = cell ();
-
-  if (isempty (content))
-    return;
-  endif
-
-  ## Extract <html> and <latex> blocks recursively.
-  content_str = strjoin (content, "\n");
-  tags = {"html", "latex"};
-  for i = 1:length(tags)
-    tok = regexp (content_str, ...
-      ['(.*?)(^|\n\n)(<', tags{i}, '>)\n(.*?)\n(<\/', ...
-        tags{i}, '>)($|\n\n)(.*)'], "tokens", "once");
-    if (! isempty (tok))
-      ## If there was some text before that block --> recursion
-      if (! strcmpi (tok{1}, ["<", tags{i}, ">"]))
-        p_content = parse_paragraph_content (strsplit (tok{1}, "\n"));
-        tok(1:2) = [];
-      endif
-      ## Extract the block content
-      p_content{end+1}.type = tags{i};
-      p_content{end}.content = tok{2};
-      ## If there was some text after that block --> recursion
-      if (length (tok) == 5)
-        p_content = [p_content, ...
-          parse_paragraph_content(strsplit (tok{5}, "\n"))];
-      endif
-      return;
-    endif
-  endfor
-
-  ## Split into blocks separated by empty lines
-  idx = [0, find(cellfun (@isempty, content)), length(content) + 1];
-
-  ## For each block
-  for i = find (diff (idx) > 1)
-    block = content(idx(i) + 1:idx(i+1) - 1);
-
-    ## Octave code (two leading spaces)
-    if (all (cellfun (@(c) strncmp (char (c), "  ", 2), block)))
-      p_content{end+1}.type = "preformatted_code";
-      block = cellfun (@(c) cellstr (c(3:end)), block);
-      p_content{end}.content = strjoin (block, "\n");
-      continue;
-    endif
-
-    ## Preformatted text (one leading space)
-    if (all (cellfun (@(c) strncmp (char (c), " ", 1), block)))
-      p_content{end+1}.type = "preformatted_text";
-      block = cellfun (@(c) cellstr (c(2:end)), block);
-      p_content{end}.content = strjoin (block, "\n");
-      continue;
-    endif
-
-    ## Bulleted list starts with "* "
-    if (strncmp (block{1}, "* ", 2))
-      p_content{end+1}.type = "bulleted_list";
-      tmpstr = strjoin (block, "\n");
-      ## Remove first "* "
-      tmpstr = tmpstr(3:end);
-      ## Split items
-      p_content{end}.content = strsplit (tmpstr, "\n* ");
-      continue;
-    endif
-
-    ## Numbered list starts with "# "
-    if (strncmp (block{1}, "# ", 2))
-      p_content{end+1}.type = "numbered_list";
-      tmpstr = strjoin (block, "\n");
-      ## Remove first "# "
-      tmpstr = tmpstr(3:end);
-      ## Split items
-      p_content{end}.content = strsplit (tmpstr, "\n# ");
-      continue;
-    endif
-
-    ## Include <include>fname.m</include>
-    if (! isempty (fname = regexpi (strjoin (block, ""),
-                                    '^<include>(.*)</include>$',
-                                    "tokens")))
-      ## Includes result in preformatted code
-      p_content{end+1}.type = "preformatted_code";
-      include_code = read_file_to_cellstr (strtrim ((fname{1}){1}));
-      p_content{end}.content = strjoin (include_code, "\n");
-
-      continue;
-    endif
-
-    ## Graphic <<myGraphic.png>>
-    if (! isempty (fname = regexpi (strjoin (block, ""),
-                                    '^<<(.*)>>$',
-                                    "tokens")))
-      p_content{end+1}.type = "graphic";
-      p_content{end}.content = strtrim ((fname{1}){1});
-      continue;
-    endif
-
-    ## Now it can be only normal text or markups belonging to normal text
-    ## that are handled while output generation:
-    ##
-    ## * Italic "_", bold "*", and monospaced "|" text
-    ## * Inline "$" and block "$$" LaTeX math
-    ## * Links
-    ## * Trademark symbols
-    p_content{end+1}.type = "text";
-    p_content{end}.content = strjoin (block, "\n");
-  endfor
-endfunction
-
-
-function m_source = read_file_to_cellstr (file)
-  ## READ_FILE_TO_CELLSTR reads a given file line by line into a cellstring
-
-  fid = fopen (file, "r");
-  i = 0;
-  do
-    m_source{++i} = fgetl (fid);
-  until (! ischar (m_source{i}))
-  fclose (fid);
-  m_source = m_source(1:end-1);  # No EOL
-endfunction
-
-
-function ofile = create_output (doc, options)
-  ## CREATE_OUTPUT creates the desired output file
-
-  formatter = [];
-  switch (options.format)
-    case "html"
-      formatter = @__publish_html_output__;
-    case {"latex", "pdf"}
-      formatter = @__publish_latex_output__;
-    otherwise
-      ## Custom formatter
-      formatter = eval (["@__publish_", options.format, "_output__"]);
-  endswitch
-
-  ## Use title, or if not given, the m-file name
-  title_str = doc.title;
-  if (isempty (title_str))
-    [~, title_str] = fileparts (doc.m_source_file_name);
-  endif
-
-  content = formatter ("header",
-                       formatter ("escape_special_chars", title_str),
-                       format_output (doc.intro, formatter, options),
-                       get_toc (doc.body, formatter));
-  content = [content, format_output(doc.body, formatter, options)];
-  content = [content, formatter("footer", strjoin (doc.m_source, "\n"))];
-
-  ## Write file
-  [~, ofile] = fileparts (doc.m_source_file_name);
-  ofile_name = [ofile, formatter("output_file_extension")];
-  ofile = fullfile (options.outputDir, ofile_name);
-  fid = fopen (ofile, "w");
-  fputs (fid, content);
-  fclose (fid);
-
-  ## Compile LaTeX, if compiler found
-  if (strcmp (options.format, "pdf"))
-    status = system ("pdflatex --version");
-    if (status == 0)
-      for i = 1:2
-        ## FIXME: This looks very likely to break when switching OS
-        system (["cd ", options.outputDir," && pdflatex ", ofile_name]);
-      endfor
-    endif
-  endif
-endfunction
-
-
-function toc_cstr = get_toc (cstr, formatter)
-  ## GET_TOC extracts the table of contents from a cellstring (e.g., doc.body)
-  ## with each section headline as a cell in a returned cellstring.
-
-  toc_cstr = cell ();
-  for i = 1:numel (cstr)
-    if (strcmp (cstr{i}.type, "section"))
-      toc_cstr{end+1} = format_text (cstr{i}.content, formatter);
-    endif
-  endfor
-endfunction
-
-
-function str = format_output (cstr, formatter, options)
-  ## FORMAT_OUTPUT steps through all blocks (doc.intro or doc.body) in cstr and
-  ## produces a single result string with the source code in the desired output
-  ## format.
-  ##
-  ##   formatter has the only knowledge how to enforce the target format
-  ##   and produces for each block the necessary target format source string.
-
-  str = "";
-  for i = 1:numel (cstr)
-    switch (cstr{i}.type)
-      case "code"
-        if (options.showCode)
-          str = [str, formatter("code", cstr{i}.content)];
-        endif
-        if ((options.evalCode) && (! isempty (cstr{i}.output)))
-          str = [str, formatter("code_output", cstr{i}.output)];
-        endif
-      case {"text", "section"}
-        str = [str, formatter(cstr{i}.type, ...
-                              format_text (cstr{i}.content, formatter))];
-      case {"bulleted_list", "numbered_list"}
-        items = cellfun (@(str) format_text(str, formatter), ...
-                         cstr{i}.content, "UniformOutput", false);
-        str = [str, formatter(cstr{i}.type, items)];
-      otherwise
-        str = [str, formatter(cstr{i}.type, cstr{i}.content)];
-    endswitch
-  endfor
-
-endfunction
-
-
-function str = format_text (str, formatter)
-  ## FORMAT_TEXT formats inline formats in strings.
-  ##   These are: links, block/inline math, bold, italic, monospaced, (TM), (R)
-
-  ## Helper to clarify the following regular expressions.  It is suitable for
-  ## inline formatting, that is delimited literally at start and end by
-  ## `delim`.  `term` is an indicating character for the end delimiter.
-  ##
-  ## Best explained by example ('^' start and '$' end of input):
-  ##
-  ##  Positive matches:
-  ##
-  ##    ^*bold*$
-  ##    ^*bold*.$
-  ##    ^(*bold*)$
-  ##    ^ *bold* $
-  ##    ^Text *bold* text$
-  ##    ^*bold text*$
-  ##
-  ##  Negative matches:
-  ##
-  ##    ^Text*bold*text$
-  ##    ^*bold *$
-  ##    ^* bold* $
-  ##    ^*bold text *$
-  ##
-  regex_helper = @(delim, term) ['(^|(?<=\s)|(?=\W))', delim, ...
-    '(?!\s)[^', term, ']*(?<!\s)', delim, '($|(?=\s)|(?=\W))'];
-
-  ## Regular expressions for the formats:
-  ##
-  ## 1) Links "<http://www.someurl.com>"
-  ## 2) Links "<octave:Function TEXT>"
-  ## 3) Links "<http://www.someurl.com TEXT>"
-  ## 4) LaTeX block math "$$x^2$$"
-  ## 5) LaTeX inline math "$x^2$"
-  ## 6) Bold *text*
-  ## 7) Italic _text_
-  ## 8) Monospaced |text|
-  ## 9) (TM) or (R)
-  regexes = {'<\S{3,}[^\s<>]*>', ...
-             '<octave:[^\s<>]* *[^<>$]*>', ...
-             '<\S{3,}[^\s<>]* *[^<>$]*>', ...
-             regex_helper('\$\$', '$'), ...
-             regex_helper('\$', '$'), ...
-             regex_helper('\*', '*'), ...
-             regex_helper('_', '_'), ...
-             regex_helper('\|', '|'), ...
-             '\((TM|R)\)'};
-
-  ## Function to escape some special characters for the GNU Octave manual,
-  ## see https://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html
-  texinfo_esc = @(str) strrep (strrep (str, "-", "_002d"), "_", "_005f");
-
-  ## Substitute all occurrences with placeholders
-  placeholder_cstr = {};
-  plh = 0;
-  for i = 1:numel (regexes)
-    cstr = regexp (str, regexes{i}, "match");
-    for j = 1:numel (cstr)
-      plh += 1;
-      str = regexprep (str, regexes{i}, ["PUBLISHPLACEHOLDER" num2str(plh)],
-                       "once");
-      switch (i)
-        case 1
-          ## Links "<http://www.someurl.com>"
-          url = cstr{j};
-          cstr{j} = formatter ("link", url(2:end-1), url(2:end-1));
-        case 2
-          ## Links "<octave:Function TEXT>"
-          idx = strfind (cstr{j}, " ");
-          url = cstr{j};
-          url = texinfo_esc (url(9:idx-1));
-          v = version ();
-          if (v(end) == '+')
-            v = "interpreter";
-          endif
-          url = sprintf ( ...
-            "https://www.gnu.org/software/octave/doc/%s/XREF%s.html", v, url);
-          txt = cstr{j};
-          txt = format_text (txt(idx+1:end-1), formatter);
-          cstr{j} = formatter ("link", url, txt);
-        case 3
-          ## Links "<http://www.someurl.com TEXT>"
-          idx = strfind (cstr{j}, " ");
-          url = cstr{j};
-          url = url(2:idx-1);
-          txt = cstr{j};
-          txt = format_text (txt(idx+1:end-1), formatter);
-          cstr{j} = formatter ("link", url, txt);
-        case 4
-          ## LaTeX block math "$$"
-          txt = cstr{j};
-          cstr{j} = formatter ("blockmath", txt(3:end-2));
-        case 5
-          ## LaTeX inline math "$"
-          txt = cstr{j};
-          cstr{j} = formatter ("inlinemath", txt(2:end-1));
-        case 6
-          ## Bold
-          txt = cstr{j};
-          cstr{j} = formatter ("bold", format_text (txt(2:end-1), formatter));
-        case 7
-          ## Italic
-          txt = cstr{j};
-          cstr{j} = formatter ("italic", format_text (txt(2:end-1), formatter));
-        case 8
-          ## Monospaced
-          txt = cstr{j};
-          cstr{j} = formatter ("monospaced", format_text (txt(2:end-1), ...
-                               formatter));
-        case 9
-          ## (TM) or (R)
-          txt = cstr{j};
-          cstr{j} = formatter (txt(2:end-1));
-      endswitch
-    endfor
-    placeholder_cstr = [placeholder_cstr, cstr];
-  endfor
-
-  ## Replace special symbols
-  str = formatter ("escape_special_chars", str);
-
-  ## Restore placeholders
-  for i = plh:-1:1
-    str = strrep (str, ["PUBLISHPLACEHOLDER" sprintf("%d", i)],
-                       placeholder_cstr{i});
-  endfor
-
-endfunction
-
-
-function doc = eval_code (doc, options)
-  ## EVAL_CODE Third level parsing
-  ##
-  ##   Generates the output of the script code and takes care of generated
-  ##   figures.
-
-  ## Necessary as the code does not run interactively
-  page_screen_output (false, "local");
-
-  ## Remember previously opened figures
-  fig_ids = findall (0, "type", "figure");
-  [~, fig_name] = fileparts (doc.m_source_file_name);
-  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);
-
-  ## Create a new figure, if there are existing plots
-  if (! isempty (fig_ids) && options.useNewFigure)
-    figure ();
-  endif
-
-  for i = 1:numel (doc.body)
-    if (strcmp (doc.body{i}.type, "code"))
-      r = doc.body{i}.lines;
-      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);
-         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);
-      endif
-
-      ## Check for newly created figures ...
-      fig_ids_new = setdiff (findall (0, "type", "figure"), fig_ids);
-      ## ... and save them
-      for j = 1:numel (fig_ids_new)
-        drawnow ();
-        if (isempty (get (fig_ids_new(j), "children")))
-          continue;
-        endif
-        fname = [fig_name, "-", sprintf("%d", fig_num)];
-        if (strncmp (options.imageFormat, "eps", 3))
-          fname = [fname ".eps"];
-        else
-          fname = [fname "." options.imageFormat];
-        endif
-        print_opts = {fig_ids_new(j), ...
-                      fullfile(options.outputDir, fname), ...
-                      ["-d" options.imageFormat], "-color"};
-        if (! isempty (options.maxWidth) && ! isempty (options.maxHeight))
-          print_opts{end+1} = sprintf ("-S%d,%d", options.maxWidth,
-                                                  options.maxHeight);
-        elseif (! isempty (options.maxWidth) || ! isempty (options.maxHeight))
-          warning (["publish: specify both options.maxWidth ", ...
-                              "and options.maxHeight"]);
-        endif
-        print (print_opts{:});
-        fig_num++;
-        delete (fig_ids_new(j));
-        fig_elem = cell ();
-        fig_elem{1} = struct ("type", "graphic", "content", fname);
-        if (isfield (fig_list, num2str (i)))
-          fig_elem = [getfield(fig_list, sprintf ("%d", i)), fig_elem];
-        endif
-        fig_list = setfield (fig_list, sprintf ("%d", i), fig_elem);
-        ## Create a new figure, if there are existing plots
-        if (isempty (setdiff (findall (0, "type", "figure"), fig_ids)) ...
-            && ! isempty (fig_ids) && options.useNewFigure)
-          figure ();
-        endif
-      endfor
-
-      ## Truncate output to desired length
-      if (options.maxOutputLines < length (doc.body{i}.output))
-        doc.body{i}.output = doc.body{i}.output(1:options.maxOutputLines);
-      endif
-      doc.body{i}.output = strjoin (doc.body{i}.output, "\n");
-    endif
-  endfor
-
-  ## 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;
-  for i = 1:numel (fig_code_blocks)
-    elems = getfield (fig_list, fig_code_blocks{i});
-    ## Compute index where the figure(s) has to be inserted
-    j = str2double (fig_code_blocks{i}) + body_offset;
-    doc.body = [doc.body(1:j), elems, doc.body(j+1:end)];
-    body_offset = body_offset + numel (elems);
-  endfor
-
-endfunction
-
-
-function cstr = eval_code_helper (context, 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))
-    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");
-endfunction
-
-
-## FIXME: Missing any functional BIST tests
-## FIXME: Need to create a temporary file for use with error testing
-
-## Test input validation
-%!error publish ()
-%!error publish (1)
-%!error <FILE does not exist> publish ("%%_non_existent_file_%%.m")
-%!error <only script files can be published> publish ("publish.m")
-%!error publish ("test_script.m", "format", "html", "showCode")
--- a/scripts/general/saveobj.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-## Copyright (C) 2008-2017 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
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {} {@var{b} =} saveobj (@var{a})
-## Method of a class to manipulate an object prior to saving it to a file.
-##
-## The function @code{saveobj} is called when the object @var{a} is saved
-## using the @code{save} function.  An example of the use of @code{saveobj}
-## might be to remove fields of the object that don't make sense to be saved
-## or it might be used to ensure that certain fields of the object are
-## initialized before the object is saved.  For example:
-##
-## @example
-## @group
-## function b = saveobj (a)
-##   b = a;
-##   if (isempty (b.field))
-##      b.field = initfield (b);
-##   endif
-## endfunction
-## @end group
-## @end example
-##
-## @seealso{loadobj, class}
-## @end deftypefn
-
-function b = saveobj (a)
-  error ('saveobj: not defined for class "%s"', class (a));
-endfunction
--- a/scripts/general/validateattributes.m	Thu Dec 28 15:56:09 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,732 +0,0 @@
-## Copyright (C) 2013-2017 Carnë Draug
-## Copyright (C) 2016 Carlo de Falco
-##
-## 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  {} {} validateattributes (@var{A}, @var{classes}, @var{attributes})
-## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{arg_idx})
-## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name})
-## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name})
-## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name}, @var{arg_idx})
-## Check validity of input argument.
-##
-## Confirms that the argument @var{A} is valid by belonging to one of
-## @var{classes}, and holding all of the @var{attributes}.  If it does not,
-## an error is thrown, with a message formatted accordingly.  The error
-## message can be made further complete by the function name @var{fun_name},
-## the argument name @var{arg_name}, and its position in the input
-## @var{arg_idx}.
-##
-## @var{classes} must be a cell array of strings (an empty cell array is
-## allowed) with the name of classes (remember that a class name is case
-## sensitive).  In addition to the class name, the following categories
-## names are also valid:
-##
-## @table @asis
-## @item @qcode{"float"}
-## Floating point value comprising classes @qcode{"double"} and
-## @qcode{"single"}.
-##
-## @item @qcode{"integer"}
-## Integer value comprising classes (u)int8, (u)int16, (u)int32, (u)int64.
-##
-## @item @qcode{"numeric"}
-## Numeric value comprising either a floating point or integer value.
-##
-## @end table
-##
-## @var{attributes} must be a cell array with names of checks for @var{A}.
-## Some of them require an additional value to be supplied right after the
-## name (see details for each below).
-##
-## @table @asis
-## @item @qcode{"<="}
-## All values are less than or equal to the following value in
-## @var{attributes}.
-##
-## @item @qcode{"<"}
-## All values are less than the following value in @var{attributes}.
-##
-## @item @qcode{">="}
-## All values are greater than or equal to the following value in
-## @var{attributes}.
-##
-## @item @qcode{">"}
-## All values are greater than the following value in @var{attributes}.
-##
-## @item @qcode{"2d"}
-## A 2-dimensional matrix.  Note that vectors and empty matrices have
-## 2 dimensions, one of them being of length 1, or both length 0.
-##
-## @item @qcode{"3d"}
-## Has no more than 3 dimensions.  A 2-dimensional matrix is a 3-D matrix
-## whose 3rd dimension is of length 1.
-##
-## @item @qcode{"binary"}
-## All values are either 1 or 0.
-##
-## @item @qcode{"column"}
-## Values are arranged in a single column.
-##
-## @item @qcode{"decreasing"}
-## No value is @var{NaN}, and each is less than the preceding one.
-##
-## @item @qcode{"diag"}
-## Value is a diagonal matrix.
-##
-## @item @qcode{"even"}
-## All values are even numbers.
-##
-## @item @qcode{"finite"}
-## All values are finite.
-##
-## @item @qcode{"increasing"}
-## No value is @var{NaN}, and each is greater than the preceding one.
-##
-## @item @qcode{"integer"}
-## All values are integer.  This is different than using @code{isinteger}
-## which only checks its an integer type.  This checks that each value in
-## @var{A} is an integer value, i.e., it has no decimal part.
-##
-## @item @qcode{"ncols"}
-## Has exactly as many columns as the next value in @var{attributes}.
-##
-## @item @qcode{"ndims"}
-## Has exactly as many dimensions as the next value in @var{attributes}.
-##
-## @item @qcode{"nondecreasing"}
-## No value is @var{NaN}, and each is greater than or equal to the preceding
-## one.
-##
-## @item @qcode{"nonempty"}
-## It is not empty.
-##
-## @item @qcode{"nonincreasing"}
-## No value is @var{NaN}, and each is less than or equal to the preceding one.
-##
-## @item @qcode{"nonnan"}
-## No value is a @code{NaN}.
-##
-## @item @nospell{@qcode{"nonnegative"}}
-## All values are non negative.
-##
-## @item @qcode{"nonsparse"}
-## It is not a sparse matrix.
-##
-## @item @qcode{"nonzero"}
-## No value is zero.
-##
-## @item @qcode{"nrows"}
-## Has exactly as many rows as the next value in @var{attributes}.
-##
-## @item @qcode{"numel"}
-## Has exactly as many elements as the next value in @var{attributes}.
-##
-## @item @qcode{"odd"}
-## All values are odd numbers.
-##
-## @item @qcode{"positive"}
-## All values are positive.
-##
-## @item @qcode{"real"}
-## It is a non-complex matrix.
-##
-## @item @qcode{"row"}
-## Values are arranged in a single row.
-##
-## @item @qcode{"scalar"}
-## It is a scalar.
-##
-## @item @qcode{"size"}
-## Its size has length equal to the values of the next in @var{attributes}.
-## The next value must is an array with the length for each dimension.  To
-## ignore the check for a certain dimension, the value of @code{NaN} can be
-## used.
-##
-## @item @qcode{"square"}
-## Is a square matrix.
-##
-## @item @qcode{"vector"}
-## Values are arranged in a single vector (column or vector).
-##
-## @end table
-##
-## @seealso{isa, validatestring, inputParser}
-## @end deftypefn
-
-function validateattributes (A, cls, attr, varargin)
-
-  if (nargin < 3 || nargin > 6)
-    print_usage ();
-  elseif (! iscellstr (cls))
-    error ("Octave:invalid-type",
-           "validateattributes: CLASSES must be a cell array of strings");
-  elseif (! iscell (attr))
-    error ("Octave:invalid-type",
-           "validateattributes: ATTRIBUTES must be a cell array");
-  endif
-
-  ## Built start of error message from the extra optional arguments
-  func_name = "";
-  var_name  = "input";
-  if (nargin > 3)
-    fourth = varargin{1};
-    if (ischar (fourth))
-      func_name = [fourth ": "];
-    elseif (nargin == 4 && valid_arg_idx (fourth))
-      var_name = sprintf ("input %d", fourth);
-    else
-      error ("Octave:invalid-input-arg",
-             "validateattributes: 4th input argument must be ARG_IDX or FUNC_NAME");
-    endif
-
-    if (nargin > 4)
-      var_name = varargin{2};
-      if (! ischar (var_name))
-        error ("Octave:invalid-type",
-               "validateattributes: VAR_NAME must be a string");
-      endif
-
-      if (nargin > 5)
-        arg_idx = varargin{3};
-        if (! valid_arg_idx (arg_idx))
-          error ("Octave:invalid-input-arg",
-                 "validateattributes: ARG_IDX must be a positive integer");
-        endif
-        var_name = sprintf ("%s (argument #%i)", var_name, arg_idx);
-      endif
-    endif
-  endif
-  err_ini = [func_name var_name];
-
-  check_cl = isa (A, cls);
-  if (! isempty (check_cl) && ! any (check_cl))
-    ## Allowing for an empty list of classes is Matlab incompatible but
-    ## that should count as a just a Matlab bug, not an incompatibility.
-
-    ## Replace the category names with the classes that belong to it.
-    integer = { "int8"  "int16"  "int32"  "int64" ...
-               "uint8" "uint16" "uint32" "uint64"};
-    float   = {"single" "double"};
-    numeric = {integer{:} float{:}};
-    cls = replace_cl_group (cls, "integer", integer);
-    cls = replace_cl_group (cls, "float",   float  );
-    cls = replace_cl_group (cls, "numeric", numeric);
-    cls = unique (cls);
-
-    classes = sprintf (" %s", cls{:});
-    error ("Octave:invalid-type",
-           "%s must be of class:\n\n %s\n\nbut was of class %s",
-           err_ini, classes, class (A));
-  endif
-
-  ## We use a while loop because some attributes require the following value
-  ## in the cell array.  Also, we can't just get the boolean value for the
-  ## test and check at the end the error message since some of the tests
-  ## require some more complex error message.
-
-  ## It may look like that we don't perform enough input check in this
-  ## function (e.g., we don't check if there's a value after the size
-  ## attribute).  The reasoning is that this will be a function mostly used
-  ## by developers with fairly static input so any problem would be caught
-  ## immediately during that function development, it's no dependent on the
-  ## final user input.  In addition, it can be called so many times at the
-  ## start of every function, we want it to run specially fast.
-  idx = 1;
-  problem = false; # becomes true when one of the tests fails
-  while (idx <= numel (attr))
-    ## FIXME: once we use this in Octave core, it might be worthy to find
-    ## which attributes are checked more often, and place them in that
-    ## order inside the switch block.
-    switch (tolower (attr{idx++}))
-      case "2d",
-        problem = ndims (A) != 2;
-        err_id = "Octave:expected-2d";
-      case "3d",
-        problem = ndims (A) > 3;
-        err_id = "Octave:expected-3d";
-      case "column",
-        problem = ! iscolumn (A);
-        err_id = "Octave:expected-column";
-      case "row",
-        problem = ! isrow (A);
-        err_id = "Octave:expected-row";
-      case "scalar",
-        problem = ! isscalar (A);
-        err_id = "Octave:expected-scalar";
-      case "vector",
-        problem = ! isvector (A);
-        err_id = "Octave:expected-vector";
-      case "square",
-        problem = ! issquare (A);
-        err_id = "Octave:expected-square";
-      case "diag",
-        problem = ! isdiag (A);
-        err_id = "Octave:expected-diag";
-      case "nonempty",
-        problem = isempty (A);
-        err_id = "Octave:expected-nonempty";
-      case "nonsparse",
-        problem = issparse (A);
-        err_id = "Octave:expected-nonsparse";
-      case "binary",
-        problem = ! islogical (A) && ...
-                  any ((A(:) != 1) & (A(:) != 0));
-        err_id = "Octave:expected-binary";
-      case "even",
-        problem = any (rem (A(:), 2) != 0);
-        err_id = "Octave:expected-even";
-      case "odd",
-        problem = any (mod (A(:), 2) != 1);
-        err_id = "Octave:expected-odd";
-      case "integer",
-        problem = ! isinteger (A) && ...
-                  any (ceil (A(:)) != A(:));
-        err_id = "Octave:expected-integer";
-      case "real",
-        problem = ! isreal (A);
-        err_id = "Octave:expected-real";
-      case "finite",
-        problem = ! isinteger (A) && ...
-                  ! all (isfinite (A(:)));
-        err_id = "Octave:expected-finite";
-      case "nonnan",
-        problem = ! isinteger (A) && ...
-                  any (isnan (A(:)));
-        err_id = "Octave:expected-nonnan";
-      case "nonnegative",
-        problem = any (A(:) < 0);
-        err_id = "Octave:expected-nonnegative";
-      case "nonzero",
-        problem = any (A(:) == 0);
-        err_id = "Octave:expected-nonzero";
-      case "positive",
-        problem = any (A(:) <= 0);
-        err_id = "Octave:expected-positive";
-      case "decreasing",
-        problem = (any (isnan (A(:)))
-                   || any (diff (A(:)) >= 0));
-        err_id = "Octave:expected-decreasing";
-      case "increasing",
-        problem = (any (isnan (A(:)))
-                   || any (diff (A(:)) <= 0));
-        err_id = "Octave:expected-increasing";
-      case "nondecreasing",
-        problem = (any (isnan (A(:)))
-                   || any (diff (A(:)) <  0));
-        err_id = "Octave:expected-nondecreasing";
-      case "nonincreasing",
-        problem = (any (isnan (A(:)))
-                   || any (diff (A(:)) >  0));
-        err_id = "Octave:expected-nonincreasing";
-      case "size",
-        A_size = size (A);
-        w_size = attr{idx++};
-        A_size(isnan (w_size)) = NaN;
-        if (! isequaln (A_size, w_size))
-          A_size_str = sprintf ("%dx", size (A))(1:end-1);
-          w_size_str = sprintf ("%ix", w_size)(1:end-1);
-          w_size_str = strrep (w_size_str, "NaN", "N");
-          err_id = "Octave:incorrect-size";
-          error (err_id,
-                 "%s must be of size %s but was %s",
-                 err_ini, w_size_str, A_size_str);
-        endif
-      case "numel",
-        if (numel (A) != attr{idx++})
-          err_id = "Octave:incorrect-numel";
-          error (err_id,
-                 "%s must have %d elements", err_ini, attr{idx-1});
-        endif
-      case "ncols",
-        if (columns (A) != attr{idx++})
-          err_id = "Octave:incorrect-numcols";
-          error (err_id,
-                 "%s must have %d columns", err_ini, attr{idx-1});
-        endif
-      case "nrows",
-        if (rows (A) != attr{idx++})
-          err_id = "Octave:incorrect-numrows";
-          error (err_id,
-                 "%s must have %d rows", err_ini, attr{idx-1});
-        endif
-      case "ndims",
-        ## Note that a [4 5 1] matrix is not considered to have ndims == 3
-        ## but is ok for "3d".  This is not a bug.
-        if (ndims (A) != attr{idx++})
-          err_id = "Octave:incorrect-numdims";
-          error (err_id,
-                 "%s must have %d dimensions", err_ini, attr{idx-1});
-        endif
-      case ">"
-        if (! all (A(:) > attr{idx++}))
-          err_id = "Octave:expected-greater";
-          error (err_id,
-                 "%s must be greater than %f", err_ini, attr{idx-1});
-        endif
-      case ">="
-        if (! all (A(:) >= attr{idx++}))
-          err_id = "Octave:expected-greater-equal";
-          error (err_id,
-                 "%s must be greater than or equal to %f", err_ini, attr{idx-1});
-        endif
-      case "<"
-        if (! all (A(:) < attr{idx++}))
-          err_id = "Octave:expected-less";
-          error (err_id,
-                 "%s must be less than %f", err_ini, attr{idx-1});
-        endif
-      case "<="
-        if (! all (A(:) <= attr{idx++}))
-          err_id = "Octave:expected-less-equal";
-          error (err_id,
-                 "%s must be less than or equal to %f", err_ini, attr{idx-1});
-        endif
-      otherwise
-        err_id = "Octave:invalid-input-arg";
-        error (err_id,
-               "validateattributes: unknown ATTRIBUTE %s", attr{idx-1});
-    endswitch
-    if (problem)
-      error (err_id,
-             "%s must be %s", err_ini, attr{idx-1});
-    endif
-  endwhile
-
-endfunction
-
-function retval = valid_arg_idx (arg)
-  retval = isnumeric (arg) && isscalar (arg) && arg > 0 && arg == fix (arg);
-endfunction
-
-function cls = replace_cl_group (cls, name, group)
-  num_pos = strcmpi (cls, name);
-  if (any (num_pos))
-    cls(num_pos) = [];
-    cls(end+1:end+numel(group)) = group;
-  endif
-endfunction
-
-
-%!error <double> validateattributes (rand (5), {"uint8"}, {})
-%!error <single> validateattributes (uint8 (rand (5)), {"float"}, {})
-%!error <2d> validateattributes (rand (5, 5, 5), {}, {"2d"})
-%!error <3d> validateattributes (rand (5, 5, 5, 7), {}, {"3d"})
-%!error <column> validateattributes (rand (5, 5), {}, {"column"})
-%!error <column> validateattributes (rand (1, 5), {}, {"column"})
-%!error <row> validateattributes (rand (5, 5), {}, {"row"})
-%!error <row> validateattributes (rand (5, 1), {}, {"row"})
-%!error <scalar> validateattributes (rand (1, 5), {}, {"scalar"})
-%!error <vector> validateattributes (rand (5), {}, {"vector"})
-%!error <square> validateattributes (rand (5, 6), {}, {"square"})
-%!error <nonempty> validateattributes ([], {}, {"nonempty"})
-%!error <nonsparse> validateattributes (sparse(rand(5)), {}, {"nonsparse"})
-%!error <binary> validateattributes ("text", {}, {"binary"})
-%!error <binary> validateattributes ([0 1 0 3 0], {}, {"binary"})
-%!error <even> validateattributes ([2 3 6 8], {}, {"even"})
-%!error <even> validateattributes ([2 NaN], {}, {"even"})
-%!error <odd> validateattributes ([3 4 7 5], {}, {"odd"})
-%!error <odd> validateattributes ([5 NaN], {}, {"odd"})
-%!error <integer> validateattributes ([5 5.2 5.7], {}, {"integer"})
-%!error <real> validateattributes ([5i 8 9], {}, {"real"})
-%!error <finite> validateattributes ([5i Inf 8], {}, {"finite"})
-%!error <nonnan> validateattributes ([NaN Inf 8], {}, {"nonnan"})
-%!error <nonnegative> validateattributes ([7 8 -9], {}, {"nonnegative"})
-%!error <nonzero> validateattributes ([7 8 0], {}, {"nonzero"})
-%!error <positive> validateattributes ([7 0 8], {}, {"positive"})
-%!error <decreasing> validateattributes ([7 8 4 3 -5], {}, {"decreasing"})
-%!error <decreasing> validateattributes ([7 NaN 4 3 -5], {}, {"decreasing"})
-%!error <increasing> validateattributes ([7 8 4 9 20], {}, {"increasing"})
-%!error <increasing> validateattributes ([7 8 NaN 9 20], {}, {"increasing"})
-%!error <nonincreasing> validateattributes ([7 8 4 9 20], {}, {"nonincreasing"})
-%!error <nonincreasing> validateattributes ([7 8 NaN 9 20], {}, {"nonincreasing"})
-%!error <nondecreasing> validateattributes ([7 8 4 3 -5], {}, {"nondecreasing"})
-%!error <nondecreasing> validateattributes ([7 NaN 4 3 -5], {}, {"nondecreasing"})
-%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 4 7]})
-%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 NaN 7]})
-%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 3 6 2]})
-%!error <elements> validateattributes (ones (6, 3), {}, {"numel", 12})
-%!error <columns> validateattributes (ones (6, 2), {}, {"ncols", 3})
-%!error <rows> validateattributes (ones (6, 2), {}, {"nrows", 3})
-%!error <dimensions> validateattributes (ones (6, 2, 6, 3), {}, {"ndims", 3})
-%!error <greater than> validateattributes ([6 7 8 5], {}, {">", 5})
-%!error <greater than> validateattributes ([6 7 8 5], {}, {">=", 6})
-%!error <less than> validateattributes ([6 7 8 5], {}, {"<", 8})
-%!error <less than> validateattributes ([6 7 8 5], {}, {"<=", 7})
-%!error <diag> validateattributes ([0 0 0; 0 0 0; 1 0 0], {}, {"diag"})
-%!error <diag> validateattributes (repmat (eye (3), [1 1 3]), {}, {"diag"})
-
-%!test
-%! validateattributes (rand (5), {"numeric"}, {});
-%! validateattributes (rand (5), {"float"}, {});
-%! validateattributes (rand (5), {"double"}, {});
-%! validateattributes ("text", {"char"}, {});
-%! validateattributes (rand (5), {}, {"2d"});
-%! validateattributes (rand (5), {}, {"3d"});
-%! validateattributes (rand (5, 5, 5), {}, {"3d"});
-%! validateattributes (rand (5, 1), {}, {"column"});
-%! validateattributes (rand (1, 5), {}, {"row"});
-%! validateattributes ("a", {}, {"scalar"});
-%! validateattributes (5, {}, {"scalar"});
-%! validateattributes (rand (1, 5), {}, {"vector"});
-%! validateattributes (rand (5, 1), {}, {"vector"});
-%! validateattributes (rand (5), {}, {"square"});
-%! validateattributes (rand (5), {}, {"nonempty"});
-%! validateattributes (rand (5), {}, {"nonsparse"});
-%! validateattributes ([0 1 0 1 0], {}, {"binary"});
-%! validateattributes (rand (5) > 0.5, {}, {"binary"});
-%! validateattributes ([8 4 0 6], {}, {"even"});
-%! validateattributes ([-1 3 5], {}, {"odd"});
-%! validateattributes ([8 4 0 6], {}, {"real"});
-%! validateattributes ([8 4i 0 6], {}, {"finite"});
-%! validateattributes (uint8 ([8 4]), {}, {"finite"});
-%! validateattributes ([8 Inf], {}, {"nonnan"});
-%! validateattributes ([0 7 4], {}, {"nonnegative"});
-%! validateattributes ([-8 7 4], {}, {"nonzero"});
-%! validateattributes ([8 7 4], {}, {"positive"});
-%! validateattributes ([8 7 4 -5], {}, {"decreasing"});
-%! validateattributes ([-8 -7 4 5], {}, {"increasing"});
-%! validateattributes ([8 4 4 -5], {}, {"nonincreasing"});
-%! validateattributes ([-8 -8 4 5], {}, {"nondecreasing"});
-%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 6 7 2]});
-%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 NaN 7 2]});
-%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 6 NaN 2 NaN]});
-%! validateattributes (rand (6, 2), {}, {"numel", 12});
-%! validateattributes (rand (6, 2), {}, {"ncols", 2});
-%! validateattributes (rand (6, 2), {}, {"nrows", 6});
-%! validateattributes (rand (6, 2, 4, 5), {}, {"ndims", 4});
-%! validateattributes ([4 5 6 7], {}, {">", 3});
-%! validateattributes ([4 5 6 7], {}, {">=", 4});
-%! validateattributes ([4 5 6 7], {}, {"<", 8});
-%! validateattributes ([4 5 6 7], {}, {"<=", 7});
-%! validateattributes (eye (3), {}, {"diag"});
-%! validateattributes ([1 0 0; 0 1 0; 0 0 1], {}, {"diag"});
-%! validateattributes (zeros (3), {}, {"diag"});
-
-%!test
-%! validateattributes ([0 1 0 1], {"double", "uint8"}, {"binary", "size", [NaN 4], "nonnan"});
-
-%!test
-%! try validateattributes (ones(1,2,3), {"numeric"}, {"2d"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-2d");
-%! end_try_catch
-
-%!test
-%! try validateattributes (ones(1,2,3,4), {"numeric"}, {"3d"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-3d");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"column"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-column");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2].', {"numeric"}, {"row"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-row");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"scalar"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-scalar");
-%! end_try_catch
-
-%!test
-%! try validateattributes (ones(3), {"numeric"}, {"vector"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-vector");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"size", [1 1]});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:incorrect-size");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"numel", 7});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:incorrect-numel");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"ncols", 7});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:incorrect-numcols");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"nrows", 7});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:incorrect-numrows");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"ndims", 5});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:incorrect-numdims");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"square"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-square");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"diag"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-diag");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([], {"numeric"}, {"nonempty"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonempty");
-%! end_try_catch
-
-%!test
-%! try validateattributes (speye(2), {"numeric"}, {"nonsparse"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonsparse");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {">", 3});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-greater");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {">=", 3});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-greater-equal");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"<", -3});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-less");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"<=", -3});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-less-equal");
-%! end_try_catch
-
-%!test
-%! try validateattributes (3, {"numeric"}, {"binary"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-binary");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1, {"numeric"}, {"even"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-even");
-%! end_try_catch
-
-%!test
-%! try validateattributes (2, {"numeric"}, {"odd"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-odd");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1.1, {"numeric"}, {"integer"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-integer");
-%! end_try_catch
-
-%!test
-%! try validateattributes (1+1i*2, {"numeric"}, {"real"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-real");
-%! end_try_catch
-
-%!test
-%! try validateattributes (Inf, {"numeric"}, {"finite"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-finite");
-%! end_try_catch
-
-%!test
-%! try validateattributes (NaN, {"numeric"}, {"nonnan"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonnan");
-%! end_try_catch
-
-%!test
-%! try validateattributes (-1, {"numeric"}, {"nonnegative"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonnegative");
-%! end_try_catch
-
-%!test
-%! try validateattributes (0, {"numeric"}, {"nonzero"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonzero");
-%! end_try_catch
-
-%!test
-%! try validateattributes (-1, {"numeric"}, {"positive"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-positive");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"decreasing"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-decreasing");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([2 1], {"numeric"}, {"increasing"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-increasing");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 0], {"numeric"}, {"nondecreasing"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nondecreasing");
-%! end_try_catch
-
-%!test
-%! try validateattributes ([1 2], {"numeric"}, {"nonincreasing"});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:expected-nonincreasing");
-%! end_try_catch
-
-%!test
-%! try validateattributes (@sin, {"numeric"}, {});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:invalid-type");
-%! end_try_catch
-
-%!test
-%! try validateattributes (@sin, 1, {});
-%! catch id,
-%! assert (getfield (id, "identifier"), "Octave:invalid-type");
-%! end_try_catch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/fieldnames.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,92 @@
+## Copyright (C) 2012-2017 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{names} =} fieldnames (@var{struct})
+## @deftypefnx {} {@var{names} =} fieldnames (@var{obj})
+## @deftypefnx {} {@var{names} =} fieldnames (@var{javaobj})
+## @deftypefnx {} {@var{names} =} fieldnames ("@var{javaclassname}")
+## Return a cell array of strings with the names of the fields in the
+## specified input.
+##
+## When the input is a structure @var{struct}, the names are the elements of
+## the structure.
+##
+## When the input is an Octave object @var{obj}, the names are the public
+## properties of the object.
+##
+## When the input is a Java object @var{javaobj} or a string containing the
+## name of a Java class @var{javaclassname}, the names are the public fields
+## (data members) of the object or class.
+## @seealso{numfields, isfield, orderfields, struct, methods}
+## @end deftypefn
+
+function names = fieldnames (obj)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (isstruct (obj) || isobject (obj))
+    ## Call internal C++ function for structs or Octave objects
+    names = __fieldnames__ (obj);
+  elseif (isjava (obj) || ischar (obj))
+    ## FIXME: Function prototype that accepts java obj exists, but doesn't
+    ##        work if obj is java.lang.String.  Convert obj to classname.
+    ## FIXME: this is now working for objects whose class is in the dynamic
+    ##        classpath but will continue to fail if such classnames are used
+    ##        instead (see bug #42710).
+    if (isa (obj, "java.lang.String"))
+      obj = class (obj);
+    endif
+    names_str = javaMethod ("getFields", "org.octave.ClassHelper", obj);
+    names = ostrsplit (names_str, ';');
+  else
+    error ("fieldnames: Invalid input argument");
+  endif
+
+endfunction
+
+
+## test preservation of fieldname order
+%!test
+%! x(3).d=1;  x(2).a=2;  x(1).b=3;  x(2).c=3;
+%! assert (fieldnames (x), {"d"; "a"; "b"; "c"});
+
+## test empty structure
+%!test
+%! s = struct ();
+%! assert (fieldnames (s), cell (0, 1));
+
+## test Java classname by passing classname
+%!testif HAVE_JAVA; usejava ("jvm")
+%! names = fieldnames ("java.lang.Double");
+%! assert (any (strcmp (names, "MAX_VALUE")));
+
+## test Java classname by passing java object
+%!testif HAVE_JAVA; usejava ("jvm")
+%! names = fieldnames (javaObject ("java.lang.Double", 10));
+%! assert (any (strcmp (names, "MAX_VALUE")));
+%! assert (all (ismember ({"POSITIVE_INFINITY", "NEGATIVE_INFINITY", ...
+%!                         "NaN", "MAX_VALUE", "MIN_NORMAL", "MIN_VALUE", ...
+%!                         "MAX_EXPONENT", "MIN_EXPONENT", "SIZE", "TYPE"},
+%!                        names)));
+
+%!testif HAVE_JAVA; usejava ("jvm")
+%! names = fieldnames (javaObject ("java.lang.String", "Hello"));
+%! assert (any (strcmp (names, "CASE_INSENSITIVE_ORDER")));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/grabcode.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,97 @@
+## Copyright (C) 2016-2017 Kai T. Ohlhus <k.ohlhus@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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} grabcode (@var{url})
+## @deftypefnx {} {} grabcode (@var{filename})
+## @deftypefnx {} {@var{code_str} =} grabcode (@dots{})
+##
+## Grab the code from a report created by the @code{publish} function.
+##
+## The grabbed code inside the published report must be enclosed by the
+## strings @samp{##### SOURCE BEGIN #####} and @samp{##### SOURCE END #####}.
+## The @code{publish} function creates this format automatically.
+##
+## If no return value is requested the code is saved to a temporary file and
+## opened in the default editor.  NOTE: The temporary file must be saved under
+## a new or the code will be lost.
+##
+## If an output is requested the grabbed code will be returned as string
+## @var{code_str}.
+##
+## Example:
+##
+## @example
+## @group
+## publish ("my_script.m");
+## grabcode ("html/my_script.html");
+## @end group
+## @end example
+##
+## The example above publishes @file{my_script.m} to the default location
+## @file{html/my_script.html}.  Next, the published Octave script is grabbed to
+## edit its content in a new temporary file.
+##
+## @seealso{publish}
+## @end deftypefn
+
+function code_str = grabcode (url)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (exist (url) == 2)
+    ## URL is a local file
+    oct_code = fileread (url);
+  else
+    ## Otherwise, try to read remote URL
+    [oct_code, success, message] = urlread (url);
+    if (! success)
+      error (["grabcode: " message]);
+    endif
+  endif
+
+  ## Extract relevant part
+  oct_code = regexp (oct_code, ...
+    '##### SOURCE BEGIN #####\n(.*)##### SOURCE END #####', "once", "tokens");
+  oct_code = oct_code{1};
+
+  if (nargout == 1)
+    code_str = oct_code;
+  else
+    ## Open temporary file in editor
+    fname = [tempname() ".m"];
+    fid = fopen (fname, "w");
+    if (fid < 0)
+      error ("grabcode: could not open temporary file");
+    endif
+    fprintf (fid, "%s", oct_code);
+    fclose (fid);
+    edit (fname);
+    warndlg (["grabcode: Make sure to save the temporary file\n\n\t", ...
+              fname, "\n\nto a location of your choice. ", ...
+              "Otherwise all grabbed code will be lost!"]);
+  endif
+
+endfunction
+
+
+## Test input validation
+%!error grabcode ()
+%!error grabcode (1,2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/inputParser.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,826 @@
+## Copyright (C) 2011-2017 Carnë Draug
+##
+## 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{p} =} inputParser ()
+## Create object @var{p} of the inputParser class.
+##
+## This class is designed to allow easy parsing of function arguments.  The
+## class supports four types of arguments:
+##
+## @enumerate
+## @item mandatory (see @command{addRequired});
+##
+## @item optional (see @command{addOptional});
+##
+## @item named (see @command{addParameter});
+##
+## @item switch (see @command{addSwitch}).
+## @end enumerate
+##
+## After defining the function API with these methods, the supplied arguments
+## can be parsed with the @command{parse} method and the parsing results
+## accessed with the @command{Results} accessor.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.Parameters
+## Return list of parameter names already defined.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.Results
+## Return structure with argument names as fieldnames and corresponding values.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.Unmatched
+## Return structure similar to @command{Results}, but for unmatched parameters.
+## See the @command{KeepUnmatched} property.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.UsingDefaults
+## Return cell array with the names of arguments that are using default values.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.CaseSensitive = @var{boolean}
+## Set whether matching of argument names should be case sensitive.  Defaults
+## to false.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.FunctionName = @var{name}
+## Set function name to be used in error messages; Defaults to empty string.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.KeepUnmatched = @var{boolean}
+## Set whether an error should be given for non-defined arguments.  Defaults to
+## false.  If set to true, the extra arguments can be accessed through
+## @code{Unmatched} after the @code{parse} method.  Note that since
+## @command{Switch} and @command{Parameter} arguments can be mixed, it is
+## not possible to know the unmatched type.  If argument is found unmatched
+## it is assumed to be of the @command{Parameter} type and it is expected to
+## be followed by a value.
+##
+## @end deftypefn
+## @deftypefn {} {} inputParser.StructExpand = @var{boolean}
+## Set whether a structure can be passed to the function instead of
+## parameter/value pairs.  Defaults to true.
+##
+## The following example shows how to use this class:
+##
+## @example
+## @group
+## function check (varargin)
+## @c The next two comments need to be indented by one for alignment
+##   p = inputParser ();                      # create object
+##   p.FunctionName = "check";                # set function name
+##   p.addRequired ("pack", @@ischar);         # mandatory argument
+##   p.addOptional ("path", pwd(), @@ischar);  # optional argument
+##
+##   ## create a function handle to anonymous functions for validators
+##   val_mat = @@(x) isvector (x) && all (x <= 1) && all (x >= 0);
+##   p.addOptional ("mat", [0 0], val_mat);
+##
+##   ## create two arguments of type "Parameter"
+##   val_type = @@(x) any (strcmp (x, @{"linear", "quadratic"@}));
+##   p.addParameter ("type", "linear", val_type);
+##   val_verb = @@(x) any (strcmp (x, @{"low", "medium", "high"@}));
+##   p.addParameter ("tolerance", "low", val_verb);
+##
+##   ## create a switch type of argument
+##   p.addSwitch ("verbose");
+##
+##   p.parse (varargin@{:@});  # Run created parser on inputs
+##
+##   ## the rest of the function can access inputs by using p.Results.
+##   ## for example, get the tolerance input with p.Results.tolerance
+## endfunction
+## @end group
+## @end example
+##
+## @example
+## @group
+## check ("mech");           # valid, use defaults for other arguments
+## check ();                 # error, one argument is mandatory
+## check (1);                # error, since ! ischar
+## check ("mech", "~/dev");  # valid, use defaults for other arguments
+##
+## check ("mech", "~/dev", [0 1 0 0], "type", "linear");  # valid
+##
+## ## following is also valid.  Note how the Switch argument type can
+## ## be mixed into or before the Parameter argument type (but it
+## ## must still appear after any Optional argument).
+## check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high");
+##
+## ## following returns an error since not all optional arguments,
+## ## `path' and `mat', were given before the named argument `type'.
+## check ("mech", "~/dev", "type", "linear");
+## @end group
+## @end example
+##
+## @emph{Note 1}: A function can have any mixture of the four API types but
+## they must appear in a specific order.  @command{Required} arguments must be
+## first and can be followed by any @command{Optional} arguments.  Only
+## the @command{Parameter} and @command{Switch} arguments may be mixed
+## together and they must appear at the end.
+##
+## @emph{Note 2}: If both @command{Optional} and @command{Parameter} arguments
+## are mixed in a function API then once a string Optional argument fails to
+## validate it will be considered the end of the @command{Optional}
+## arguments.  The remaining arguments will be compared against any
+## @command{Parameter} or @command{Switch} arguments.
+##
+## @seealso{nargin, validateattributes, validatestring, varargin}
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn  {} {} addOptional (@var{argname}, @var{default})
+## @deftypefnx {} {} addOptional (@var{argname}, @var{default}, @var{validator})
+## Add new optional argument to the object @var{parser} of the class
+## inputParser to implement an ordered arguments type of API
+##
+## @var{argname} must be a string with the name of the new argument.  The order
+## in which new arguments are added with @command{addOptional}, represents the
+## expected order of arguments.
+##
+## @var{default} will be the value used when the argument is not specified.
+##
+## @var{validator} is an optional anonymous function to validate the given
+## values for the argument with name @var{argname}.  Alternatively, a
+## function name can be used.
+##
+## See @command{help inputParser} for examples.
+##
+## @emph{Note}: if a string argument does not validate, it will be considered a
+## ParamValue key.  If an optional argument is not given a validator, anything
+## will be valid, and so any string will be considered will be the value of the
+## optional argument (in @sc{matlab}, if no validator is given and argument is
+## a string it will also be considered a ParamValue key).
+##
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn  {} {} addParameter (@var{argname}, @var{default})
+## @deftypefnx {} {} addParameter (@var{argname}, @var{default}, @var{validator})
+## Add new parameter to the object @var{parser} of the class inputParser to
+## implement a name/value pair type of API.
+##
+## @var{argname} must be a string with the name of the new parameter.
+##
+## @var{default} will be the value used when the parameter is not specified.
+##
+## @var{validator} is an optional function handle to validate the given values
+## for the parameter with name @var{argname}.  Alternatively, a function name
+## can be used.
+##
+## See @command{help inputParser} for examples.
+##
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn  {} {} addParamValue (@var{argname}, @var{default})
+## @deftypefnx {} {} addParamValue (@var{argname}, @var{default}, @var{validator})
+## Add new parameter to the object @var{parser} of the class inputParser to
+## implement a name/value pair type of API.
+##
+## This is an alias for @command{addParameter} method without the
+## @qcode{"PartialMatchPriority"} option.  See it for the help text.
+##
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn  {} {} addRequired (@var{argname})
+## @deftypefnx {} {} addRequired (@var{argname}, @var{validator})
+## Add new mandatory argument to the object @var{parser} of inputParser class.
+##
+## This method belongs to the inputParser class and implements an ordered
+## arguments type of API.
+##
+## @var{argname} must be a string with the name of the new argument.  The order
+## in which new arguments are added with @command{addrequired}, represents the
+## expected order of arguments.
+##
+## @var{validator} is an optional function handle to validate the given values
+## for the argument with name @var{argname}.  Alternatively, a function name
+## can be used.
+##
+## See @command{help inputParser} for examples.
+##
+## @emph{Note}: this can be used together with the other type of arguments but
+## it must be the first (see @command{@@inputParser}).
+##
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn {} {} addSwitch (@var{argname})
+## Add new switch type of argument to the object @var{parser} of inputParser
+## class.
+##
+## This method belongs to the inputParser class and implements a switch
+## arguments type of API.
+##
+## @var{argname} must be a string with the name of the new argument.  Arguments
+## of this type can be specified at the end, after @code{Required} and
+## @code{Optional}, and mixed between the @code{Parameter}.  They default to
+## false.  If one of the arguments supplied is a string like @var{argname},
+## then after parsing the value of @var{parse}.Results.@var{argname} will be
+## true.
+##
+## See @command{help inputParser} for examples.
+##
+## @end deftypefn
+
+## -*- texinfo -*-
+## @deftypefn {} {} parse (@var{varargin})
+## Parses and validates list of arguments according to object @var{parser} of
+## the class inputParser.
+##
+## After parsing, the results can be accessed with the @command{Results}
+## accessor.  See @command{help inputParser} for a more complete description.
+##
+## @end deftypefn
+
+## Author: Carnë Draug <carandraug@octave.org>
+
+classdef inputParser < handle
+  properties
+    ## FIXME: set input checking for these properties
+    CaseSensitive = false;
+    FunctionName  = "";
+    KeepUnmatched = false;
+    PartialMatching = false; # FIXME: unimplemented (and default should be true)
+    StructExpand    = true;
+  endproperties
+
+  properties (SetAccess = protected)
+    Parameters    = cell ();
+    Results       = struct ();
+    Unmatched     = struct ();
+    UsingDefaults = cell ();
+  endproperties
+
+  properties (Access = protected)
+    ## Since Required and Optional are ordered, they get a cell array of
+    ## structs with the fields "name", "def" (default), and "val" (validator).
+    Required = cell ();
+    Optional = cell ();
+    ## Parameter and Switch are unordered so we have a struct whose fieldnames
+    ## are the argname, and values are a struct with fields "def" and "val"
+    Parameter = struct ();
+    Switch    = struct ();
+
+    ## List of Parameter and Switch names to ease searches
+    ParameterNames = cell ();
+    SwitchNames    = cell ();
+
+    ## When checking for fieldnames in a Case Insensitive way, this variable
+    ## holds the correct identifier for the last searched named using the
+    ## is_argname method.
+    last_name = "";
+  endproperties
+
+  properties (Access = protected, Constant = true)
+    ## Default validator, always returns scalar true.
+    def_val = @() true;
+  endproperties
+
+  methods
+    function set.PartialMatching (this, val)
+      if (val)
+        error ("inputParser: PartialMatching is not yet implemented");
+      endif
+    endfunction
+
+    function addRequired (this, name, val = inputParser.def_val)
+      if (nargin < 2 || nargin > 3)
+        print_usage ();
+      elseif (numel (this.Optional) || numfields (this.Parameter)
+              || numfields (this.Switch))
+        error (["inputParser.addRequired: can't have a Required argument " ...
+                "after Optional, Parameter, or Switch"]);
+      endif
+      this.validate_name ("Required", name);
+      this.Required{end+1} = struct ("name", name, "val", val);
+    endfunction
+
+    function addOptional (this, name, def, val = inputParser.def_val)
+      if (nargin < 3 || nargin > 4)
+        print_usage ();
+      elseif (numfields (this.Parameter) || numfields (this.Switch))
+        error (["inputParser.Optional: can't have Optional arguments " ...
+                "after Parameter or Switch"]);
+      endif
+      this.validate_name ("Optional", name);
+      this.Optional{end+1} = struct ("name", name, "def", def, "val", val);
+    endfunction
+
+    function addParamValue (this, name, def, val = inputParser.def_val)
+      if (nargin < 3 || nargin > 4)
+        print_usage ();
+      endif
+      this.addParameter (name, def, val);
+    endfunction
+
+    function addParameter (this, name, def, varargin)
+      if (nargin < 3 || nargin > 6)
+        print_usage ();
+      endif
+
+      n_opt = numel (varargin);
+
+      if (n_opt == 0 || n_opt == 2)
+        val = inputParser.def_val;
+      else # n_opt is 1 or 3
+        val = varargin{1};
+      endif
+
+      if (n_opt == 0 || n_opt == 1)
+        match_priority = 1;
+      else # n_opt is 2 or 3
+        if (! strcmpi (varargin{end-1}, "PartialMatchPriority"))
+          error ("inputParser.addParameter: unrecognized option");
+        endif
+        match_priority = varargin{end};
+        validateattributes (match_priority, {"numeric"}, {"positive", "integer"},
+                            "inputParser.addParameter",
+                            "PartialMatchPriority");
+      endif
+
+      this.validate_name ("Parameter", name);
+      this.Parameter.(name).def = def;
+      this.Parameter.(name).val = val;
+    endfunction
+
+    function addSwitch (this, name)
+      if (nargin != 2)
+        print_usage ();
+      endif
+      this.validate_name ("Switch", name);
+      this.Switch.(name).def = false;
+    endfunction
+
+    function parse (this, varargin)
+      this.Results = struct ();
+      this.Unmatched = struct ();
+      this.UsingDefaults = cell ();
+      if (numel (varargin) < numel (this.Required))
+        if (this.FunctionName)
+          print_usage (this.FunctionName);
+        else
+          this.error ("inputParser.parse: not enough input arguments");
+        endif
+      endif
+      pnargin = numel (varargin);
+
+      this.ParameterNames = fieldnames (this.Parameter);
+      this.SwitchNames    = fieldnames (this.Switch);
+
+      ## Evaluate the Required arguments first
+      nReq = numel (this.Required);
+      for idx = 1:nReq
+        req = this.Required{idx};
+        this.validate_arg (req.name, req.val, varargin{idx});
+      endfor
+
+      vidx = nReq;  # current index in varargin
+
+      ## Search for a list of Optional arguments
+      idx  = 0;     # current index on the array of Optional
+      nOpt = numel (this.Optional);
+      while (vidx < pnargin && idx < nOpt)
+        opt = this.Optional{++idx};
+        in  = varargin{++vidx};
+        if ((this.is_argname ("Parameter", in) && vidx < pnargin)
+            || this.is_argname ("Switch", in))
+          ## This looks like an optional parameter/value pair or a
+          ## switch, not an positional option.  This does mean that
+          ## positional options cannot be strings named like parameter
+          ## keys.  See bug #50752.
+          idx -= 1;
+          vidx -= 1;
+          break
+        endif
+        try
+          valid_option = opt.val (in);
+        catch
+          valid_option = false;
+        end_try_catch
+        if (! valid_option)
+          ## If it does not match there's two options:
+          ##    1) input is actually wrong and we should error;
+          ##    2) it's a Parameter or Switch name and we should use
+          ##       the default for the rest;
+          ##    3) it's a struct with the Parameter pairs.
+          if (ischar (in) || (this.StructExpand && isstruct (in)
+                              && isscalar (in)))
+            idx -= 1;
+            vidx -= 1;
+            break
+          else
+            this.error (sprintf (["failed validation of %s\n", ...
+                                  "Validation function: %s"],
+                                 toupper (opt.name), disp(opt.val)));
+          endif
+        endif
+        this.Results.(opt.name) = in;
+      endwhile
+
+      ## Fill in with defaults of missing Optional
+      while (idx++ < nOpt)
+        opt = this.Optional{idx};
+        this.UsingDefaults{end+1} = opt.name;
+        this.Results.(opt.name) = opt.def;
+      endwhile
+
+      ## Search unordered Options (Switch and Parameter)
+      while (vidx++ < pnargin)
+        name = varargin{vidx};
+
+        if (this.StructExpand && isstruct (name) && isscalar (name))
+          expanded_options = [fieldnames(name) struct2cell(name)]'(:);
+          n_new_args = numel (expanded_options) -1;
+          pnargin += n_new_args;
+          varargin(vidx+n_new_args+1:pnargin) = varargin(vidx+1:end);
+          varargin(vidx:vidx+n_new_args) = expanded_options;
+          name = varargin{vidx};
+        endif
+
+        if (! ischar (name))
+          this.error ("non-string for Parameter name or Switch");
+        endif
+
+        if (this.is_argname ("Parameter", name))
+          if (vidx++ > pnargin)
+            this.error (sprintf ("no matching value for option '%s'",
+                                 toupper (name)));
+          endif
+          this.validate_arg (this.last_name,
+                             this.Parameter.(this.last_name).val,
+                             varargin{vidx});
+        elseif (this.is_argname ("Switch", name))
+          this.Results.(this.last_name) = true;
+        else
+          if (vidx++ < pnargin && this.KeepUnmatched)
+            this.Unmatched.(name) = varargin{vidx};
+          else
+            this.error (sprintf ("argument '%s' is not a valid parameter",
+                                 toupper (name)));
+          endif
+        endif
+      endwhile
+      ## Add them to the UsingDefaults list
+      this.add_missing ("Parameter");
+      this.add_missing ("Switch");
+
+    endfunction
+
+    function disp (this)
+      if (nargin != 1)
+        print_usage ();
+      endif
+      printf ("inputParser object with properties:\n\n");
+      b2s = @(x) ifelse (any (x), "true", "false");
+      printf (["   CaseSensitive   : %s\n   FunctionName    : %s\n" ...
+               "   KeepUnmatched   : %s\n   PartialMatching : %s\n" ...
+               "   StructExpand    : %s\n\n"],
+               b2s (this.CaseSensitive), b2s (this.FunctionName),
+               b2s (this.KeepUnmatched), b2s (this.PartialMatching),
+               b2s (this.StructExpand));
+      printf ("Defined parameters:\n\n   {%s}\n",
+              strjoin (this.Parameters, ", "));
+    endfunction
+  endmethods
+
+  methods (Access = private)
+    function validate_name (this, type, name)
+      if (! isvarname (name))
+        error ("inputParser.add%s: NAME is an invalid identifier", method);
+      elseif (any (strcmpi (this.Parameters, name)))
+        ## Even if CaseSensitive is "on", we still shouldn't allow
+        ## two args with the same name.
+        error ("inputParser.add%s: argname '%s' has already been specified",
+               type, name);
+      endif
+      this.Parameters{end+1} = name;
+    endfunction
+
+    function validate_arg (this, name, val, in)
+        if (! val (in))
+          this.error (sprintf ("failed validation of %s with %s",
+                               toupper (name), func2str (val)));
+        endif
+        this.Results.(name) = in;
+    endfunction
+
+    function r = is_argname (this, type, name)
+      if (this.CaseSensitive)
+        r = isfield (this.(type), name);
+        this.last_name = name;
+      else
+        fnames = this.([type "Names"]);
+        l = strcmpi (name, fnames);
+        r = any (l(:));
+        if (r)
+          this.last_name = fnames{l};
+        endif
+      endif
+    endfunction
+
+    function add_missing (this, type)
+      unmatched = setdiff (fieldnames (this.(type)), fieldnames (this.Results));
+      for namec = unmatched(:)'
+        name = namec{1};
+        this.UsingDefaults{end+1} = name;
+        this.Results.(name) = this.(type).(name).def;
+      endfor
+    endfunction
+
+    function error (this, msg)
+      where = "";
+      if (this.FunctionName)
+        where = [this.FunctionName ": "];
+      endif
+      error ("%s%s", where, msg);
+    endfunction
+  endmethods
+
+endclassdef
+
+%!function p = create_p ()
+%!  p = inputParser ();
+%!  p.CaseSensitive = true;
+%!  p.addRequired ("req1", @(x) ischar (x));
+%!  p.addOptional ("op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
+%!  p.addOptional ("op2", 78, @(x) x > 50);
+%!  p.addSwitch ("verbose");
+%!  p.addParameter ("line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
+%!endfunction
+
+## check normal use, only required are given
+%!test
+%! p = create_p ();
+%! p.parse ("file");
+%! r = p.Results;
+%! assert (r.req1, "file");
+%! assert (sort (p.UsingDefaults), sort ({"op1", "op2", "verbose", "line"}));
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "val", 78,    false,     "tree"});
+
+## check normal use, but give values different than defaults
+%!test
+%! p = create_p ();
+%! p.parse ("file", "foo", 80, "line", "circle", "verbose");
+%! r = p.Results;
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "foo", 80,    true,      "circle"});
+
+## check optional is skipped and considered Parameter if unvalidated string
+%!test
+%! p = create_p ();
+%! p.parse ("file", "line", "circle");
+%! r = p.Results;
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "val", 78,    false,     "circle"});
+
+## check case insensitivity
+%!test
+%! p = create_p ();
+%!  p.CaseSensitive = false;
+%! p.parse ("file", "foo", 80, "LiNE", "circle", "vERbOSe");
+%! r = p.Results;
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "foo", 80,    true,      "circle"});
+
+## check KeepUnmatched
+%!test
+%! p = create_p ();
+%! p.KeepUnmatched = true;
+%! p.parse ("file", "foo", 80, "line", "circle", "verbose", "extra", 50);
+%! assert (p.Unmatched.extra, 50);
+
+## check error when missing required
+%!error <not enough input arguments>
+%! p = create_p ();
+%! p.parse ();
+
+## check error when given required does not validate
+%!error <failed validation of >
+%! p = create_p ();
+%! p.parse (50);
+
+## check error when given optional does not validate
+%!error <is not a valid parameter>
+%! p = create_p ();
+%! p.parse ("file", "no-val");
+
+## check error when given Parameter does not validate
+%!error <failed validation of >
+%! p = create_p ();
+%! p.parse ("file", "foo", 51, "line", "round");
+
+## check alternative method (obj, ...) API
+%!function p2 = create_p2 ();
+%!  p2 = inputParser;
+%!  addRequired (p2, "req1", @(x) ischar (x));
+%!  addOptional (p2, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
+%!  addOptional (p2, "op2", 78, @(x) x > 50);
+%!  addSwitch (p2, "verbose");
+%!  addParameter (p2, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
+%!endfunction
+
+## check normal use, only required are given
+%!test
+%! p2 = create_p2 ();
+%! parse (p2, "file");
+%! r = p2.Results;
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "val", 78,    false,     "tree"});
+%! assert (sort (p2.UsingDefaults), sort ({"op1", "op2", "verbose", "line"}));
+
+## check normal use, but give values different than defaults
+%!test
+%! p2 = create_p2 ();
+%! parse (p2, "file", "foo", 80, "line", "circle", "verbose");
+%! r = p2.Results;
+%! assert ({r.req1, r.op1, r.op2, r.verbose, r.line},
+%!         {"file", "foo", 80,    true,      "circle"});
+
+## We must not perform validation of default values
+%!test <*45837>
+%! p = inputParser;
+%! p.addParameter ("Dir", [], @ischar);
+%! p.parse ();
+%! assert (p.Results.Dir, []);
+
+%!test
+%! p = inputParser;
+%! p.addParameter ("positive", -1, @(x) x > 5);
+%! p.parse ();
+%! assert (p.Results.positive, -1);
+
+## Throw an error on validation of optional argument to check that it
+## is caught without preventing continuation into param/value pairs.
+%!test
+%! p = inputParser ();
+%! p.addOptional ("err", "foo", @error);
+%! p.addParameter ("not_err", "bar", @ischar);
+%! p.parse ("not_err", "qux");
+%! assert (p.Results.err, "foo")
+%! assert (p.Results.not_err, "qux")
+
+
+## With more Parameters to test StructExpand
+%!function p3 = create_p3 ();
+%!  p3 = inputParser;
+%!  addOptional (p3, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
+%!  addOptional (p3, "op2", 78, @(x) x > 50);
+%!  addSwitch (p3, "verbose");
+%!  addParameter (p3, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
+%!  addParameter (p3, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
+%!  addParameter (p3, "style", "tt", @(x) any (strcmp (x, {"tt", "f", "i"})));
+%!endfunction
+
+## Test StructExpand
+%!test
+%! p3 = create_p3 ();
+%! p3.parse (struct ("line", "circle", "color", "green"));
+%! assert (p3.Results, struct ("op1", "val", "op2", 78, "verbose", false,
+%!                             "line", "circle", "color", "green",
+%!                             "style", "tt"))
+
+%!test
+%! p3 = create_p3 ();
+%! p3.parse (struct ("line", "circle", "color", "green"), "line", "tree");
+%! assert (p3.Results.line, "tree")
+%! p3.parse ("line", "tree", struct ("line", "circle", "color", "green"));
+%! assert (p3.Results.line, "circle")
+
+%!test # unmatched parameters with StructExpand
+%! p3 = create_p3 ();
+%! p3.KeepUnmatched = true;
+%! p3.parse (struct ("line", "circle", "color", "green", "bar", "baz"));
+%! assert (p3.Unmatched.bar, "baz")
+
+## The validation for the second optional argument throws an error with
+## a struct so check that we can handle it.
+%!test
+%! p3 = create_p3 ();
+%! p3.parse ("foo", struct ("color", "green"), "line", "tree");
+%! assert (p3.Results.op1, "foo")
+%! assert (p3.Results.line, "tree")
+%! assert (p3.Results.color, "green")
+%! assert (p3.Results.verbose, false)
+
+
+## Some simple tests for addParamValue since all the other ones use add
+## addParameter but they use the same codepath.
+%!test
+%! p = inputParser;
+%! addParameter (p, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
+%! addParameter (p, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
+%! p.parse ("line", "circle");
+%! assert ({p.Results.line, p.Results.color}, {"circle", "red"})
+
+%!test
+%! p = inputParser;
+%! p.addParameter ("foo", "bar", @ischar);
+%! p.parse ();
+%! assert (p.Results, struct ("foo", "bar"))
+%! p.parse ("foo", "qux");
+%! assert (p.Results, struct ("foo", "qux"))
+
+## This behaviour means that a positional option can never be a string
+## that is the name of a parameter key.  This is required for Matlab
+## compatibility.
+%!test <*50752>
+%! p = inputParser ();
+%! p.addOptional ("op1", "val");
+%! p.addParameter ("line", "tree");
+%! p.parse ("line", "circle");
+%! assert (p.Results, struct ("op1", "val", "line", "circle"))
+%!
+%! p = inputParser ();
+%! p.addOptional ("op1", "val1");
+%! p.addOptional ("op2", "val2");
+%! p.addParameter ("line", "tree");
+%! p.parse ("line", "circle");
+%! assert (p.Results.op1, "val1")
+%! assert (p.Results.op2, "val2")
+%! assert (p.Results.line, "circle")
+%!
+%! ## If there's enough arguments to fill the positional options and
+%! ## param/key, it still skips positional options.
+%! p = inputParser ();
+%! p.addOptional ("op1", "val1");
+%! p.addOptional ("op2", "val2");
+%! p.addParameter ("line", "tree");
+%! p.parse ("line", "circle", "line", "rectangle");
+%! assert (p.Results, struct ("op1", "val1", "op2", "val2",
+%!                            "line", "rectangle"))
+%!
+%! ## Even if the key/param fails validation, it does not backtrack to
+%! ## check if the values are valid positional options.
+%! p = inputParser ();
+%! p.addOptional ("op1", "val1", @ischar);
+%! p.addOptional ("op2", "val2", @isnumeric);
+%! p.addParameter ("line", "circle", @ischar);
+%! fail ('p.parse ("line", 89)', "failed validation of LINE")
+%!
+%! p = inputParser ();
+%! p.addOptional ("op1", "val1");
+%! p.addParamValue ("line", "circle", @ischar);
+%! fail ('p.parse ("line", "line", 89)',
+%!       "non-string for Parameter name or Switch")
+
+%!test <*50752>
+%! ## This fails in Matlab but works in Octave.  It is a bug there
+%! ## that we do not replicate.
+%! p = inputParser ();
+%! p.addOptional ("op1", "val1");
+%! p.addParameter ("line", "circle");
+%! p.parse ("line");
+%! assert (p.Results, struct ("op1", "line", "line", "circle"))
+
+%!test <*50752>
+%! p = inputParser;
+%! p.addOptional ("op1", "val1");
+%! p.addSwitch ("line");
+%! p.parse ("line");
+%! assert (p.Results.op1, "val1")
+%! assert (p.Results.line, true)
+
+%!test
+%! p = inputParser;
+%! p.addParameter ("a", []);
+%! p.addParameter ("b", []);
+%! p.parse ("a", 1);
+%! p.parse ("b", 1);
+%! assert (p.Results, struct ("a", [], "b", 1));
+%! assert (p.UsingDefaults, {"a"});
+
+%!test
+%! p = inputParser;
+%! p.addParameter ("b", []);
+%! p.KeepUnmatched = true;
+%! p.parse ("a", 1);
+%! p.parse ("b", 1);
+%! assert (p.Results, struct ("b", 1));
+%! assert (p.Unmatched, struct ());
+
+## Test for patch #9241
+%!error<failed validation of A with ischar>
+%! p = inputParser;
+%! p.addParameter ("a", [], @ischar);
+%! p.parse ("a", 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/isdir.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,41 @@
+## Copyright (C) 2004-2017 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
+## <http://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/loadobj.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,42 @@
+## Copyright (C) 2008-2017 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{b} =} loadobj (@var{a})
+## Method of a class to manipulate an object after loading it from a file.
+##
+## The function @code{loadobj} is called when the object @var{a} is loaded
+## using the @code{load} function.  An example of the use of @code{saveobj}
+## might be to add fields to an object that don't make sense to be saved.
+## For example:
+##
+## @example
+## @group
+## function b = loadobj (a)
+##   b = a;
+##   b.addmissingfield = addfield (b);
+## endfunction
+## @end group
+## @end example
+##
+## @seealso{saveobj, class}
+## @end deftypefn
+
+function b = loadobj (a)
+  error ('loadobj: not defined for class "%s"', class (a));
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/methods.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,86 @@
+## Copyright (C) 2012-2017 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} methods (@var{obj})
+## @deftypefnx {} {} methods ("@var{classname}")
+## @deftypefnx {} {@var{mtds} =} methods (@dots{})
+## List the names of the public methods for the object @var{obj} or the
+## named class @var{classname}.
+##
+## @var{obj} may be an Octave class object or a Java object.
+## @var{classname} may be the name of an Octave class or a Java class.
+##
+## When called with no output arguments, @code{methods} prints the list of
+## method names to the screen.  Otherwise, the output argument @var{mtds}
+## contains the list in a cell array of strings.
+## @seealso{fieldnames}
+## @end deftypefn
+
+function mtds = methods (obj)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (isobject (obj))
+    ## Call internal C++ function for Octave objects
+    mtds_list = __methods__ (obj);
+  elseif (ischar (obj))
+    ## Could be a classname for an Octave class or Java class.
+    ## Try Octave class first.
+    mtds_list = __methods__ (obj);
+    if (isempty (mtds_list))
+      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
+      mtds_list = ostrsplit (mtds_str, ';');
+    endif
+  elseif (isjava (obj))
+    ## FIXME: Function prototype accepts java obj, but doesn't work if obj
+    ##        is e.g., java.lang.String.  Convert obj to classname then.
+    try
+      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
+    catch
+      obj = class (obj);
+      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
+    end_try_catch
+    mtds_list = strsplit (mtds_str, ';');
+  else
+    error ("methods: Invalid input argument");
+  endif
+
+  if (nargout == 0)
+    classname = ifelse (ischar (obj), obj, class (obj));
+    printf ("Methods for class %s:\n", classname);
+    disp (list_in_columns (mtds_list));
+  else
+    mtds = mtds_list;
+  endif
+
+endfunction
+
+
+## test Octave classname
+%!test
+%! mtds = methods ("ftp");
+%! assert (mtds{1}, "ascii");
+
+## test Java classname
+%!testif HAVE_JAVA; usejava ("jvm")
+%! mtds = methods ("java.lang.Double");
+%! search = strfind (mtds, "java.lang.Double valueOf");
+%! assert (! isempty ([search{:}]));
--- a/scripts/miscellaneous/module.mk	Thu Dec 28 15:56:09 2017 -0800
+++ b/scripts/miscellaneous/module.mk	Thu Dec 28 16:14:37 2017 -0800
@@ -3,6 +3,8 @@
   %reldir%/private
 
 %canon_reldir%_PRIVATE_FCN_FILES = \
+  %reldir%/private/__publish_html_output__.m \
+  %reldir%/private/__publish_latex_output__.m \
   %reldir%/private/__w2mpth__.m \
   %reldir%/private/display_info_file.m
 
@@ -20,38 +22,50 @@
   %reldir%/dos.m \
   %reldir%/edit.m \
   %reldir%/fact.m \
+  %reldir%/fieldnames.m \
   %reldir%/fileattrib.m \
   %reldir%/fileparts.m \
   %reldir%/fullfile.m \
   %reldir%/genvarname.m \
   %reldir%/getfield.m \
+  %reldir%/grabcode.m \
   %reldir%/gunzip.m \
   %reldir%/info.m \
   %reldir%/inputname.m \
+  %reldir%/inputParser.m \
   %reldir%/isdeployed.m \
+  %reldir%/isdir.m \
   %reldir%/ismac.m \
   %reldir%/ispc.m \
   %reldir%/isunix.m \
   %reldir%/license.m \
   %reldir%/list_primes.m \
+  %reldir%/loadobj.m \
   %reldir%/ls.m \
   %reldir%/ls_command.m \
   %reldir%/menu.m \
+  %reldir%/methods.m \
   %reldir%/mex.m \
   %reldir%/mexext.m \
   %reldir%/mkdir.m \
   %reldir%/mkoctfile.m \
   %reldir%/movefile.m \
   %reldir%/namelengthmax.m \
+  %reldir%/nargchk.m \
+  %reldir%/narginchk.m \
+  %reldir%/nargoutchk.m \
   %reldir%/news.m \
+  %reldir%/nthargout.m \
   %reldir%/open.m \
   %reldir%/orderfields.m \
   %reldir%/pack.m \
   %reldir%/parseparams.m \
   %reldir%/perl.m \
+  %reldir%/publish.m \
   %reldir%/python.m \
   %reldir%/recycle.m \
   %reldir%/run.m \
+  %reldir%/saveobj.m \
   %reldir%/setfield.m \
   %reldir%/substruct.m \
   %reldir%/swapbytes.m \
@@ -66,6 +80,7 @@
   %reldir%/ver.m \
   %reldir%/version.m \
   %reldir%/what.m \
+  %reldir%/validateattributes.m \
   %reldir%/zip.m
 
 %canon_reldir%dir = $(fcnfiledir)/miscellaneous
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/nargchk.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,83 @@
+## Copyright (C) 2008-2017 Bill Denney
+##
+## 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{msgstr} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs})
+## @deftypefnx {} {@var{msgstr} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs}, "string")
+## @deftypefnx {} {@var{msgstruct} =} nargchk (@var{minargs}, @var{maxargs}, @var{nargs}, "struct")
+## Return an appropriate error message string (or structure) if the number of
+## inputs requested is invalid.
+##
+## This is useful for checking to see that the number of input arguments
+## supplied to a function is within an acceptable range.
+##
+## @strong{Caution}: @code{nargchk} is scheduled for deprecation.  Use
+## @code{narginchk} in all new code.
+## @seealso{narginchk, nargoutchk, error, nargin, nargout}
+## @end deftypefn
+
+## Author: Bill Denney <bill@denney.ws>
+
+function msg = nargchk (minargs, maxargs, nargs, outtype = "string")
+
+  if (nargin < 3 || nargin > 4)
+    print_usage ();
+  elseif (minargs > maxargs)
+    error ("nargchk: MINARGS must be <= MAXARGS");
+  elseif (! any (strcmpi (outtype, {"string", "struct"})))
+    error ('nargchk: output type must be either "string" or "struct"');
+  elseif (! (isscalar (minargs) && isscalar (maxargs) && isscalar (nargs)))
+    error ("nargchk: MINARGS, MAXARGS, and NARGS must be scalars");
+  endif
+
+  msg = struct ("message", "", "identifier", "");
+  if (nargs < minargs)
+    msg.message = "not enough input arguments";
+    msg.identifier = "Octave:nargchk:not-enough-inputs";
+  elseif (nargs > maxargs)
+    msg.message = "too many input arguments";
+    msg.identifier = "Octave:nargchk:too-many-inputs";
+  endif
+
+  if (strcmpi (outtype, "string"))
+    msg = msg.message;
+  elseif (isempty (msg.message))
+    ## Compatability: Matlab returns a 0x1 empty struct when nargchk passes
+    msg = resize (msg, 0, 1);
+  endif
+
+endfunction
+
+
+## Tests
+%!shared stnul, stmin, stmax
+%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1);
+%! stmin = struct ("message", "not enough input arguments",
+%!                 "identifier", "Octave:nargchk:not-enough-inputs");
+%! stmax = struct ("message", "too many input arguments",
+%!                 "identifier", "Octave:nargchk:too-many-inputs");
+%!assert (nargchk (0, 1, 0), "")
+%!assert (nargchk (0, 1, 1), "")
+%!assert (nargchk (1, 1, 0), "not enough input arguments")
+%!assert (nargchk (0, 1, 2), "too many input arguments")
+%!assert (nargchk (0, 1, 2, "string"), "too many input arguments")
+## Struct outputs
+%!assert (nargchk (0, 1, 0, "struct"), stnul)
+%!assert (nargchk (0, 1, 1, "struct"), stnul)
+%!assert (nargchk (1, 1, 0, "struct"), stmin)
+%!assert (nargchk (0, 1, 2, "struct"), stmax)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/narginchk.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,71 @@
+## Copyright (C) 2012-2017 Carnë Draug
+##
+## 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 {} {} narginchk (@var{minargs}, @var{maxargs})
+## Check for correct number of input arguments.
+##
+## Generate an error message if the number of arguments in the calling function
+## is outside the range @var{minargs} and @var{maxargs}.  Otherwise, do
+## nothing.
+##
+## Both @var{minargs} and @var{maxargs} must be scalar numeric values.  Zero,
+## Inf, and negative values are all allowed, and @var{minargs} and
+## @var{maxargs} may be equal.
+##
+## Note that this function evaluates @code{nargin} on the caller.
+##
+## @seealso{nargoutchk, error, nargout, nargin}
+## @end deftypefn
+
+## Author: Carnë Draug <carandraug+dev@gmail.com>
+
+function narginchk (minargs, maxargs)
+
+  if (nargin != 2)
+    print_usage;
+  elseif (! isnumeric (minargs) || ! isscalar (minargs))
+    error ("narginchk: MINARGS must be a numeric scalar");
+  elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
+    error ("narginchk: MAXARGS must be a numeric scalar");
+  elseif (minargs > maxargs)
+    error ("narginchk: MINARGS cannot be larger than MAXARGS");
+  endif
+
+  args = evalin ("caller", "nargin;");
+
+  if (args < minargs)
+    error ("narginchk: not enough input arguments");
+  elseif (args > maxargs)
+    error ("narginchk: too many input arguments");
+  endif
+
+endfunction
+
+
+%!function f (nargs, varargin)
+%! narginchk (nargs(1), nargs(2));
+%!endfunction
+
+%!error <too many input arguments> f([0,0])
+%!error <not enough input arguments> f([3, 3], 1)
+
+%!test
+%! f([1,1]);
+%!test
+%! f([1,5], 2, 3, 4, 5);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/nargoutchk.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,124 @@
+## Copyright (C) 2008-2017 Bill Denney
+## Copyright (C) 2012 Carnë Draug
+##
+## 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  {} {} nargoutchk (@var{minargs}, @var{maxargs})
+## @deftypefnx {} {@var{msgstr} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs})
+## @deftypefnx {} {@var{msgstr} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs}, "string")
+## @deftypefnx {} {@var{msgstruct} =} nargoutchk (@var{minargs}, @var{maxargs}, @var{nargs}, "struct")
+## Check for correct number of output arguments.
+##
+## In the first form, return an error if the number of arguments is not between
+## @var{minargs} and @var{maxargs}.  Otherwise, do nothing.  Note that this
+## function evaluates the value of @code{nargout} on the caller so its value
+## must have not been tampered with.
+##
+## Both @var{minargs} and @var{maxargs} must be numeric scalars.  Zero, Inf,
+## and negative are all valid, and they can have the same value.
+##
+## For backwards compatibility, the other forms return an appropriate error
+## message string (or structure) if the number of outputs requested is
+## invalid.
+##
+## This is useful for checking to that the number of output arguments supplied
+## to a function is within an acceptable range.
+## @seealso{narginchk, error, nargout, nargin}
+## @end deftypefn
+
+## Author: Bill Denney <bill@denney.ws>
+## Author: Carnë Draug <carandraug+dev@gmail.com>
+
+function msg = nargoutchk (minargs, maxargs, nargs, outtype)
+
+  ## before matlab's 2011b, nargoutchk would return an error message (just the
+  ## message in a string).  With 2011b, it no longer returns anything, it
+  ## simply gives an error if the args number is incorrect.
+  ## To try to keep compatibility with both versions, check nargout and nargin
+  ## to guess if the caller is expecting a value (old syntax)
+  ## or none (new syntax).
+
+  if (nargout == 1 && (nargin == 3 || nargin == 4))
+
+    if (minargs > maxargs)
+      error ("nargoutchk: MINARGS must be <= MAXARGS");
+    elseif (nargin == 3)
+      outtype = "string";
+    elseif (! any (strcmpi (outtype, {"string" "struct"})))
+      error ("nargoutchk: output type must be either string or struct");
+    elseif (! (isscalar (minargs) && isscalar (maxargs) && isscalar (nargs)))
+      error ("nargoutchk: MINARGS, MAXARGS, and NARGS must be scalars");
+    endif
+
+    msg = struct ("message", "", "identifier", "");
+    if (nargs < minargs)
+      msg.message = "not enough output arguments";
+      msg.identifier = "Octave:nargoutchk:not-enough-outputs";
+    elseif (nargs > maxargs)
+      msg.message = "too many output arguments";
+      msg.identifier = "Octave:nargoutchk:too-many-outputs";
+    endif
+
+    if (strcmpi (outtype, "string"))
+      msg = msg.message;
+    elseif (isempty (msg.message))
+      ## Compatibility: Matlab returns a 0x1 empty struct when nargoutchk passes
+      msg = resize (msg, 0, 1);
+    endif
+
+  elseif (nargout == 0 && nargin == 2)
+
+    if (! isnumeric (minargs) || ! isscalar (minargs))
+      error ("nargoutchk: MINARGS must be a numeric scalar");
+    elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
+      error ("nargoutchk: MAXARGS must be a numeric scalar");
+    elseif (minargs > maxargs)
+      error ("nargoutchk: MINARGS cannot be larger than MAXARGS");
+    endif
+
+    args = evalin ("caller", "nargout;");
+
+    if (args < minargs)
+      error ("nargoutchk: Not enough output arguments.");
+    elseif (args > maxargs)
+      error ("nargoutchk: Too many output arguments.");
+    endif
+
+  else
+    print_usage;
+  endif
+
+endfunction
+
+
+%!shared stnul, stmin, stmax
+%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1);
+%! stmin = struct ("message", "not enough output arguments",
+%!                 "identifier", "Octave:nargoutchk:not-enough-outputs");
+%! stmax = struct ("message", "too many output arguments",
+%!                 "identifier", "Octave:nargoutchk:too-many-outputs");
+%!assert (nargoutchk (0, 1, 0), "")
+%!assert (nargoutchk (0, 1, 1), "")
+%!assert (nargoutchk (1, 1, 0), "not enough output arguments")
+%!assert (nargoutchk (0, 1, 2), "too many output arguments")
+%!assert (nargoutchk (0, 1, 2, "string"), "too many output arguments")
+## Struct outputs
+%!assert (nargoutchk (0, 1, 0, "struct"), stnul)
+%!assert (nargoutchk (0, 1, 1, "struct"), stnul)
+%!assert (nargoutchk (1, 1, 0, "struct"), stmin)
+%!assert (nargoutchk (0, 1, 2, "struct"), stmax)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/nthargout.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,116 @@
+## Copyright (C) 2012-2017 Jordi Gutiérrez Hermoso
+##
+## 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  {} {} nthargout (@var{n}, @var{func}, @dots{})
+## @deftypefnx {} {} nthargout (@var{n}, @var{ntot}, @var{func}, @dots{})
+## Return the @var{n}th output argument of the function specified by the
+## function handle or string @var{func}.
+##
+## Any additional arguments are passed directly to @var{func}.  The total
+## number of arguments to call @var{func} with can be passed in @var{ntot}; by
+## default @var{ntot} is @var{n}.  The input @var{n} can also be a vector of
+## indices of the output, in which case the output will be a cell array of the
+## requested output arguments.
+##
+## The intended use @code{nthargout} is to avoid intermediate variables.  For
+## example, when finding the indices of the maximum entry of a matrix, the
+## following two compositions of nthargout
+##
+## @example
+## @group
+## @var{m} = magic (5);
+## cell2mat (nthargout ([1, 2], @@ind2sub, size (@var{m}),
+##                      nthargout (2, @@max, @var{m}(:))))
+## @result{} 5   3
+## @end group
+## @end example
+##
+## @noindent
+## are completely equivalent to the following lines:
+##
+## @example
+## @group
+## @var{m} = magic (5);
+## [~, idx] = max (@var{M}(:));
+## [i, j] = ind2sub (size (@var{m}), idx);
+## [i, j]
+## @result{} 5   3
+## @end group
+## @end example
+##
+## It can also be helpful to have all output arguments in a single cell in the
+## following manner:
+##
+## @example
+## @var{USV} = nthargout ([1:3], @@svd, hilb (5));
+## @end example
+##
+## @seealso{nargin, nargout, varargin, varargout, isargout}
+## @end deftypefn
+
+## Author: Jordi Gutiérrez Hermoso
+
+function out = nthargout (n, varargin)
+
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  if (isa (varargin{1}, "function_handle") || 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})))
+    ntot = varargin{1};
+    func = varargin{2};
+    args = varargin(3:end);
+  else
+    print_usage ();
+  endif
+
+  if (any (n != fix (n))  || ntot != fix (ntot) || any (n <= 0) || ntot <= 0)
+    error ("nthargout: N and NTOT must consist of positive integers");
+  endif
+
+  outargs = cell (1, ntot);
+
+  try
+    [outargs{:}] = feval (func, args{:});
+    if (numel (n) > 1)
+      out = outargs(n);
+    else
+      out = outargs{n};
+    endif
+  catch
+    err = lasterr ();
+    if (strfind ("some elements undefined in return list", err))
+      error ("nthargout: Too many output arguments: %d", ntot);
+    else
+      error (err);
+    endif
+  end_try_catch
+
+endfunction
+
+
+%!shared m
+%! m = magic (5);
+%!assert (nthargout ([1,2], @ind2sub, size (m), nthargout (2, @max, m(:))), {5,3})
+%!assert (nthargout (3, @find, m(m>20)), [23, 24, 25, 21, 22]')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/private/__publish_html_output__.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,430 @@
+## Copyright (C) 2016-2017 Kai T. Ohlhus
+##
+## 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{outstr} =} __publish_html_output__ (@var{type}, @var{varargin})
+##
+## Internal function.
+##
+## The first input argument @var{type} defines the required strings
+## (@samp{str}) or cell-strings (@samp{cstr}) in @var{varargin} in order
+## to produce HTML output.
+##
+## @var{type} is one of
+##
+## @itemize @bullet
+## @item
+## @samp{output_file_extension} ()
+##
+## @item
+## @samp{header} (title_str, intro_str, toc_cstr)
+##
+## @item
+## @samp{footer} ()
+##
+## @item
+## @samp{code} (str)
+##
+## @item
+## @samp{code_output} (str)
+##
+## @item
+## @samp{section} (str)
+##
+## @item
+## @samp{preformatted_code} (str)
+##
+## @item
+## @samp{preformatted_text} (str)
+##
+## @item
+## @samp{bulleted_list} (cstr)
+##
+## @item
+## @samp{numbered_list} (cstr)
+##
+## @item
+## @samp{graphic} (str)
+##
+## @item
+## @samp{html} (str)
+##
+## @item
+## @samp{latex} (str)
+##
+## @item
+## @samp{text} (str)
+##
+## @item
+## @samp{blockmath} (str)
+##
+## @item
+## @samp{inlinemath} (str)
+##
+## @item
+## @samp{bold} (str)
+##
+## @item
+## @samp{italic} (str)
+##
+## @item
+## @samp{monospaced} (str)
+##
+## @item
+## @samp{link} (url_str, url_str, str)
+##
+## @item
+## @samp{TM} ()
+##
+## @item
+## @samp{R} ()
+##
+## @item
+## @samp{escape_special_chars} (str)
+## @end itemize
+## @end deftypefn
+
+function outstr = __publish_html_output__ (type, varargin)
+  outstr = feval (["do_" type], varargin{:});
+endfunction
+
+function outstr = do_output_file_extension ()
+  outstr = ".html";
+endfunction
+
+function outstr = do_header (title_str, intro_str, toc_cstr)
+  mathjax_str = sprintf ("%s\n",
+'<script type="text/x-mathjax-config">',
+"MathJax.Hub.Config({",
+"  tex2jax: { inlineMath: [['$','$'], ['\\\\(','\\\\)']] },",
+"  TeX: { equationNumbers: { autoNumber: 'all' } }",
+"});",
+"</script>",
+['<script type="text/javascript" async ', ...
+ 'src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?', ...
+ 'config=TeX-MML-AM_CHTML"></script>']);
+
+  stylesheet_str = sprintf ("%s\n",
+"<style>",
+"body > * {",
+"  max-width: 42em;",
+"}",
+"body {",
+'  font-family: "Roboto Condensed", sans-serif;',
+"  padding-left: 7.5em;",
+"  padding-right: 7.5em;",
+"}",
+"pre, code {",
+"  max-width: 50em;",
+"  font-family: monospace;",
+"}",
+"pre.oct-code {",
+"  border: 1px solid Grey;",
+"  padding: 5px;",
+"}",
+"pre.oct-code-output {",
+"  margin-left: 2em;",
+"}",
+"span.comment {",
+"  color: ForestGreen;",
+"}",...
+"span.keyword {",
+"  color: Blue;",
+"}",...
+"span.string {",
+"  color: DarkOrchid;",
+"}",...
+"footer {",
+"  margin-top: 2em;",
+"  font-size: 80%;",
+"}",
+"a, a:visited {",
+"  color: Blue;",
+"}",
+"h2 {",
+'  font-family: "Roboto Condensed", serif;',
+"  margin-top: 1.5em;",
+"}",
+"h2 a, h2 a:visited {",
+"  color: Black;",
+"}",
+"</style>");
+
+  outstr = sprintf ("%s\n",
+"<!DOCTYPE html>",
+"<html>",
+"<head>",
+'<meta charset="UTF-8">',
+["<title>" title_str "</title>"],
+mathjax_str,
+stylesheet_str,
+"</head>",
+"<body>",
+["<h1>" title_str "</h1>"],
+intro_str);
+
+  if (! isempty (toc_cstr))
+    for i = 1:numel (toc_cstr)
+      toc_cstr{i} = do_link (["#node" sprintf("%d", i)], toc_cstr{i});
+    endfor
+    outstr = [outstr, "<h2>Contents</h2>", do_bulleted_list(toc_cstr)];
+  endif
+
+  ## Reset section counter
+  do_section ();
+
+endfunction
+
+function outstr = do_footer (m_source_str)
+  outstr = sprintf ("%s\n",
+"",
+"<footer>",
+"<hr>",
+['<a href="http://www.octave.org">Published with GNU Octave ' version() '</a>'],
+"</footer>",
+"<!--",
+"##### SOURCE BEGIN #####",
+m_source_str,
+"##### SOURCE END #####",
+"-->",
+"</body>",
+"</html>");
+endfunction
+
+function outstr = do_code (str)
+  outstr = ["\n", '<pre class="oct-code">' syntax_highlight(str) "</pre>\n"];
+endfunction
+
+function outstr = do_code_output (str)
+  str = do_escape_special_chars (str);
+  outstr = ["\n", '<pre class="oct-code-output">' str "</pre>\n"];
+endfunction
+
+function outstr = do_section (varargin)
+  persistent counter = 1;
+
+  if (nargin == 0)
+    outstr = "";
+    counter = 1;
+    return;
+  endif
+
+  outstr = ['<h2><a id="node' sprintf("%d", counter) '">', ...
+            varargin{1}, ...
+            "</a></h2>"];
+
+  counter++;
+
+endfunction
+
+function outstr = do_preformatted_code (str)
+  outstr = ["\n", '<pre class="pre-code">' syntax_highlight(str) "</pre>\n"];
+endfunction
+
+function outstr = do_preformatted_text (str)
+  str = do_escape_special_chars (str);
+  outstr = ["\n", '<pre class="pre-text">' str "</pre>\n"];
+endfunction
+
+function outstr = do_bulleted_list (cstr)
+  outstr = "\n<ul>\n";
+  for i = 1:numel (cstr)
+    outstr = [outstr, "<li>" cstr{i} "</li>\n"];
+  endfor
+  outstr = [outstr, "</ul>\n"];
+endfunction
+
+function outstr = do_numbered_list (cstr)
+  outstr = "\n<ol>\n";
+  for i = 1:numel (cstr)
+    outstr = [outstr, "<li>" cstr{i} "</li>\n"];
+  endfor
+  outstr = [outstr, "</ol>\n"];
+endfunction
+
+function outstr = do_graphic (str)
+  outstr = ['<img src="' str '" alt="' str '">'];
+endfunction
+
+function outstr = do_html (str)
+  outstr = ["\n" str "\n"];
+endfunction
+
+function outstr = do_latex (str)
+  outstr = "";
+endfunction
+
+function outstr = do_link (url_str, str)
+  outstr = ['<a href="' url_str '">' str "</a>"];
+endfunction
+
+function outstr = do_text (str)
+  outstr = ["\n<p>" str "</p>\n"];
+endfunction
+
+function outstr = do_blockmath (str)
+  outstr = ["$$" str "$$"];
+endfunction
+
+function outstr = do_inlinemath (str)
+  outstr = ["$" str "$"];
+endfunction
+
+function outstr = do_bold (str)
+  outstr = ["<b>" str "</b>"];
+endfunction
+
+function outstr = do_italic (str)
+  outstr = ["<i>" str "</i>"];
+endfunction
+
+function outstr = do_monospaced (str)
+  outstr = ["<code>" str "</code>"];
+endfunction
+
+function outstr = do_TM ()
+  outstr = "&trade;";
+endfunction
+
+function outstr = do_R ()
+  outstr = "&reg;";
+endfunction
+
+function str = do_escape_special_chars (str)
+  str = regexprep (str, '&', '&amp;');
+  str = regexprep (str, '<', '&lt;');
+  str = regexprep (str, '>', '&gt;');
+  ## str = regexprep (str, '"', '&quot;'); ## MATLAB R2017a compatibility.
+endfunction
+
+## SYNTAX_HIGHLIGHT: A primitive parser to highlight syntax via <span> tags.
+## FIXME: Needs to be replaced by a better solution.
+function outstr = syntax_highlight (str)
+  str = do_escape_special_chars (str);
+  outstr = "";
+  placeholder_cstr = {};
+  i = 1;
+  plh = 0;
+
+  while (i <= numel (str))
+    ## Block comment
+    if (any (strncmp (str(i:end), {"%{", "#{"}, 2)))
+      plh_str = ['<span class="comment">', str(i:i+1)];
+      i += 2;
+      while (i <= numel (str)
+             && ! (any (strncmp (str(i:end), {"%}", "#}"}, 2))))
+        plh_str = [plh_str, str(i)];
+        i += 1;
+      endwhile
+      if (i < numel (str))
+        plh_str = [plh_str, str(i:i+1), "</span>"];
+        i += 2;
+      else
+        plh_str = [plh_str, "</span>"];
+      endif
+      plh += 1;
+      placeholder_cstr{plh} = plh_str;
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
+    ## Line comment
+    elseif (str(i) == "#" || str(i) == "%")
+      plh_str = '<span class="comment">';
+      idx = find (str(i:end) == "\n", 1);
+      if (isempty (idx))
+        plh_str = [plh_str, str(i:end)];
+        i = numel (str) + 1;
+      else
+        plh_str = [plh_str, str(i:i+idx-2)];
+        i += idx;
+      endif
+      plh_str = [plh_str, "</span>\n"];
+      plh += 1;
+      placeholder_cstr{plh} = plh_str;
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
+    ## Single quoted string
+    elseif (str(i) == "'")
+      plh_str = "<span class=\"string\">'";
+      i += 1;
+      while (i <= numel (str))
+        ## Ignore escaped string terminations
+        if (strncmp (str(i:end), "''", 2))
+          plh_str = [plh_str, "''"];
+          i += 2;
+        ## Is char a string termination?
+        elseif (str(i) == "'")
+          plh_str = [plh_str, "'"];
+          i += 1;
+          break;
+        ## Is string terminated by line break?
+        elseif (str(i) == "\n")
+          break;
+        ## String content
+        else
+          plh_str = [plh_str, str(i)];
+          i += 1;
+        endif
+      endwhile
+      plh_str = [plh_str, "</span>"];
+      plh += 1;
+      placeholder_cstr{plh} = plh_str;
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
+    ## Double quoted string
+    elseif (str(i) == '"')
+      plh_str = '<span class="string">"';
+      i += 1;
+      while (i <= numel (str))
+        ## Is char a string termination?
+        if (str(i) == '"' && str(i-1) != '\')
+          plh_str = [plh_str, '"'];
+          i += 1;
+          break;
+        ## Is string terminated by line break?
+        elseif (str(i) == "\n")
+          break;
+        ## String content
+        else
+          plh_str = [plh_str, str(i)];
+          i += 1;
+        endif
+      endwhile
+      plh_str = [plh_str, "</span>"];
+      plh += 1;
+      placeholder_cstr{plh} = plh_str;
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
+    else
+      outstr = [outstr, str(i)];
+      i += 1;
+    endif
+  endwhile
+
+  persistent kword_ptn = strjoin (iskeyword (), '|');
+
+  ## FIXME: remove hack for regexprep once bug #38149 is solved
+  outstr = [" ", strrep(outstr, "\n", " \n "), " "];
+  outstr = regexprep (outstr,
+                      ['(\s)(' kword_ptn ')(\s|\()'],
+                      ['$1<span class="keyword">$2</span>$3']);
+  ## FIXME: remove hack for regexprep once bug #38149 is solved
+  outstr = strrep (outstr(2:end-1), " \n ", "\n");
+
+  ## Restore placeholders
+  for i = plh:-1:1
+    outstr = strrep (outstr, [" PUBLISHPLACEHOLDER", sprintf("%d", i), " "],
+                             placeholder_cstr{i});
+  endfor
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/private/__publish_latex_output__.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,280 @@
+## Copyright (C) 2016-2017 Kai T. Ohlhus
+##
+## 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{outstr} =} __publish_latex_output__ (@var{type}, @var{varargin})
+##
+## Internal function.
+##
+## The first input argument @var{type} defines the required strings
+## (@samp{str}) or cell-strings (@samp{cstr}) in @var{varargin} in order
+## to produce @LaTeX{} output.
+##
+## @var{type} is one of
+##
+## @itemize @bullet
+## @item
+## @samp{output_file_extension} ()
+##
+## @item
+## @samp{header} (title_str, intro_str, toc_cstr)
+##
+## @item
+## @samp{footer} ()
+##
+## @item
+## @samp{code} (str)
+##
+## @item
+## @samp{code_output} (str)
+##
+## @item
+## @samp{section} (str)
+##
+## @item
+## @samp{preformatted_code} (str)
+##
+## @item
+## @samp{preformatted_text} (str)
+##
+## @item
+## @samp{bulleted_list} (cstr)
+##
+## @item
+## @samp{numbered_list} (cstr)
+##
+## @item
+## @samp{graphic} (str)
+##
+## @item
+## @samp{html} (str)
+##
+## @item
+## @samp{latex} (str)
+##
+## @item
+## @samp{text} (str)
+##
+## @item
+## @samp{blockmath} (str)
+##
+## @item
+## @samp{inlinemath} (str)
+##
+## @item
+## @samp{bold} (str)
+##
+## @item
+## @samp{italic} (str)
+##
+## @item
+## @samp{monospaced} (str)
+##
+## @item
+## @samp{link} (url_str, url_str, str)
+##
+## @item
+## @samp{TM} ()
+##
+## @item
+## @samp{R} ()
+##
+## @item
+## @samp{escape_special_chars} (str)
+## @end itemize
+## @end deftypefn
+
+function outstr = __publish_latex_output__ (type, varargin)
+  outstr = feval (["do_" type], varargin{:});
+endfunction
+
+function outstr = do_output_file_extension ()
+  outstr = ".tex";
+endfunction
+
+function outstr = do_header (title_str, intro_str, toc_cstr)
+  publish_comment = sprintf ("%s\n",
+"",
+"",
+"% This document was generated by the publish-function",
+["% from GNU Octave " version()],
+"");
+
+  latex_preamble = sprintf ("%s\n",
+"",
+"",
+'\documentclass[10pt]{article}',
+'\usepackage{listings}',
+'\usepackage{mathtools}',
+'\usepackage{amssymb}',
+'\usepackage{graphicx}',
+'\usepackage{hyperref}',
+'\usepackage{xcolor}',
+'\usepackage{titlesec}',
+'\usepackage[utf8]{inputenc}',
+'\usepackage[T1]{fontenc}',
+'\usepackage{lmodern}');
+
+  listings_option = sprintf ("%s\n",
+"",
+"",
+'\lstset{',
+'language=Octave,',
+'numbers=none,',
+'frame=single,',
+'tabsize=2,',
+'showstringspaces=false,',
+'breaklines=true}');
+
+  latex_head = sprintf ("%s\n",
+"",
+"",
+'\titleformat*{\section}{\Huge\bfseries}',
+'\titleformat*{\subsection}{\large\bfseries}',
+'\renewcommand{\contentsname}{\Large\bfseries Contents}',
+'\setlength{\parindent}{0pt}',
+"",
+'\begin{document}',
+"",
+['{\Huge\section*{' title_str '}}'],
+"",
+'\tableofcontents',
+'\vspace*{4em}',
+"");
+
+  outstr = [publish_comment, latex_preamble, listings_option, latex_head];
+
+endfunction
+
+function outstr = do_footer (m_source_str)
+  outstr = ["\n\n" '\end{document}' "\n"];
+endfunction
+
+function outstr = do_code (str)
+  outstr = ['\begin{lstlisting}' "\n", str, "\n" '\end{lstlisting}' "\n"];
+endfunction
+
+function outstr = do_code_output (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}[language={},xleftmargin=5pt,frame=none]',
+str,
+'\end{lstlisting}');
+endfunction
+
+function outstr = do_section (str)
+  outstr = sprintf ("%s\n",
+"",
+"",
+'\phantomsection',
+['\addcontentsline{toc}{section}{' str '}'],
+['\subsection*{' str '}'],
+"");
+endfunction
+
+function outstr = do_preformatted_code (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}',
+str,
+'\end{lstlisting}');
+endfunction
+
+function outstr = do_preformatted_text (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}[language={}]',
+str,
+'\end{lstlisting}');
+endfunction
+
+function outstr = do_bulleted_list (cstr)
+  outstr = ["\n" '\begin{itemize}' "\n"];
+  for i = 1:numel (cstr)
+    outstr = [outstr, '\item ' cstr{i} "\n"];
+  endfor
+  outstr = [outstr, '\end{itemize}' "\n"];
+endfunction
+
+function outstr = do_numbered_list (cstr)
+  outstr = ["\n" '\begin{enumerate}' "\n"];
+  for i = 1:numel (cstr)
+    outstr = [outstr, '\item ' cstr{i} "\n"];
+  endfor
+  outstr = [outstr, "\\end{enumerate}\n"];
+endfunction
+
+function outstr = do_graphic (str)
+  outstr = sprintf ("%s\n",
+'\begin{figure}[!ht]',
+['\includegraphics[width=\textwidth]{' str '}'],
+'\end{figure}');
+endfunction
+
+function outstr = do_html (str)
+  outstr = "";
+endfunction
+
+function outstr = do_latex (str)
+  outstr = ["\n" str "\n"];
+endfunction
+
+function outstr = do_link (url_str, str)
+  outstr = ['\href{' url_str '}{' str '}'];
+endfunction
+
+function outstr = do_text (str)
+  outstr = ["\n\n" str "\n\n"];
+endfunction
+
+function outstr = do_blockmath (str)
+  outstr = ["$$" str "$$"];
+endfunction
+
+function outstr = do_inlinemath (str)
+  outstr = ["$" str "$"];
+endfunction
+
+function outstr = do_bold (str)
+  outstr = ['\textbf{' str '}'];
+endfunction
+
+function outstr = do_italic (str)
+  outstr = ['\textit{' str '}'];
+endfunction
+
+function outstr = do_monospaced (str)
+  outstr = ['\texttt{' str '}'];
+endfunction
+
+function outstr = do_TM ()
+  outstr = '\texttrademark ';
+endfunction
+
+function outstr = do_R ()
+  outstr = '\textregistered ';
+endfunction
+
+function str = do_escape_special_chars (str)
+  ## Escape \, {, }, &, %, #, _, ~, ^, <, >
+  str = regexprep (str, '\\', "\\ensuremath{\\backslash}");
+  str = regexprep (str, '(?<!\\)(\{|\}|&|%|#|_)', '\\$1');
+  ## Revert accidential {} replacements for backslashes
+  str = strrep (str, '\ensuremath\{\backslash\}', '\ensuremath{\backslash}');
+  str = regexprep (str, '(?<!\\)~', "\\ensuremath{\\tilde{\\;}}");
+  str = regexprep (str, '(?<!\\)\^', "\\^{}");
+  str = regexprep (str, '(?<!\\)<', "\\ensuremath{<}");
+  str = regexprep (str, '(?<!\\)>', "\\ensuremath{>}");
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/publish.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,1071 @@
+## Copyright (C) 2016-2017 Kai T. Ohlhus <k.ohlhus@gmail.com>
+## Copyright (C) 2010 Fotios Kasolis <fotios.kasolis@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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} publish (@var{file})
+## @deftypefnx {} {} publish (@var{file}, @var{output_format})
+## @deftypefnx {} {} publish (@var{file}, @var{option1}, @var{value1}, @dots{})
+## @deftypefnx {} {} publish (@var{file}, @var{options})
+## @deftypefnx {} {@var{output_file} =} publish (@var{file}, @dots{})
+##
+## Generate a report from the Octave script file @var{file} in one of several
+## output formats.
+##
+## The generated reports interpret any Publishing Markup in comments, which is
+## explained in detail in the GNU Octave manual.  Assume the following example,
+## using some Publishing Markup, to be the contents of the script file
+## @file{pub_example.m}:
+##
+## @example
+## @group
+## ## Headline title
+## #
+## # Some *bold*, _italic_, or |monospaced| Text with
+## # a <http://www.octave.org link to *GNU Octave*>.
+## ##
+##
+## # "Real" Octave commands to be evaluated
+## sombrero ()
+##
+## %% @sc{matlab} comment style ('%') is supported as well
+## %
+## % * Bulleted list item 1
+## % * Bulleted list item 2
+## %
+## % # Numbered list item 1
+## % # Numbered list item 2
+## @end group
+## @end example
+##
+## To publish this script file, type @code{publish ("pub_example.m")}.
+##
+## With only @var{file} given, a HTML report is generated in a subdirectory
+## @file{html} relative to the current working directory.  The Octave commands
+## are evaluated in a separate context and any figures created while executing
+## the script file are included in the report.  All formatting syntax of
+## @var{file} is treated according to the specified output format and included
+## in the report.
+##
+## Using @code{publish (@var{file}, @var{output_format})} is equivalent to the
+## function call using a structure
+##
+## @example
+## @group
+## @var{options}.format = @var{output_format};
+## publish (@var{file}, @var{options})
+## @end group
+## @end example
+##
+## @noindent
+## which is described below.  The same holds for using option/value pairs
+##
+## @example
+## @group
+## @var{options}.@var{option1} = @var{value1};
+## publish (@var{file}, @var{options})
+## @end group
+## @end example
+##
+## The structure @var{options} can have the following field names.  If a field
+## name is not specified, the default value is used:
+##
+## @itemize @bullet
+## @item
+## @samp{format} --- Output format of the published script file, one of
+##
+## @samp{html} (default), @samp{doc}, @samp{latex}, @samp{ppt},
+## @samp{pdf}, or @samp{xml}.
+##
+## The output formats @samp{doc}, @samp{ppt}, and @samp{xml} are not currently
+## supported.  To generate a @samp{doc} report, open a generated @samp{html}
+## report with your office suite.
+##
+## In Octave custom formats are supported by implementing all callback
+## subfunctions in a function file named
+## @samp{__publish_<custom format>_output__.m}.  To obtain a template for the
+## HTML format type:
+##
+## @example
+## @group
+## edit (fullfile (fileparts (which ("publish")), ...
+##       "private", "__publish_html_output__.m"))
+## @end group
+## @end example
+##
+## @item
+## @samp{outputDir} --- Full path of the directory where the generated report
+## will be located.  If no directory is given, the report is generated in a
+## subdirectory @file{html} relative to the current working directory.
+##
+## @item
+## @samp{stylesheet} --- Not supported, only for @sc{matlab} compatibility.
+##
+## @item
+## @samp{createThumbnail} --- Not supported, only for @sc{matlab}
+## compatibility.
+##
+## @item
+## @samp{figureSnapMethod} --- Not supported, only for @sc{matlab}
+## compatibility.
+##
+## @item
+## @samp{imageFormat} --- Desired format for any images produced while
+## evaluating the code.  The allowed image formats depend on the output format:
+##
+## @itemize @bullet
+## @item @samp{html}, @samp{xml} --- @samp{png} (default), any image format
+## supported by Octave
+##
+## @item @samp{latex} --- @samp{epsc2} (default), any image format supported by
+## Octave
+##
+## @item @samp{pdf} --- @samp{jpg} (default) or @samp{bmp}, note @sc{matlab}
+## uses  @samp{bmp} as default
+##
+## @item @samp{doc} or @samp{ppt} --- @samp{png} (default), @samp{jpg},
+## @samp{bmp}, or @samp{tiff}
+## @end itemize
+##
+## @item
+## @samp{maxWidth} and @samp{maxHeight} --- Maximum width (height) of the
+## produced images in pixels.  An empty value means no restriction.  Both
+## values must be set in order for the option to work properly.
+##
+## @samp{[]} (default), integer value @geq{} 0
+##
+## @item
+## @samp{useNewFigure} --- Use a new figure window for figures created by the
+## evaluated code.  This avoids side effects with already opened figure
+## windows.
+##
+## @samp{true} (default) or @samp{false}
+##
+## @item
+## @samp{evalCode} --- Evaluate code of the Octave source file
+##
+## @samp{true} (default) or @samp{false}
+##
+## @item
+## @samp{catchError} --- Catch errors while evaluating code and continue
+##
+## @samp{true} (default) or @samp{false}
+##
+## @item
+## @samp{codeToEvaluate} --- Octave commands that should be evaluated prior to
+## publishing the script file.  These Octave commands do not appear in the
+## generated report.
+##
+## @item
+## @samp{maxOutputLines} --- Maximum number of output lines from code
+## evaluation which are included in output.
+##
+## @samp{Inf} (default) or integer value > 0
+##
+## @item
+## @samp{showCode} --- Show the evaluated Octave commands in the generated
+## report
+##
+## @samp{true} (default) or @samp{false}
+## @end itemize
+##
+## The option output @var{output_file} is a string with path and file name
+## of the generated report.
+##
+## @seealso{grabcode}
+## @end deftypefn
+
+function output_file = publish (file, varargin)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (exist (file, "file") != 2)
+    error ("publish: FILE does not exist");
+  endif
+
+  ## Check file to be in Octave's load path
+  [file_path, file_name, file_ext] = fileparts (file);
+  if (isempty (file_path))
+    file_path = pwd;
+  endif
+  if (exist ([file_name, file_ext]) != 2)
+    error (["publish: " file " is not in the load path"]);
+  endif
+
+  ## Check file extension and that file is an Octave script
+  file_info = __which__ (file_name);
+  if (! strcmp (file_ext, ".m") || ! strcmp (file_info.type, "script"))
+    error ("publish: only script files can be published");
+  endif
+
+  ## Check file to be parsable
+  __parse_file__ (file);
+
+  ## Get structure with necessary options
+  options = struct ();
+  if (numel (varargin) == 1)
+    ## Call: publish (file, format)
+    if (ischar (varargin{1}))
+      options.format = varargin{1};
+    ## Call: publish (file, options)
+    elseif (isstruct (varargin{1}))
+      options = varargin{1};
+    else
+      error ("publish: second argument must be OUTPUT_FORMAT or OPTIONS");
+    endif
+  ## Call: publish (file, Name1, Value1, Name2, Value2, ...)
+  elseif (rem (numel (varargin), 2) == 0
+          && all (cellfun (@ischar, varargin(1:2:end))))
+    options = cell2struct (varargin(2:2:end), varargin(1:2:end), 2);
+  else
+    error ("publish: invalid arguments");
+  endif
+
+  ## Validate options struct
+
+  ## Options for the output
+  if (! isfield (options, "format"))
+    options.format = "html";
+  else
+    ## FIXME: Implement remaining formats
+    if (any (strcmpi (options.format, {"doc", "ppt", "xml"})))
+      error ('publish: Output format "%s" is not yet supported',
+             options.format);
+    endif
+    ## Supported or custom output format
+    supported_formats = {"html", "doc", "latex", "ppt", "xml", "pdf"};
+    if (! any (strcmpi (options.format, supported_formats)))
+      ## Check existence of custom formatter
+      custom_formatter = ["__publish_", options.format, "_output__"];
+      if (! exist (custom_formatter, "file"))
+        error (['publish: Custom output format "%s" requires the ', ...
+                "formatter function:\n\n\t%s\n\n\t", ...
+                'See "help publish" for more information.'],
+                options.format, custom_formatter);
+      endif
+    else
+      options.format = validatestring (options.format, supported_formats);
+    endif
+  endif
+
+  if (! isfield (options, "outputDir"))
+    ## Matlab R2016a doc says default is "", but specifies to create a
+    ## subdirectory named "html" in the current working directory.
+    options.outputDir = fullfile (file_path, "html");
+  elseif (! ischar (options.outputDir))
+    error ("publish: OUTPUTDIR must be a string");
+  endif
+
+  if (! isfield (options, "stylesheet"))
+    options.stylesheet = "";
+  elseif (! ischar (options.stylesheet))
+    error ("publish: STYLESHEET must be a string");
+  endif
+
+  ## Options for the figures
+  if (! isfield (options, "createThumbnail"))
+    options.createThumbnail = true;
+  elseif (! isscalar (options.createThumbnail)
+          || ! isreal (options.createThumbnail))
+    error ("publish: CREATETHUMBNAIL must be TRUE or FALSE");
+  endif
+
+  if (! isfield (options, "figureSnapMethod"))
+    options.figureSnapMethod = "entireGUIWindow";
+  else
+    options.figureSnapMethod = validatestring (options.figureSnapMethod, ...
+      {"entireGUIWindow", "print", "getframe", "entireFigureWindow"});
+    ## FIXME: implement other SnapMethods
+    warning ("publish: option FIGURESNAPMETHOD currently not supported");
+  endif
+
+  if (! isfield (options, "imageFormat"))
+    switch (options.format)
+      case "latex"
+        options.imageFormat = "epsc2";
+      case "pdf"
+        ## Note: Matlab R2016a uses bmp as default
+        options.imageFormat = "jpg";
+      otherwise
+        options.imageFormat = "png";
+    endswitch
+  elseif (! ischar (options.imageFormat))
+    error ("publish: IMAGEFORMAT must be a string");
+  else
+    ## Check valid imageFormat for chosen format
+    ##   html, latex, and xml accept any imageFormat
+    switch (options.format)
+      case {"doc", "ppt"}
+        options.imageFormat = validatestring (options.imageFormat,
+                                              {"png", "jpg", "bmp", "tiff"});
+      case "pdf"
+        options.imageFormat = validatestring (options.imageFormat,
+                                              {"bmp", "jpg"});
+    endswitch
+  endif
+
+  if (! isfield (options, "maxHeight"))
+    options.maxHeight = [];
+  elseif (! isscalar (options.maxHeight) || options.maxHeight < 1)
+    error ("publish: MAXHEIGHT must be a positive integer");
+  else
+    options.maxHeight = uint64 (options.maxHeight);
+  endif
+
+  if (! isfield (options, "maxWidth"))
+    options.maxWidth = [];
+  elseif (! isscalar (options.maxWidth) || options.maxWidth < 1)
+    error ("publish: MAXWIDTH must be a positive integer");
+  else
+    options.maxWidth = uint64 (options.maxWidth);
+  endif
+
+  if (! isfield (options, "useNewFigure"))
+    options.useNewFigure = true;
+  elseif (! isscalar (options.useNewFigure) || ! isreal (options.useNewFigure))
+    error ("publish: USENEWFIGURE must be TRUE or FALSE");
+  endif
+
+  ## Options for the code
+  if (! isfield (options, "evalCode"))
+    options.evalCode = true;
+  elseif (! isscalar (options.evalCode) || ! isreal (options.evalCode))
+    error ("publish: EVALCODE must be TRUE or FALSE");
+  endif
+
+  if (! isfield (options, "catchError"))
+    options.catchError = true;
+  elseif (! isscalar (options.catchError) || ! isreal (options.catchError))
+    error ("publish: CATCHERROR must be TRUE or FALSE");
+  endif
+
+  if (! isfield (options, "codeToEvaluate"))
+    options.codeToEvaluate = "";
+  elseif (! ischar (options.codeToEvaluate))
+    error ("publish: CODETOEVALUTE must be a string");
+  endif
+
+  if (! isfield (options, "maxOutputLines"))
+    options.maxOutputLines = Inf;
+  elseif (! isscalar (options.maxOutputLines) || options.maxOutputLines < 0)
+    error ("publish: MAXOUTPUTLINES must be an integer >= 0");
+  else
+    options.maxOutputLines = uint64 (options.maxOutputLines);
+  endif
+
+  if (! isfield (options, "showCode"))
+    options.showCode = true;
+  elseif (! isscalar (options.showCode) || ! isreal (options.showCode))
+    error ("publish: SHOWCODE must be TRUE or FALSE");
+  endif
+
+  doc.title = "";
+  doc.intro = "";
+  doc.body = cell ();
+  doc.m_source = deblank (read_file_to_cellstr (file));
+  doc.m_source_file_name = file;
+
+  ## Split code and paragraphs, find formatting
+  doc = parse_m_source (doc);
+
+  ## Create output directory
+  [status, msg] = mkdir (options.outputDir);
+  if (status != 1)
+    error ("publish: cannot create output directory: %s", msg);
+  endif
+
+  if (options.evalCode)
+    doc = eval_code (doc, options);
+  endif
+
+  output_file = create_output (doc, options);
+
+endfunction
+
+
+function doc = parse_m_source (doc)
+  ## PARSE_M_SOURCE First parsing level
+  ##   This function extracts the overall structure (paragraphs and code
+  ##   sections) given in doc.m_source.
+  ##
+  ##   The result is written to doc.body, which then contains a cell
+  ##   vector of structs, either of
+  ##
+  ##     a) {struct ("type", "code", ...
+  ##                 "lines", [a, b], ...
+  ##                 "output", [])}
+  ##     b) {struct ("type", "section", ...
+  ##                 "content", title_str)}
+  ##
+  ##   Second parsing level is invoked for the paragraph contents, resulting
+  ##   in more elements for doc.body.
+
+  if (isempty (doc.m_source))
+    return;  # Nothing to parse
+  endif
+
+  ## Parsing helper functions
+  ##
+  ## 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) == " "));
+  ## 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
+  is_head = @(cstr) is_publish_markup (cstr, 2);
+  ## Checks line of cellstring to be a headline without section break, using
+  ## the cell mode in Matlab (for compatibility), just treated as a new head.
+  is_no_break_head = @(cstr) is_publish_markup (cstr, 3);
+
+  ## Find the indices of paragraphs starting with "%%", "##", or "%%%"
+  par_start_idx = find (cellfun (is_head, doc.m_source)
+                        | cellfun (is_no_break_head, doc.m_source));
+
+  ## If the whole document is code
+  if (isempty (par_start_idx))
+    doc.body{end+1}.type = "code";
+    doc.body{end}.content = strtrim (strjoin (doc.m_source, "\n"));
+    doc.body{end}.lines = [1, length(doc.m_source)];
+    doc.body{end}.output = {};
+    return;
+  endif
+
+  ## Determine continuous range of paragraphs
+  par_end_idx = [par_start_idx(2:end) - 1, length(doc.m_source)];
+  for i = 1:numel (par_end_idx)
+    idx = find (! cellfun (is_paragraph,
+                           doc.m_source(par_start_idx(i) + 1:par_end_idx(i))));
+    if (! isempty (idx))
+      par_end_idx(i) = par_start_idx(i) + idx(1) - 1;
+    endif
+  endfor
+  ## Code sections between paragraphs
+  code_start_idx = par_end_idx(1:end-1) + 1;
+  code_end_idx = par_start_idx(2:end) - 1;
+  ## Code at the beginning?
+  if (par_start_idx(1) > 1)
+    code_start_idx = [1, code_start_idx];
+    code_end_idx = [par_start_idx(1) - 1, code_end_idx];
+  endif
+  ## Code at the end?
+  if (par_end_idx(end) < length (doc.m_source))
+    code_start_idx = [code_start_idx, par_end_idx(end) + 1];
+    code_end_idx = [code_end_idx, length(doc.m_source)];
+  endif
+  ## Remove overlaps
+  idx = code_start_idx > code_end_idx;
+  code_start_idx(idx) = [];
+  code_end_idx(idx) = [];
+  ## Remove empty code blocks
+  idx = [];
+  for i = 1:numel (code_start_idx)
+    if (all (cellfun (@(cstr) isempty (char (cstr)),
+                      doc.m_source(code_start_idx(i):code_end_idx(i)))))
+      idx = [idx, i];
+    endif
+  endfor
+  code_start_idx(idx) = [];
+  code_end_idx(idx) = [];
+
+  ## Try to find a document title and introduction text
+  ##   1. First paragraph must start in first line
+  ##   2. Second paragraph must start before any code
+  title_offset = 0;
+  if (is_head (doc.m_source{1})
+      && ! isempty (par_start_idx)
+      && par_start_idx(1) == 1
+      && (isempty (code_start_idx)
+          || (length (par_start_idx) > 1
+              && par_start_idx(2) < code_start_idx(1))))
+    doc.title = doc.m_source{1};
+    doc.title = doc.title(4:end);
+    content = doc.m_source(2:par_end_idx(1));
+    ## Strip leading "# "
+    content = cellfun (@(c) cellstr (c(3:end)), content);
+    doc.intro = parse_paragraph_content (content);
+    title_offset = 1;
+  endif
+
+  ## Add non-empty paragraphs and code to doc
+  j = 1;
+  i = (1 + title_offset);
+  while (i <= numel (par_start_idx) || j <= numel (code_start_idx))
+    ## Add code while there is code left
+    ##   and code is before the next paragraph or there are no more paragraphs
+    while (j <= numel (code_start_idx)
+           && (i > numel (par_start_idx)
+               || par_start_idx(i) > code_start_idx(j)))
+      doc.body{end+1}.type = "code";
+      lines = [code_start_idx(j), code_end_idx(j)];
+      doc.body{end}.content = ...
+        strtrim (strjoin (doc.m_source(lines(1):lines(2)), "\n"));
+      doc.body{end}.lines = lines;
+      doc.body{end}.output = {};
+      j++;
+    endwhile
+
+    if (i <= numel (par_start_idx))
+      type_str = "section";
+      title_str = doc.m_source{par_start_idx(i)};
+      if (is_head (doc.m_source(par_start_idx(i))))
+        title_str = title_str(4:end);
+      else
+        title_str = title_str(5:end);
+      endif
+      ## Append, if paragraph title is given
+      if (! isempty (title_str))
+        doc.body{end+1}.type = type_str;
+        doc.body{end}.content = title_str;
+      endif
+
+      content = doc.m_source(par_start_idx(i) + 1:par_end_idx(i));
+      ## Strip leading "# "
+      content = cellfun (@(c) cellstr (c(3:end)), content);
+      doc.body = [doc.body, parse_paragraph_content(content)];
+      i++;
+    endif
+  endwhile
+
+endfunction
+
+
+function p_content = parse_paragraph_content (content)
+  ## PARSE_PARAGRAPH_CONTENT second parsing level
+  ##
+  ##   Parses the content of a paragraph (without potential title) and
+  ##   returns a cell vector of structs, that can be appended to doc.body,
+  ##   either of
+  ##
+  ##     a) {struct ("type", "preformatted_code", ...
+  ##                 "content", code_str)}
+  ##     b) {struct ("type", "preformatted_text", ...
+  ##                 "content", text_str)}
+  ##     c) {struct ("type", "bulleted_list", ...
+  ##                 "content", {"item1", "item2", ..})}
+  ##     d) {struct ("type", "numbered_list", ...
+  ##                 "content", {"item1", "item2", ..})}
+  ##     e) {struct ("type", "include", ...
+  ##                 "content", file_str)}
+  ##     f) {struct ("type", "graphic", ...
+  ##                 "content", file_str)}
+  ##     g) {struct ("type", "html", ...
+  ##                 "content", html_str)}
+  ##     h) {struct ("type", "latex", ...
+  ##                 "content", latex_str)}
+  ##     i) {struct ("type", "text", ...
+  ##                 "content", text_str)}
+  ##
+  ##   Option i) might contain:
+  ##
+  ##     * Italic "_", bold "*", and monospaced "|" text
+  ##     * Inline "$" and block "$$" LaTeX math
+  ##     * Links
+  ##     * Trademark symbols
+
+  p_content = cell ();
+
+  if (isempty (content))
+    return;
+  endif
+
+  ## Extract <html> and <latex> blocks recursively.
+  content_str = strjoin (content, "\n");
+  tags = {"html", "latex"};
+  for i = 1:length(tags)
+    tok = regexp (content_str, ...
+      ['(.*?)(^|\n\n)(<', tags{i}, '>)\n(.*?)\n(<\/', ...
+        tags{i}, '>)($|\n\n)(.*)'], "tokens", "once");
+    if (! isempty (tok))
+      ## If there was some text before that block --> recursion
+      if (! strcmpi (tok{1}, ["<", tags{i}, ">"]))
+        p_content = parse_paragraph_content (strsplit (tok{1}, "\n"));
+        tok(1:2) = [];
+      endif
+      ## Extract the block content
+      p_content{end+1}.type = tags{i};
+      p_content{end}.content = tok{2};
+      ## If there was some text after that block --> recursion
+      if (length (tok) == 5)
+        p_content = [p_content, ...
+          parse_paragraph_content(strsplit (tok{5}, "\n"))];
+      endif
+      return;
+    endif
+  endfor
+
+  ## Split into blocks separated by empty lines
+  idx = [0, find(cellfun (@isempty, content)), length(content) + 1];
+
+  ## For each block
+  for i = find (diff (idx) > 1)
+    block = content(idx(i) + 1:idx(i+1) - 1);
+
+    ## Octave code (two leading spaces)
+    if (all (cellfun (@(c) strncmp (char (c), "  ", 2), block)))
+      p_content{end+1}.type = "preformatted_code";
+      block = cellfun (@(c) cellstr (c(3:end)), block);
+      p_content{end}.content = strjoin (block, "\n");
+      continue;
+    endif
+
+    ## Preformatted text (one leading space)
+    if (all (cellfun (@(c) strncmp (char (c), " ", 1), block)))
+      p_content{end+1}.type = "preformatted_text";
+      block = cellfun (@(c) cellstr (c(2:end)), block);
+      p_content{end}.content = strjoin (block, "\n");
+      continue;
+    endif
+
+    ## Bulleted list starts with "* "
+    if (strncmp (block{1}, "* ", 2))
+      p_content{end+1}.type = "bulleted_list";
+      tmpstr = strjoin (block, "\n");
+      ## Remove first "* "
+      tmpstr = tmpstr(3:end);
+      ## Split items
+      p_content{end}.content = strsplit (tmpstr, "\n* ");
+      continue;
+    endif
+
+    ## Numbered list starts with "# "
+    if (strncmp (block{1}, "# ", 2))
+      p_content{end+1}.type = "numbered_list";
+      tmpstr = strjoin (block, "\n");
+      ## Remove first "# "
+      tmpstr = tmpstr(3:end);
+      ## Split items
+      p_content{end}.content = strsplit (tmpstr, "\n# ");
+      continue;
+    endif
+
+    ## Include <include>fname.m</include>
+    if (! isempty (fname = regexpi (strjoin (block, ""),
+                                    '^<include>(.*)</include>$',
+                                    "tokens")))
+      ## Includes result in preformatted code
+      p_content{end+1}.type = "preformatted_code";
+      include_code = read_file_to_cellstr (strtrim ((fname{1}){1}));
+      p_content{end}.content = strjoin (include_code, "\n");
+
+      continue;
+    endif
+
+    ## Graphic <<myGraphic.png>>
+    if (! isempty (fname = regexpi (strjoin (block, ""),
+                                    '^<<(.*)>>$',
+                                    "tokens")))
+      p_content{end+1}.type = "graphic";
+      p_content{end}.content = strtrim ((fname{1}){1});
+      continue;
+    endif
+
+    ## Now it can be only normal text or markups belonging to normal text
+    ## that are handled while output generation:
+    ##
+    ## * Italic "_", bold "*", and monospaced "|" text
+    ## * Inline "$" and block "$$" LaTeX math
+    ## * Links
+    ## * Trademark symbols
+    p_content{end+1}.type = "text";
+    p_content{end}.content = strjoin (block, "\n");
+  endfor
+endfunction
+
+
+function m_source = read_file_to_cellstr (file)
+  ## READ_FILE_TO_CELLSTR reads a given file line by line into a cellstring
+
+  fid = fopen (file, "r");
+  i = 0;
+  do
+    m_source{++i} = fgetl (fid);
+  until (! ischar (m_source{i}))
+  fclose (fid);
+  m_source = m_source(1:end-1);  # No EOL
+endfunction
+
+
+function ofile = create_output (doc, options)
+  ## CREATE_OUTPUT creates the desired output file
+
+  formatter = [];
+  switch (options.format)
+    case "html"
+      formatter = @__publish_html_output__;
+    case {"latex", "pdf"}
+      formatter = @__publish_latex_output__;
+    otherwise
+      ## Custom formatter
+      formatter = eval (["@__publish_", options.format, "_output__"]);
+  endswitch
+
+  ## Use title, or if not given, the m-file name
+  title_str = doc.title;
+  if (isempty (title_str))
+    [~, title_str] = fileparts (doc.m_source_file_name);
+  endif
+
+  content = formatter ("header",
+                       formatter ("escape_special_chars", title_str),
+                       format_output (doc.intro, formatter, options),
+                       get_toc (doc.body, formatter));
+  content = [content, format_output(doc.body, formatter, options)];
+  content = [content, formatter("footer", strjoin (doc.m_source, "\n"))];
+
+  ## Write file
+  [~, ofile] = fileparts (doc.m_source_file_name);
+  ofile_name = [ofile, formatter("output_file_extension")];
+  ofile = fullfile (options.outputDir, ofile_name);
+  fid = fopen (ofile, "w");
+  fputs (fid, content);
+  fclose (fid);
+
+  ## Compile LaTeX, if compiler found
+  if (strcmp (options.format, "pdf"))
+    status = system ("pdflatex --version");
+    if (status == 0)
+      for i = 1:2
+        ## FIXME: This looks very likely to break when switching OS
+        system (["cd ", options.outputDir," && pdflatex ", ofile_name]);
+      endfor
+    endif
+  endif
+endfunction
+
+
+function toc_cstr = get_toc (cstr, formatter)
+  ## GET_TOC extracts the table of contents from a cellstring (e.g., doc.body)
+  ## with each section headline as a cell in a returned cellstring.
+
+  toc_cstr = cell ();
+  for i = 1:numel (cstr)
+    if (strcmp (cstr{i}.type, "section"))
+      toc_cstr{end+1} = format_text (cstr{i}.content, formatter);
+    endif
+  endfor
+endfunction
+
+
+function str = format_output (cstr, formatter, options)
+  ## FORMAT_OUTPUT steps through all blocks (doc.intro or doc.body) in cstr and
+  ## produces a single result string with the source code in the desired output
+  ## format.
+  ##
+  ##   formatter has the only knowledge how to enforce the target format
+  ##   and produces for each block the necessary target format source string.
+
+  str = "";
+  for i = 1:numel (cstr)
+    switch (cstr{i}.type)
+      case "code"
+        if (options.showCode)
+          str = [str, formatter("code", cstr{i}.content)];
+        endif
+        if ((options.evalCode) && (! isempty (cstr{i}.output)))
+          str = [str, formatter("code_output", cstr{i}.output)];
+        endif
+      case {"text", "section"}
+        str = [str, formatter(cstr{i}.type, ...
+                              format_text (cstr{i}.content, formatter))];
+      case {"bulleted_list", "numbered_list"}
+        items = cellfun (@(str) format_text(str, formatter), ...
+                         cstr{i}.content, "UniformOutput", false);
+        str = [str, formatter(cstr{i}.type, items)];
+      otherwise
+        str = [str, formatter(cstr{i}.type, cstr{i}.content)];
+    endswitch
+  endfor
+
+endfunction
+
+
+function str = format_text (str, formatter)
+  ## FORMAT_TEXT formats inline formats in strings.
+  ##   These are: links, block/inline math, bold, italic, monospaced, (TM), (R)
+
+  ## Helper to clarify the following regular expressions.  It is suitable for
+  ## inline formatting, that is delimited literally at start and end by
+  ## `delim`.  `term` is an indicating character for the end delimiter.
+  ##
+  ## Best explained by example ('^' start and '$' end of input):
+  ##
+  ##  Positive matches:
+  ##
+  ##    ^*bold*$
+  ##    ^*bold*.$
+  ##    ^(*bold*)$
+  ##    ^ *bold* $
+  ##    ^Text *bold* text$
+  ##    ^*bold text*$
+  ##
+  ##  Negative matches:
+  ##
+  ##    ^Text*bold*text$
+  ##    ^*bold *$
+  ##    ^* bold* $
+  ##    ^*bold text *$
+  ##
+  regex_helper = @(delim, term) ['(^|(?<=\s)|(?=\W))', delim, ...
+    '(?!\s)[^', term, ']*(?<!\s)', delim, '($|(?=\s)|(?=\W))'];
+
+  ## Regular expressions for the formats:
+  ##
+  ## 1) Links "<http://www.someurl.com>"
+  ## 2) Links "<octave:Function TEXT>"
+  ## 3) Links "<http://www.someurl.com TEXT>"
+  ## 4) LaTeX block math "$$x^2$$"
+  ## 5) LaTeX inline math "$x^2$"
+  ## 6) Bold *text*
+  ## 7) Italic _text_
+  ## 8) Monospaced |text|
+  ## 9) (TM) or (R)
+  regexes = {'<\S{3,}[^\s<>]*>', ...
+             '<octave:[^\s<>]* *[^<>$]*>', ...
+             '<\S{3,}[^\s<>]* *[^<>$]*>', ...
+             regex_helper('\$\$', '$'), ...
+             regex_helper('\$', '$'), ...
+             regex_helper('\*', '*'), ...
+             regex_helper('_', '_'), ...
+             regex_helper('\|', '|'), ...
+             '\((TM|R)\)'};
+
+  ## Function to escape some special characters for the GNU Octave manual,
+  ## see https://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html
+  texinfo_esc = @(str) strrep (strrep (str, "-", "_002d"), "_", "_005f");
+
+  ## Substitute all occurrences with placeholders
+  placeholder_cstr = {};
+  plh = 0;
+  for i = 1:numel (regexes)
+    cstr = regexp (str, regexes{i}, "match");
+    for j = 1:numel (cstr)
+      plh += 1;
+      str = regexprep (str, regexes{i}, ["PUBLISHPLACEHOLDER" num2str(plh)],
+                       "once");
+      switch (i)
+        case 1
+          ## Links "<http://www.someurl.com>"
+          url = cstr{j};
+          cstr{j} = formatter ("link", url(2:end-1), url(2:end-1));
+        case 2
+          ## Links "<octave:Function TEXT>"
+          idx = strfind (cstr{j}, " ");
+          url = cstr{j};
+          url = texinfo_esc (url(9:idx-1));
+          v = version ();
+          if (v(end) == '+')
+            v = "interpreter";
+          endif
+          url = sprintf ( ...
+            "https://www.gnu.org/software/octave/doc/%s/XREF%s.html", v, url);
+          txt = cstr{j};
+          txt = format_text (txt(idx+1:end-1), formatter);
+          cstr{j} = formatter ("link", url, txt);
+        case 3
+          ## Links "<http://www.someurl.com TEXT>"
+          idx = strfind (cstr{j}, " ");
+          url = cstr{j};
+          url = url(2:idx-1);
+          txt = cstr{j};
+          txt = format_text (txt(idx+1:end-1), formatter);
+          cstr{j} = formatter ("link", url, txt);
+        case 4
+          ## LaTeX block math "$$"
+          txt = cstr{j};
+          cstr{j} = formatter ("blockmath", txt(3:end-2));
+        case 5
+          ## LaTeX inline math "$"
+          txt = cstr{j};
+          cstr{j} = formatter ("inlinemath", txt(2:end-1));
+        case 6
+          ## Bold
+          txt = cstr{j};
+          cstr{j} = formatter ("bold", format_text (txt(2:end-1), formatter));
+        case 7
+          ## Italic
+          txt = cstr{j};
+          cstr{j} = formatter ("italic", format_text (txt(2:end-1), formatter));
+        case 8
+          ## Monospaced
+          txt = cstr{j};
+          cstr{j} = formatter ("monospaced", format_text (txt(2:end-1), ...
+                               formatter));
+        case 9
+          ## (TM) or (R)
+          txt = cstr{j};
+          cstr{j} = formatter (txt(2:end-1));
+      endswitch
+    endfor
+    placeholder_cstr = [placeholder_cstr, cstr];
+  endfor
+
+  ## Replace special symbols
+  str = formatter ("escape_special_chars", str);
+
+  ## Restore placeholders
+  for i = plh:-1:1
+    str = strrep (str, ["PUBLISHPLACEHOLDER" sprintf("%d", i)],
+                       placeholder_cstr{i});
+  endfor
+
+endfunction
+
+
+function doc = eval_code (doc, options)
+  ## EVAL_CODE Third level parsing
+  ##
+  ##   Generates the output of the script code and takes care of generated
+  ##   figures.
+
+  ## Necessary as the code does not run interactively
+  page_screen_output (false, "local");
+
+  ## Remember previously opened figures
+  fig_ids = findall (0, "type", "figure");
+  [~, fig_name] = fileparts (doc.m_source_file_name);
+  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);
+
+  ## Create a new figure, if there are existing plots
+  if (! isempty (fig_ids) && options.useNewFigure)
+    figure ();
+  endif
+
+  for i = 1:numel (doc.body)
+    if (strcmp (doc.body{i}.type, "code"))
+      r = doc.body{i}.lines;
+      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);
+         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);
+      endif
+
+      ## Check for newly created figures ...
+      fig_ids_new = setdiff (findall (0, "type", "figure"), fig_ids);
+      ## ... and save them
+      for j = 1:numel (fig_ids_new)
+        drawnow ();
+        if (isempty (get (fig_ids_new(j), "children")))
+          continue;
+        endif
+        fname = [fig_name, "-", sprintf("%d", fig_num)];
+        if (strncmp (options.imageFormat, "eps", 3))
+          fname = [fname ".eps"];
+        else
+          fname = [fname "." options.imageFormat];
+        endif
+        print_opts = {fig_ids_new(j), ...
+                      fullfile(options.outputDir, fname), ...
+                      ["-d" options.imageFormat], "-color"};
+        if (! isempty (options.maxWidth) && ! isempty (options.maxHeight))
+          print_opts{end+1} = sprintf ("-S%d,%d", options.maxWidth,
+                                                  options.maxHeight);
+        elseif (! isempty (options.maxWidth) || ! isempty (options.maxHeight))
+          warning (["publish: specify both options.maxWidth ", ...
+                              "and options.maxHeight"]);
+        endif
+        print (print_opts{:});
+        fig_num++;
+        delete (fig_ids_new(j));
+        fig_elem = cell ();
+        fig_elem{1} = struct ("type", "graphic", "content", fname);
+        if (isfield (fig_list, num2str (i)))
+          fig_elem = [getfield(fig_list, sprintf ("%d", i)), fig_elem];
+        endif
+        fig_list = setfield (fig_list, sprintf ("%d", i), fig_elem);
+        ## Create a new figure, if there are existing plots
+        if (isempty (setdiff (findall (0, "type", "figure"), fig_ids)) ...
+            && ! isempty (fig_ids) && options.useNewFigure)
+          figure ();
+        endif
+      endfor
+
+      ## Truncate output to desired length
+      if (options.maxOutputLines < length (doc.body{i}.output))
+        doc.body{i}.output = doc.body{i}.output(1:options.maxOutputLines);
+      endif
+      doc.body{i}.output = strjoin (doc.body{i}.output, "\n");
+    endif
+  endfor
+
+  ## 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;
+  for i = 1:numel (fig_code_blocks)
+    elems = getfield (fig_list, fig_code_blocks{i});
+    ## Compute index where the figure(s) has to be inserted
+    j = str2double (fig_code_blocks{i}) + body_offset;
+    doc.body = [doc.body(1:j), elems, doc.body(j+1:end)];
+    body_offset = body_offset + numel (elems);
+  endfor
+
+endfunction
+
+
+function cstr = eval_code_helper (context, 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))
+    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");
+endfunction
+
+
+## FIXME: Missing any functional BIST tests
+## FIXME: Need to create a temporary file for use with error testing
+
+## Test input validation
+%!error publish ()
+%!error publish (1)
+%!error <FILE does not exist> publish ("%%_non_existent_file_%%.m")
+%!error <only script files can be published> publish ("publish.m")
+%!error publish ("test_script.m", "format", "html", "showCode")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/saveobj.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,45 @@
+## Copyright (C) 2008-2017 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
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{b} =} saveobj (@var{a})
+## Method of a class to manipulate an object prior to saving it to a file.
+##
+## The function @code{saveobj} is called when the object @var{a} is saved
+## using the @code{save} function.  An example of the use of @code{saveobj}
+## might be to remove fields of the object that don't make sense to be saved
+## or it might be used to ensure that certain fields of the object are
+## initialized before the object is saved.  For example:
+##
+## @example
+## @group
+## function b = saveobj (a)
+##   b = a;
+##   if (isempty (b.field))
+##      b.field = initfield (b);
+##   endif
+## endfunction
+## @end group
+## @end example
+##
+## @seealso{loadobj, class}
+## @end deftypefn
+
+function b = saveobj (a)
+  error ('saveobj: not defined for class "%s"', class (a));
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/validateattributes.m	Thu Dec 28 16:14:37 2017 -0800
@@ -0,0 +1,732 @@
+## Copyright (C) 2013-2017 Carnë Draug
+## Copyright (C) 2016 Carlo de Falco
+##
+## 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  {} {} validateattributes (@var{A}, @var{classes}, @var{attributes})
+## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{arg_idx})
+## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name})
+## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name})
+## @deftypefnx {} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name}, @var{arg_idx})
+## Check validity of input argument.
+##
+## Confirms that the argument @var{A} is valid by belonging to one of
+## @var{classes}, and holding all of the @var{attributes}.  If it does not,
+## an error is thrown, with a message formatted accordingly.  The error
+## message can be made further complete by the function name @var{fun_name},
+## the argument name @var{arg_name}, and its position in the input
+## @var{arg_idx}.
+##
+## @var{classes} must be a cell array of strings (an empty cell array is
+## allowed) with the name of classes (remember that a class name is case
+## sensitive).  In addition to the class name, the following categories
+## names are also valid:
+##
+## @table @asis
+## @item @qcode{"float"}
+## Floating point value comprising classes @qcode{"double"} and
+## @qcode{"single"}.
+##
+## @item @qcode{"integer"}
+## Integer value comprising classes (u)int8, (u)int16, (u)int32, (u)int64.
+##
+## @item @qcode{"numeric"}
+## Numeric value comprising either a floating point or integer value.
+##
+## @end table
+##
+## @var{attributes} must be a cell array with names of checks for @var{A}.
+## Some of them require an additional value to be supplied right after the
+## name (see details for each below).
+##
+## @table @asis
+## @item @qcode{"<="}
+## All values are less than or equal to the following value in
+## @var{attributes}.
+##
+## @item @qcode{"<"}
+## All values are less than the following value in @var{attributes}.
+##
+## @item @qcode{">="}
+## All values are greater than or equal to the following value in
+## @var{attributes}.
+##
+## @item @qcode{">"}
+## All values are greater than the following value in @var{attributes}.
+##
+## @item @qcode{"2d"}
+## A 2-dimensional matrix.  Note that vectors and empty matrices have
+## 2 dimensions, one of them being of length 1, or both length 0.
+##
+## @item @qcode{"3d"}
+## Has no more than 3 dimensions.  A 2-dimensional matrix is a 3-D matrix
+## whose 3rd dimension is of length 1.
+##
+## @item @qcode{"binary"}
+## All values are either 1 or 0.
+##
+## @item @qcode{"column"}
+## Values are arranged in a single column.
+##
+## @item @qcode{"decreasing"}
+## No value is @var{NaN}, and each is less than the preceding one.
+##
+## @item @qcode{"diag"}
+## Value is a diagonal matrix.
+##
+## @item @qcode{"even"}
+## All values are even numbers.
+##
+## @item @qcode{"finite"}
+## All values are finite.
+##
+## @item @qcode{"increasing"}
+## No value is @var{NaN}, and each is greater than the preceding one.
+##
+## @item @qcode{"integer"}
+## All values are integer.  This is different than using @code{isinteger}
+## which only checks its an integer type.  This checks that each value in
+## @var{A} is an integer value, i.e., it has no decimal part.
+##
+## @item @qcode{"ncols"}
+## Has exactly as many columns as the next value in @var{attributes}.
+##
+## @item @qcode{"ndims"}
+## Has exactly as many dimensions as the next value in @var{attributes}.
+##
+## @item @qcode{"nondecreasing"}
+## No value is @var{NaN}, and each is greater than or equal to the preceding
+## one.
+##
+## @item @qcode{"nonempty"}
+## It is not empty.
+##
+## @item @qcode{"nonincreasing"}
+## No value is @var{NaN}, and each is less than or equal to the preceding one.
+##
+## @item @qcode{"nonnan"}
+## No value is a @code{NaN}.
+##
+## @item @nospell{@qcode{"nonnegative"}}
+## All values are non negative.
+##
+## @item @qcode{"nonsparse"}
+## It is not a sparse matrix.
+##
+## @item @qcode{"nonzero"}
+## No value is zero.
+##
+## @item @qcode{"nrows"}
+## Has exactly as many rows as the next value in @var{attributes}.
+##
+## @item @qcode{"numel"}
+## Has exactly as many elements as the next value in @var{attributes}.
+##
+## @item @qcode{"odd"}
+## All values are odd numbers.
+##
+## @item @qcode{"positive"}
+## All values are positive.
+##
+## @item @qcode{"real"}
+## It is a non-complex matrix.
+##
+## @item @qcode{"row"}
+## Values are arranged in a single row.
+##
+## @item @qcode{"scalar"}
+## It is a scalar.
+##
+## @item @qcode{"size"}
+## Its size has length equal to the values of the next in @var{attributes}.
+## The next value must is an array with the length for each dimension.  To
+## ignore the check for a certain dimension, the value of @code{NaN} can be
+## used.
+##
+## @item @qcode{"square"}
+## Is a square matrix.
+##
+## @item @qcode{"vector"}
+## Values are arranged in a single vector (column or vector).
+##
+## @end table
+##
+## @seealso{isa, validatestring, inputParser}
+## @end deftypefn
+
+function validateattributes (A, cls, attr, varargin)
+
+  if (nargin < 3 || nargin > 6)
+    print_usage ();
+  elseif (! iscellstr (cls))
+    error ("Octave:invalid-type",
+           "validateattributes: CLASSES must be a cell array of strings");
+  elseif (! iscell (attr))
+    error ("Octave:invalid-type",
+           "validateattributes: ATTRIBUTES must be a cell array");
+  endif
+
+  ## Built start of error message from the extra optional arguments
+  func_name = "";
+  var_name  = "input";
+  if (nargin > 3)
+    fourth = varargin{1};
+    if (ischar (fourth))
+      func_name = [fourth ": "];
+    elseif (nargin == 4 && valid_arg_idx (fourth))
+      var_name = sprintf ("input %d", fourth);
+    else
+      error ("Octave:invalid-input-arg",
+             "validateattributes: 4th input argument must be ARG_IDX or FUNC_NAME");
+    endif
+
+    if (nargin > 4)
+      var_name = varargin{2};
+      if (! ischar (var_name))
+        error ("Octave:invalid-type",
+               "validateattributes: VAR_NAME must be a string");
+      endif
+
+      if (nargin > 5)
+        arg_idx = varargin{3};
+        if (! valid_arg_idx (arg_idx))
+          error ("Octave:invalid-input-arg",
+                 "validateattributes: ARG_IDX must be a positive integer");
+        endif
+        var_name = sprintf ("%s (argument #%i)", var_name, arg_idx);
+      endif
+    endif
+  endif
+  err_ini = [func_name var_name];
+
+  check_cl = isa (A, cls);
+  if (! isempty (check_cl) && ! any (check_cl))
+    ## Allowing for an empty list of classes is Matlab incompatible but
+    ## that should count as a just a Matlab bug, not an incompatibility.
+
+    ## Replace the category names with the classes that belong to it.
+    integer = { "int8"  "int16"  "int32"  "int64" ...
+               "uint8" "uint16" "uint32" "uint64"};
+    float   = {"single" "double"};
+    numeric = {integer{:} float{:}};
+    cls = replace_cl_group (cls, "integer", integer);
+    cls = replace_cl_group (cls, "float",   float  );
+    cls = replace_cl_group (cls, "numeric", numeric);
+    cls = unique (cls);
+
+    classes = sprintf (" %s", cls{:});
+    error ("Octave:invalid-type",
+           "%s must be of class:\n\n %s\n\nbut was of class %s",
+           err_ini, classes, class (A));
+  endif
+
+  ## We use a while loop because some attributes require the following value
+  ## in the cell array.  Also, we can't just get the boolean value for the
+  ## test and check at the end the error message since some of the tests
+  ## require some more complex error message.
+
+  ## It may look like that we don't perform enough input check in this
+  ## function (e.g., we don't check if there's a value after the size
+  ## attribute).  The reasoning is that this will be a function mostly used
+  ## by developers with fairly static input so any problem would be caught
+  ## immediately during that function development, it's no dependent on the
+  ## final user input.  In addition, it can be called so many times at the
+  ## start of every function, we want it to run specially fast.
+  idx = 1;
+  problem = false; # becomes true when one of the tests fails
+  while (idx <= numel (attr))
+    ## FIXME: once we use this in Octave core, it might be worthy to find
+    ## which attributes are checked more often, and place them in that
+    ## order inside the switch block.
+    switch (tolower (attr{idx++}))
+      case "2d",
+        problem = ndims (A) != 2;
+        err_id = "Octave:expected-2d";
+      case "3d",
+        problem = ndims (A) > 3;
+        err_id = "Octave:expected-3d";
+      case "column",
+        problem = ! iscolumn (A);
+        err_id = "Octave:expected-column";
+      case "row",
+        problem = ! isrow (A);
+        err_id = "Octave:expected-row";
+      case "scalar",
+        problem = ! isscalar (A);
+        err_id = "Octave:expected-scalar";
+      case "vector",
+        problem = ! isvector (A);
+        err_id = "Octave:expected-vector";
+      case "square",
+        problem = ! issquare (A);
+        err_id = "Octave:expected-square";
+      case "diag",
+        problem = ! isdiag (A);
+        err_id = "Octave:expected-diag";
+      case "nonempty",
+        problem = isempty (A);
+        err_id = "Octave:expected-nonempty";
+      case "nonsparse",
+        problem = issparse (A);
+        err_id = "Octave:expected-nonsparse";
+      case "binary",
+        problem = ! islogical (A) && ...
+                  any ((A(:) != 1) & (A(:) != 0));
+        err_id = "Octave:expected-binary";
+      case "even",
+        problem = any (rem (A(:), 2) != 0);
+        err_id = "Octave:expected-even";
+      case "odd",
+        problem = any (mod (A(:), 2) != 1);
+        err_id = "Octave:expected-odd";
+      case "integer",
+        problem = ! isinteger (A) && ...
+                  any (ceil (A(:)) != A(:));
+        err_id = "Octave:expected-integer";
+      case "real",
+        problem = ! isreal (A);
+        err_id = "Octave:expected-real";
+      case "finite",
+        problem = ! isinteger (A) && ...
+                  ! all (isfinite (A(:)));
+        err_id = "Octave:expected-finite";
+      case "nonnan",
+        problem = ! isinteger (A) && ...
+                  any (isnan (A(:)));
+        err_id = "Octave:expected-nonnan";
+      case "nonnegative",
+        problem = any (A(:) < 0);
+        err_id = "Octave:expected-nonnegative";
+      case "nonzero",
+        problem = any (A(:) == 0);
+        err_id = "Octave:expected-nonzero";
+      case "positive",
+        problem = any (A(:) <= 0);
+        err_id = "Octave:expected-positive";
+      case "decreasing",
+        problem = (any (isnan (A(:)))
+                   || any (diff (A(:)) >= 0));
+        err_id = "Octave:expected-decreasing";
+      case "increasing",
+        problem = (any (isnan (A(:)))
+                   || any (diff (A(:)) <= 0));
+        err_id = "Octave:expected-increasing";
+      case "nondecreasing",
+        problem = (any (isnan (A(:)))
+                   || any (diff (A(:)) <  0));
+        err_id = "Octave:expected-nondecreasing";
+      case "nonincreasing",
+        problem = (any (isnan (A(:)))
+                   || any (diff (A(:)) >  0));
+        err_id = "Octave:expected-nonincreasing";
+      case "size",
+        A_size = size (A);
+        w_size = attr{idx++};
+        A_size(isnan (w_size)) = NaN;
+        if (! isequaln (A_size, w_size))
+          A_size_str = sprintf ("%dx", size (A))(1:end-1);
+          w_size_str = sprintf ("%ix", w_size)(1:end-1);
+          w_size_str = strrep (w_size_str, "NaN", "N");
+          err_id = "Octave:incorrect-size";
+          error (err_id,
+                 "%s must be of size %s but was %s",
+                 err_ini, w_size_str, A_size_str);
+        endif
+      case "numel",
+        if (numel (A) != attr{idx++})
+          err_id = "Octave:incorrect-numel";
+          error (err_id,
+                 "%s must have %d elements", err_ini, attr{idx-1});
+        endif
+      case "ncols",
+        if (columns (A) != attr{idx++})
+          err_id = "Octave:incorrect-numcols";
+          error (err_id,
+                 "%s must have %d columns", err_ini, attr{idx-1});
+        endif
+      case "nrows",
+        if (rows (A) != attr{idx++})
+          err_id = "Octave:incorrect-numrows";
+          error (err_id,
+                 "%s must have %d rows", err_ini, attr{idx-1});
+        endif
+      case "ndims",
+        ## Note that a [4 5 1] matrix is not considered to have ndims == 3
+        ## but is ok for "3d".  This is not a bug.
+        if (ndims (A) != attr{idx++})
+          err_id = "Octave:incorrect-numdims";
+          error (err_id,
+                 "%s must have %d dimensions", err_ini, attr{idx-1});
+        endif
+      case ">"
+        if (! all (A(:) > attr{idx++}))
+          err_id = "Octave:expected-greater";
+          error (err_id,
+                 "%s must be greater than %f", err_ini, attr{idx-1});
+        endif
+      case ">="
+        if (! all (A(:) >= attr{idx++}))
+          err_id = "Octave:expected-greater-equal";
+          error (err_id,
+                 "%s must be greater than or equal to %f", err_ini, attr{idx-1});
+        endif
+      case "<"
+        if (! all (A(:) < attr{idx++}))
+          err_id = "Octave:expected-less";
+          error (err_id,
+                 "%s must be less than %f", err_ini, attr{idx-1});
+        endif
+      case "<="
+        if (! all (A(:) <= attr{idx++}))
+          err_id = "Octave:expected-less-equal";
+          error (err_id,
+                 "%s must be less than or equal to %f", err_ini, attr{idx-1});
+        endif
+      otherwise
+        err_id = "Octave:invalid-input-arg";
+        error (err_id,
+               "validateattributes: unknown ATTRIBUTE %s", attr{idx-1});
+    endswitch
+    if (problem)
+      error (err_id,
+             "%s must be %s", err_ini, attr{idx-1});
+    endif
+  endwhile
+
+endfunction
+
+function retval = valid_arg_idx (arg)
+  retval = isnumeric (arg) && isscalar (arg) && arg > 0 && arg == fix (arg);
+endfunction
+
+function cls = replace_cl_group (cls, name, group)
+  num_pos = strcmpi (cls, name);
+  if (any (num_pos))
+    cls(num_pos) = [];
+    cls(end+1:end+numel(group)) = group;
+  endif
+endfunction
+
+
+%!error <double> validateattributes (rand (5), {"uint8"}, {})
+%!error <single> validateattributes (uint8 (rand (5)), {"float"}, {})
+%!error <2d> validateattributes (rand (5, 5, 5), {}, {"2d"})
+%!error <3d> validateattributes (rand (5, 5, 5, 7), {}, {"3d"})
+%!error <column> validateattributes (rand (5, 5), {}, {"column"})
+%!error <column> validateattributes (rand (1, 5), {}, {"column"})
+%!error <row> validateattributes (rand (5, 5), {}, {"row"})
+%!error <row> validateattributes (rand (5, 1), {}, {"row"})
+%!error <scalar> validateattributes (rand (1, 5), {}, {"scalar"})
+%!error <vector> validateattributes (rand (5), {}, {"vector"})
+%!error <square> validateattributes (rand (5, 6), {}, {"square"})
+%!error <nonempty> validateattributes ([], {}, {"nonempty"})
+%!error <nonsparse> validateattributes (sparse(rand(5)), {}, {"nonsparse"})
+%!error <binary> validateattributes ("text", {}, {"binary"})
+%!error <binary> validateattributes ([0 1 0 3 0], {}, {"binary"})
+%!error <even> validateattributes ([2 3 6 8], {}, {"even"})
+%!error <even> validateattributes ([2 NaN], {}, {"even"})
+%!error <odd> validateattributes ([3 4 7 5], {}, {"odd"})
+%!error <odd> validateattributes ([5 NaN], {}, {"odd"})
+%!error <integer> validateattributes ([5 5.2 5.7], {}, {"integer"})
+%!error <real> validateattributes ([5i 8 9], {}, {"real"})
+%!error <finite> validateattributes ([5i Inf 8], {}, {"finite"})
+%!error <nonnan> validateattributes ([NaN Inf 8], {}, {"nonnan"})
+%!error <nonnegative> validateattributes ([7 8 -9], {}, {"nonnegative"})
+%!error <nonzero> validateattributes ([7 8 0], {}, {"nonzero"})
+%!error <positive> validateattributes ([7 0 8], {}, {"positive"})
+%!error <decreasing> validateattributes ([7 8 4 3 -5], {}, {"decreasing"})
+%!error <decreasing> validateattributes ([7 NaN 4 3 -5], {}, {"decreasing"})
+%!error <increasing> validateattributes ([7 8 4 9 20], {}, {"increasing"})
+%!error <increasing> validateattributes ([7 8 NaN 9 20], {}, {"increasing"})
+%!error <nonincreasing> validateattributes ([7 8 4 9 20], {}, {"nonincreasing"})
+%!error <nonincreasing> validateattributes ([7 8 NaN 9 20], {}, {"nonincreasing"})
+%!error <nondecreasing> validateattributes ([7 8 4 3 -5], {}, {"nondecreasing"})
+%!error <nondecreasing> validateattributes ([7 NaN 4 3 -5], {}, {"nondecreasing"})
+%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 4 7]})
+%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 NaN 7]})
+%!error <size> validateattributes (ones (5, 3, 6), {}, {"size", [5 3 6 2]})
+%!error <elements> validateattributes (ones (6, 3), {}, {"numel", 12})
+%!error <columns> validateattributes (ones (6, 2), {}, {"ncols", 3})
+%!error <rows> validateattributes (ones (6, 2), {}, {"nrows", 3})
+%!error <dimensions> validateattributes (ones (6, 2, 6, 3), {}, {"ndims", 3})
+%!error <greater than> validateattributes ([6 7 8 5], {}, {">", 5})
+%!error <greater than> validateattributes ([6 7 8 5], {}, {">=", 6})
+%!error <less than> validateattributes ([6 7 8 5], {}, {"<", 8})
+%!error <less than> validateattributes ([6 7 8 5], {}, {"<=", 7})
+%!error <diag> validateattributes ([0 0 0; 0 0 0; 1 0 0], {}, {"diag"})
+%!error <diag> validateattributes (repmat (eye (3), [1 1 3]), {}, {"diag"})
+
+%!test
+%! validateattributes (rand (5), {"numeric"}, {});
+%! validateattributes (rand (5), {"float"}, {});
+%! validateattributes (rand (5), {"double"}, {});
+%! validateattributes ("text", {"char"}, {});
+%! validateattributes (rand (5), {}, {"2d"});
+%! validateattributes (rand (5), {}, {"3d"});
+%! validateattributes (rand (5, 5, 5), {}, {"3d"});
+%! validateattributes (rand (5, 1), {}, {"column"});
+%! validateattributes (rand (1, 5), {}, {"row"});
+%! validateattributes ("a", {}, {"scalar"});
+%! validateattributes (5, {}, {"scalar"});
+%! validateattributes (rand (1, 5), {}, {"vector"});
+%! validateattributes (rand (5, 1), {}, {"vector"});
+%! validateattributes (rand (5), {}, {"square"});
+%! validateattributes (rand (5), {}, {"nonempty"});
+%! validateattributes (rand (5), {}, {"nonsparse"});
+%! validateattributes ([0 1 0 1 0], {}, {"binary"});
+%! validateattributes (rand (5) > 0.5, {}, {"binary"});
+%! validateattributes ([8 4 0 6], {}, {"even"});
+%! validateattributes ([-1 3 5], {}, {"odd"});
+%! validateattributes ([8 4 0 6], {}, {"real"});
+%! validateattributes ([8 4i 0 6], {}, {"finite"});
+%! validateattributes (uint8 ([8 4]), {}, {"finite"});
+%! validateattributes ([8 Inf], {}, {"nonnan"});
+%! validateattributes ([0 7 4], {}, {"nonnegative"});
+%! validateattributes ([-8 7 4], {}, {"nonzero"});
+%! validateattributes ([8 7 4], {}, {"positive"});
+%! validateattributes ([8 7 4 -5], {}, {"decreasing"});
+%! validateattributes ([-8 -7 4 5], {}, {"increasing"});
+%! validateattributes ([8 4 4 -5], {}, {"nonincreasing"});
+%! validateattributes ([-8 -8 4 5], {}, {"nondecreasing"});
+%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 6 7 2]});
+%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 NaN 7 2]});
+%! validateattributes (rand (4, 6, 7, 2), {}, {"size", [4 6 NaN 2 NaN]});
+%! validateattributes (rand (6, 2), {}, {"numel", 12});
+%! validateattributes (rand (6, 2), {}, {"ncols", 2});
+%! validateattributes (rand (6, 2), {}, {"nrows", 6});
+%! validateattributes (rand (6, 2, 4, 5), {}, {"ndims", 4});
+%! validateattributes ([4 5 6 7], {}, {">", 3});
+%! validateattributes ([4 5 6 7], {}, {">=", 4});
+%! validateattributes ([4 5 6 7], {}, {"<", 8});
+%! validateattributes ([4 5 6 7], {}, {"<=", 7});
+%! validateattributes (eye (3), {}, {"diag"});
+%! validateattributes ([1 0 0; 0 1 0; 0 0 1], {}, {"diag"});
+%! validateattributes (zeros (3), {}, {"diag"});
+
+%!test
+%! validateattributes ([0 1 0 1], {"double", "uint8"}, {"binary", "size", [NaN 4], "nonnan"});
+
+%!test
+%! try validateattributes (ones(1,2,3), {"numeric"}, {"2d"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-2d");
+%! end_try_catch
+
+%!test
+%! try validateattributes (ones(1,2,3,4), {"numeric"}, {"3d"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-3d");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"column"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-column");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2].', {"numeric"}, {"row"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-row");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"scalar"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-scalar");
+%! end_try_catch
+
+%!test
+%! try validateattributes (ones(3), {"numeric"}, {"vector"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-vector");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"size", [1 1]});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:incorrect-size");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"numel", 7});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:incorrect-numel");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"ncols", 7});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:incorrect-numcols");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"nrows", 7});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:incorrect-numrows");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"ndims", 5});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:incorrect-numdims");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"square"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-square");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"diag"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-diag");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([], {"numeric"}, {"nonempty"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonempty");
+%! end_try_catch
+
+%!test
+%! try validateattributes (speye(2), {"numeric"}, {"nonsparse"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonsparse");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {">", 3});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-greater");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {">=", 3});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-greater-equal");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"<", -3});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-less");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"<=", -3});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-less-equal");
+%! end_try_catch
+
+%!test
+%! try validateattributes (3, {"numeric"}, {"binary"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-binary");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1, {"numeric"}, {"even"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-even");
+%! end_try_catch
+
+%!test
+%! try validateattributes (2, {"numeric"}, {"odd"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-odd");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1.1, {"numeric"}, {"integer"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-integer");
+%! end_try_catch
+
+%!test
+%! try validateattributes (1+1i*2, {"numeric"}, {"real"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-real");
+%! end_try_catch
+
+%!test
+%! try validateattributes (Inf, {"numeric"}, {"finite"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-finite");
+%! end_try_catch
+
+%!test
+%! try validateattributes (NaN, {"numeric"}, {"nonnan"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonnan");
+%! end_try_catch
+
+%!test
+%! try validateattributes (-1, {"numeric"}, {"nonnegative"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonnegative");
+%! end_try_catch
+
+%!test
+%! try validateattributes (0, {"numeric"}, {"nonzero"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonzero");
+%! end_try_catch
+
+%!test
+%! try validateattributes (-1, {"numeric"}, {"positive"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-positive");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"decreasing"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-decreasing");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([2 1], {"numeric"}, {"increasing"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-increasing");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 0], {"numeric"}, {"nondecreasing"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nondecreasing");
+%! end_try_catch
+
+%!test
+%! try validateattributes ([1 2], {"numeric"}, {"nonincreasing"});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:expected-nonincreasing");
+%! end_try_catch
+
+%!test
+%! try validateattributes (@sin, {"numeric"}, {});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:invalid-type");
+%! end_try_catch
+
+%!test
+%! try validateattributes (@sin, 1, {});
+%! catch id,
+%! assert (getfield (id, "identifier"), "Octave:invalid-type");
+%! end_try_catch