changeset 22705:e9a0aa0a49ed

Overhaul publish function and it's private helper functions. * publish.m: Rewrite docstring. Don't use narginchk, nargoutchk. Don't end error messages with a period. Fix input validation to check that PROPERTY_NAME in a propert/value pair is a string, but value does not need to be. Rewrite messages in error() function calls. Use single quotes to reduce excessive backslashing. Don't require TRUE/FALSE options to be boolean, just real. Remove excessive parentheses around tests in if conditionals. Rename doc_struct to just doc for simplicity. Prefer numel() to length(). Correct cuddling of parentheses to indicate indexing versus function call. Use do/until loop rather than while loop to simplify loop setup. Use str2double rather than str2num. __publish_html_output__.m: Use sprintf() to create HERE documents to make definition of large constant blocks of text easier to understand. Prefer numel() over length(). Rename all handle_XXX functions to do_XXX to follow Octave convention. Use single quoted strings to avoid excessive backslashing. Add newlines to lists so that generated HTML is human-readable. Use in-place operators for efficiency. Use sprintf rather than num2str for efficiency. Use direct comparison when looking at a single character rather than strcmp for efficiency. Use single regexprep with alternation rather than for loop with individual patterns for efficiency. * __publish_latex_output__.m: Use sprintf() to create HERE documents to make definition of large constant blocks of text easier to understand. Prefer numel() over length(). Rename all handle_XXX functions to do_XXX to follow Octave convention. Use single quoted strings to avoid excessive backslashing.
author Rik <rik@octave.org>
date Mon, 31 Oct 2016 22:33:00 -0700
parents b5407b1ab11a
children 5a5d6c8647f6
files scripts/general/private/__publish_html_output__.m scripts/general/private/__publish_latex_output__.m scripts/general/publish.m
diffstat 3 files changed, 631 insertions(+), 607 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/general/private/__publish_html_output__.m	Mon Oct 31 12:22:43 2016 -0700
+++ b/scripts/general/private/__publish_html_output__.m	Mon Oct 31 22:33:00 2016 -0700
@@ -1,315 +1,332 @@
-function outstr = __publish_html_output__ (varargin)
-  ##
-  ## Types to handle are:
+function outstr = __publish_html_output__ (type, varargin)
+  ## Recognized types are:
   ##
-  ## * "header" (title_str, intro_str, toc_cstr)
-  ## * "footer" ()
-  ## * "code" (str)
-  ## * "code_output" (str)
-  ## * "section" (str)
-  ## * "preformatted_code" (str)
-  ## * "preformatted_text" (str)
-  ## * "bulleted_list" (cstr)
-  ## * "numbered_list" (cstr)
-  ## * "graphic" (str)
-  ## * "html" (str)
-  ## * "latex" (str)
-  ## * "text" (str)
-  ## * "bold" (str)
-  ## * "italic" (str)
-  ## * "monospaced" (str)
-  ## * "link" (url_str, url_str, str)
-  ## * "TM" ()
-  ## * "R" ()
-  ##
-  eval (["outstr = handle_", varargin{1}, " (varargin{2:end});"]);
+  ## "header" (title_str, intro_str, toc_cstr)
+  ## "footer" ()
+  ## "code" (str)
+  ## "code_output" (str)
+  ## "section" (str)
+  ## "preformatted_code" (str)
+  ## "preformatted_text" (str)
+  ## "bulleted_list" (cstr)
+  ## "numbered_list" (cstr)
+  ## "graphic" (str)
+  ## "html" (str)
+  ## "latex" (str)
+  ## "text" (str)
+  ## "bold" (str)
+  ## "italic" (str)
+  ## "monospaced" (str)
+  ## "link" (url_str, url_str, str)
+  ## "TM" ()
+  ## "R" ()
+
+  outstr = feval (["do_" type], varargin{:});
 endfunction
 
-function outstr = handle_header (title_str, intro_str, toc_cstr)
-  mathjax_str = ["<script type=\"text/x-mathjax-config\">\n", ...
-    "MathJax.Hub.Config({\n", ...
-    "  tex2jax: { inlineMath: [['$','$'], ['\\\\(','\\\\)']] },\n", ...
-    "  TeX: { equationNumbers: { autoNumber: 'all' } }\n", ...
-    "});\n", ...
-    "</script>\n", ...
-    "<script type=\"text/javascript\" async ", ...
-    "src=\"https://cdn.mathjax.org/mathjax/latest/MathJax.js?", ...
-    "config=TeX-MML-AM_CHTML\"></script>\n"];
-  stylesheet_str = ["<style>\n", ...
-    "body > * {\n", ...
-    "  max-width: 42em;\n", ...
-    "}\n", ...
-    "body {\n", ...
-    "  font-family: \"Roboto Condensed\", sans-serif;\n", ...
-    "  padding-left: 7.5em;\n", ...
-    "  padding-right: 7.5em;\n", ...
-    "}\n", ...
-    "pre, code {\n", ...
-    "  max-width: 50em;\n", ...
-    "  font-family: monospace;\n", ...
-    "}\n", ...
-    "pre.oct-code {\n", ...
-    "  border: 1px solid Grey;\n", ...
-    "  padding: 5px;\n", ...
-    "}\n", ...
-    "pre.oct-code-output {\n", ...
-    "  margin-left: 2em;\n", ...
-    "}\n", ...
-    "span.comment {\n", ...
-    "  color: ForestGreen;\n", ...
-    "}\n",...
-    "span.keyword {\n", ...
-    "  color: Blue;\n", ...
-    "}\n",...
-    "span.string {\n", ...
-    "  color: DarkOrchid;\n", ...
-    "}\n",...
-    "footer {\n", ...
-    "  margin-top: 2em;\n", ...
-    "  font-size: 80%;\n", ...
-    "}\n", ...
-    "a, a:visited {\n", ...
-    "  color: Blue;\n", ...
-    "}\n", ...
-    "h2 {\n", ...
-    "  font-family: \"Roboto Condensed\", serif;\n", ...
-    "  margin-top: 1.5em;\n", ...
-    "}\n", ...
-    "h2 a, h2 a:visited {\n", ...
-    "  color: Black;\n", ...
-    "}\n", ...
-    "</style>\n"];
-  outstr = ["<!DOCTYPE html>\n", ...
-    "<html>\n", ...
-    "<head>\n", ...
-    "<meta charset=\"UTF-8\">\n", ...
-    "<title>", title_str, "</title>\n", ...
-    mathjax_str, ...
-    stylesheet_str, ...
-    "</head>\n", ...
-    "<body>\n", ...
-    "<h1>", title_str, "</h1>\n", ...
-    intro_str];
+
+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://cdn.mathjax.org/mathjax/latest/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:length(toc_cstr)
-      toc_cstr{i} = handle_link (["#node", num2str(i)], toc_cstr{i});
+    for i = 1:numel (toc_cstr)
+      toc_cstr{i} = do_link (["#node" sprintf("%d", i)], toc_cstr{i});
     endfor
-    outstr = [outstr, "<h2>Contents</h2>", ...
-      handle_bulleted_list(toc_cstr)];
+    outstr = [outstr, "<h2>Contents</h2>", do_bulleted_list(toc_cstr)];
   endif
 
   ## Reset section counter
-  handle_section ();
+  do_section ();
+
 endfunction
 
-function outstr = handle_footer (m_source_str)
-  outstr = ["\n", ...
-    "<footer><hr>", ...
-    "<a href=\"http://www.octave.org\">Published with GNU Octave ", ...
-    version(), "</a></footer>\n", ...
-    "<!--\n", ...
-    "##### SOURCE BEGIN #####\n", ...
-    m_source_str, ...
-    "\n##### SOURCE END #####\n", ...
-    "-->\n", ...
-    "</body>\n", ...
-    "</html>\n"];
+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 = handle_code (str)
-  outstr = ["<pre class=\"oct-code\">", syntax_highlight(str), "</pre>"];
+function outstr = do_code (str)
+  outstr = ["\n", '<pre class="oct-code">' syntax_highlight(str) "</pre>\n"];
 endfunction
 
-function outstr = handle_code_output (str)
-  outstr = ["<pre class=\"oct-code-output\">", str, "</pre>"];
+function outstr = do_code_output (str)
+  outstr = ["\n", '<pre class="oct-code-output">' str "</pre>\n"];
 endfunction
 
-function outstr = handle_section (varargin)
+function outstr = do_section (varargin)
   persistent counter = 1;
+
   if (nargin == 0)
+    outstr = "";
     counter = 1;
-    outstr = "";
     return;
   endif
-  outstr = ["<h2><a id=\"node", num2str(counter), "\">", varargin{1}, ...
-    "</a></h2>"];
+
+  outstr = ['<h2><a id="node' sprintf("%d", counter) '">', ...
+            varargin{1}, ...
+            "</a></h2>"];
+
   counter++;
+
 endfunction
 
-function outstr = handle_preformatted_code (str)
-  outstr = ["<pre class=\"pre-code\">", syntax_highlight(str), "</pre>"];
+function outstr = do_preformatted_code (str)
+  outstr = ["\n", '<pre class="pre-code">' syntax_highlight(str) "</pre>\n"];
 endfunction
 
-function outstr = handle_preformatted_text (str)
-  outstr = ["<pre class=\"pre-text\">", str, "</pre>"];
+function outstr = do_preformatted_text (str)
+  outstr = ["\n", '<pre class="pre-text">' str "</pre>\n"];
 endfunction
 
-function outstr = handle_bulleted_list (cstr)
-  outstr = "<ul>";
-  for i = 1:length(cstr)
-    outstr = [outstr, "<li>", cstr{i}, "</li>"];
+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>"];
+  outstr = [outstr, "</ul>\n"];
 endfunction
 
-function outstr = handle_numbered_list (cstr)
-  outstr = "<ol>";
-  for i = 1:length(cstr)
-    outstr = [outstr, "<li>", cstr{i}, "</li>"];
+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>"];
+  outstr = [outstr, "</ol>\n"];
 endfunction
 
-function outstr = handle_graphic (str)
-  outstr = ["<img src=\"", str,"\" alt=\"", str, "\">"];
+function outstr = do_graphic (str)
+  outstr = ['<img src="' str '" alt="' str '">'];
 endfunction
 
-function outstr = handle_html (str)
+function outstr = do_html (str)
   outstr = str;
 endfunction
 
-function outstr = handle_latex (str)
+function outstr = do_latex (str)
   outstr = "";
 endfunction
 
-function outstr = handle_link (url_str, str)
-  outstr = ["<a href=\"", url_str,"\">", str, "</a>"];
+function outstr = do_link (url_str, str)
+  outstr = ['<a href="' url_str '">' str "</a>"];
 endfunction
 
-function outstr = handle_text (str)
-  outstr = ["<p>", str, "</p>"];
+function outstr = do_text (str)
+  outstr = ["\n<p>" str "</p>\n"];
 endfunction
 
-function outstr = handle_bold (str)
-  outstr = ["<b>", str, "</b>"];
+function outstr = do_bold (str)
+  outstr = ["<b>" str "</b>"];
 endfunction
 
-function outstr = handle_italic (str)
-  outstr = ["<i>", str, "</i>"];
+function outstr = do_italic (str)
+  outstr = ["<i>" str "</i>"];
 endfunction
 
-function outstr = handle_monospaced (str)
-  outstr = ["<code>", str, "</code>"];
+function outstr = do_monospaced (str)
+  outstr = ["<code>" str "</code>"];
 endfunction
 
-function outstr = handle_TM ()
+function outstr = do_TM ()
   outstr = "&trade;";
 endfunction
 
-function outstr = handle_R ()
+function outstr = do_R ()
   outstr = "&reg;";
 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)
-  ## SYNTAX_HIGHLIGHT a primitive parser to add syntax highlight via <span>
-  ##   tags. Should be replaced by a better solution.
-  ##
+  outstr = "";
+  placeholder_cstr = {};
+  i = 1;
+  plh = 0;
 
-  outstr = "";
-  i = 1;
-  placeholder_cstr = {};
-  plh = 0;
-  while (i <= length(str))
+  while (i <= numel (str))
     ## Block comment
     if (any (strncmp (str(i:end), {"%{", "#{"}, 2)))
-      plh_str = ["<span class=\"comment\">", str(i:i+1)];
-      i = i + 2;
-      while ((i <= length(str)) ...
+      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++;
+        i += 1;
       endwhile
-      if (i < length(str))
+      if (i < numel (str))
         plh_str = [plh_str, str(i:i+1), "</span>"];
-        i = i + 2;
+        i += 2;
       else
         plh_str = [plh_str, "</span>"];
       endif
-      plh = plh + 1;
+      plh += 1;
       placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", num2str(plh), " "];
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
     ## Line comment
-    elseif (any (strcmp (str(i), {"%", "#"})))
-      plh_str = "<span class=\"comment\">";
-      while ((i <= length(str)) && (! strcmp (str(i), "\n")))
-        plh_str = [plh_str, str(i)];
-        i++;
-      endwhile
+    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"];
-      i++;
-      plh = plh + 1;
+      plh += 1;
       placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", num2str(plh), " "];
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
     ## Single quoted string
-    elseif (strcmp (str(i), "'"))
+    elseif (str(i) == "'")
       plh_str = "<span class=\"string\">'";
-      i = i + 1;
-      while (i <= length(str))
+      i += 1;
+      while (i <= numel (str))
         ## Ignore escaped string terminations
         if (strncmp (str(i:end), "''", 2))
           plh_str = [plh_str, "''"];
-          i = i + 2;
-        ## Is string termination
-        elseif (strcmp (str(i), "'"))
+          i += 2;
+        ## Is char a string termination?
+        elseif (str(i) == "'")
           plh_str = [plh_str, "'"];
-          i = i + 1;
+          i += 1;
           break;
-        ## Is string termination by line break
-        elseif (strcmp (str(i), "\n"))
+        ## Is string terminated by line break?
+        elseif (str(i) == "\n")
           break;
         ## String content
         else
           plh_str = [plh_str, str(i)];
-          i = i + 1;
+          i += 1;
         endif
       endwhile
       plh_str = [plh_str, "</span>"];
-      plh = plh + 1;
+      plh += 1;
       placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", num2str(plh), " "];
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
     ## Double quoted string
-    elseif (strcmp (str(i), "\""))
-      plh_str = "<span class=\"string\">\"";
-      i = i + 1;
-      while (i <= length(str))
-        ## Is string termination
-        if (strcmp (str(i), "\"") && ! strcmp (str(i - 1), "\\"))
-          plh_str = [plh_str, "\""];
-          i = i + 1;
+    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 termination by line break
-        elseif (strcmp (str(i), "\n"))
+        ## Is string terminated by line break?
+        elseif (str(i) == "\n")
           break;
         ## String content
         else
           plh_str = [plh_str, str(i)];
-          i = i + 1;
+          i += 1;
         endif
       endwhile
       plh_str = [plh_str, "</span>"];
-      plh = plh + 1;
+      plh += 1;
       placeholder_cstr{plh} = plh_str;
-      outstr = [outstr, " PUBLISHPLACEHOLDER", num2str(plh), " "];
+      outstr = [outstr, " PUBLISHPLACEHOLDER", sprintf("%d", plh), " "];
     else
       outstr = [outstr, str(i)];
-      i++;
+      i += 1;
     endif
   endwhile
-  kwords = iskeyword ();
-  ## TODO: remove hack for regexp (bug #38149)
+
+  persistent kword_ptn = strjoin (iskeyword (), '|');
+
+  ## FIXME: remove hack for regexprep once bug #38149 is solved
   outstr = [" ", strrep(outstr, "\n", " \n "), " "];
-  for i = 1:length(kwords)
-    outstr = regexprep (outstr, ...
-      ['(\s)(', kwords{i},')(\s|\()'], ...
-      ["$1<span class=\"keyword\">$2</span>$3"]);
-  endfor
-  ## TODO: remove hack for regexp (bug #38149)
-  outstr = strrep(outstr(2:end-1), " \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", num2str(i), " "], ...
-      placeholder_cstr{i});
+    outstr = strrep (outstr, [" PUBLISHPLACEHOLDER", sprintf("%d", i), " "],
+                             placeholder_cstr{i});
   endfor
-endfunction
\ No newline at end of file
+
+endfunction
+
--- a/scripts/general/private/__publish_latex_output__.m	Mon Oct 31 12:22:43 2016 -0700
+++ b/scripts/general/private/__publish_latex_output__.m	Mon Oct 31 22:33:00 2016 -0700
@@ -1,6 +1,5 @@
-function outstr = __publish_latex_output__ (varargin)
-  ##
-  ## Types to handle are:
+function outstr = __publish_latex_output__ (type, varargin)
+  ## Recognized types are:
   ##
   ## * "header" (title_str, intro_str, toc_cstr)
   ## * "footer" ()
@@ -21,146 +20,169 @@
   ## * "link" (url_str, url_str, str)
   ## * "TM" ()
   ## * "R" ()
-  ##
-  eval (["outstr = handle_", varargin{1}, " (varargin{2:end});"]);
+
+  outstr = feval (["do_" type], varargin{:});
 endfunction
 
-function outstr = handle_header (title_str, intro_str, toc_cstr)
-  publish_comment = ["\n\n", ...
-    "% This document was generated by the publish-function\n", ...
-    "% from GNU Octave ", version(), "\n\n"];
+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 = ["\n\n", ...
-    "\\documentclass[10pt]{article}\n", ...
-    "\\usepackage{listings}\n", ...
-    "\\usepackage{mathtools}\n", ...
-    "\\usepackage{amssymb}\n", ...
-    "\\usepackage{graphicx}\n", ...
-    "\\usepackage{hyperref}\n", ...
-    "\\usepackage{xcolor}\n", ...
-    "\\usepackage{titlesec}\n", ...
-    "\\usepackage[utf8]{inputenc}\n", ...
-    "\\usepackage[T1]{fontenc}\n", ...
-    "\\usepackage{lmodern}\n"];
+  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 = ["\n\n", ...
-    "\\lstset{\n", ...
-    "language=Octave,\n", ...
-    "numbers=none,\n", ...
-    "frame=single,\n", ...
-    "tabsize=2,\n", ...
-    "showstringspaces=false,\n", ...
-    "breaklines=true}\n"];
+  listings_option = sprintf ("%s\n",
+"",
+"",
+'\lstset{',
+'language=Octave,',
+'numbers=none,',
+'frame=single,',
+'tabsize=2,',
+'showstringspaces=false,',
+'breaklines=true}');
 
-  latex_head = ["\n\n", ...
-    "\\titleformat*{\\section}{\\Huge\\bfseries}\n", ...
-    "\\titleformat*{\\subsection}{\\large\\bfseries}\n", ...
-    "\\renewcommand{\\contentsname}{\\Large\\bfseries Contents}\n", ...
-    "\\setlength{\\parindent}{0pt}\n\n",...
-    "\\begin{document}\n\n", ...
-    "{\\Huge\\section*{", escape_latex(title_str),"}}\n\n", ...
-    "\\tableofcontents\n", ...
-    "\\vspace*{4em}\n\n"];
+  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*{' escape_latex(title_str) '}}'],
+"",
+'\tableofcontents',
+'\vspace*{4em}',
+"");
 
   outstr = [publish_comment, latex_preamble, listings_option, latex_head];
+
 endfunction
 
-function outstr = handle_footer (m_source_str)
-  outstr = ["\n\n\\end{document}\n"];
-endfunction
-
-function outstr = handle_code (str)
-  outstr = ["\\begin{lstlisting}\n", str, "\n\\end{lstlisting}\n"];
+function outstr = do_footer (m_source_str)
+  outstr = ["\n\n" '\end{document}' "\n"];
 endfunction
 
-function outstr = handle_code_output (str)
-  outstr = ["\\begin{lstlisting}", ...
-    "[language={},xleftmargin=5pt,frame=none]\n", ...
-    str, "\n\\end{lstlisting}\n"];
+function outstr = do_code (str)
+  outstr = ['\begin{lstlisting}' "\n", str, "\n" '\end{lstlisting}' "\n"];
 endfunction
 
-function outstr = handle_section (str)
-  outstr = ["\n\n\\phantomsection\n", ...
-    "\\addcontentsline{toc}{section}{", escape_latex(str), "}\n", ...
-    "\\subsection*{", escape_latex(str), "}\n\n"];
+function outstr = do_code_output (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}[language={},xleftmargin=5pt,frame=none]',
+str,
+'\end{lstlisting}');
 endfunction
 
-function outstr = handle_preformatted_code (str)
-  outstr = ["\\begin{lstlisting}\n", str, "\n\\end{lstlisting}\n"];
+function outstr = do_section (str)
+  outstr = sprintf ("%s\n",
+"",
+"",
+'\phantomsection',
+['\addcontentsline{toc}{section}{' escape_latex(str) '}'],
+['\subsection*{' escape_latex(str) '}'],
+"");
 endfunction
 
-function outstr = handle_preformatted_text (str)
-  outstr = ["\\begin{lstlisting}[language={}]\n", ...
-    str, "\n\\end{lstlisting}\n"];
+function outstr = do_preformatted_code (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}',
+str,
+'\end{lstlisting}');
 endfunction
 
-function outstr = handle_bulleted_list (cstr)
-  outstr = "\n\\begin{itemize}\n";
-  for i = 1:length(cstr)
-    outstr = [outstr, "\\item ", escape_latex(cstr{i}), "\n"];
-  endfor
-  outstr = [outstr, "\\end{itemize}\n"];
+function outstr = do_preformatted_text (str)
+  outstr = sprintf ("%s\n",
+'\begin{lstlisting}[language={}]',
+str,
+'\end{lstlisting}');
 endfunction
 
-function outstr = handle_numbered_list (cstr)
-  outstr = "\n\\begin{enumerate}\n";
-  for i = 1:length(cstr)
-    outstr = [outstr, "\\item ", escape_latex(cstr{i}), "\n"];
+function outstr = do_bulleted_list (cstr)
+  outstr = ["\n" '\begin{itemize}' "\n"];
+  for i = 1:numel (cstr)
+    outstr = [outstr, '\item ' escape_latex(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 ' escape_latex(cstr{i}) "\n"];
   endfor
   outstr = [outstr, "\\end{enumerate}\n"];
 endfunction
 
-function outstr = handle_graphic (str)
-  outstr = ["\\begin{figure}[!ht]\n", ...
-    "\\includegraphics[width=\\textwidth]{", str, "}\n", ...
-    "\\end{figure}\n"];
+function outstr = do_graphic (str)
+  outstr = sprintf ("%s\n",
+'\begin{figure}[!ht]',
+['\includegraphics[width=\textwidth]{' str '}'],
+'\end{figure}');
 endfunction
 
-function outstr = handle_html (str)
+function outstr = do_html (str)
   outstr = "";
 endfunction
 
-function outstr = handle_latex (str)
+function outstr = do_latex (str)
   outstr = str;
 endfunction
 
-function outstr = handle_link (url_str, str)
-  outstr = ["\\href{", url_str,"}{", str, "}"];
+function outstr = do_link (url_str, str)
+  outstr = ['\href{' url_str '}{' str '}'];
 endfunction
 
-function outstr = handle_text (str)
-  outstr = ["\n\n", escape_latex(str), "\n\n"];
+function outstr = do_text (str)
+  outstr = ["\n\n" escape_latex(str) "\n\n"];
 endfunction
 
-function outstr = handle_bold (str)
-  outstr = ["\\textbf{", str, "}"];
+function outstr = do_bold (str)
+  outstr = ['\textbf{' str '}'];
 endfunction
 
-function outstr = handle_italic (str)
-  outstr = ["\\textit{", str, "}"];
+function outstr = do_italic (str)
+  outstr = ['\textit{' str '}'];
 endfunction
 
-function outstr = handle_monospaced (str)
-  outstr = ["\\texttt{", str, "}"];
+function outstr = do_monospaced (str)
+  outstr = ['\texttt{' str '}'];
 endfunction
 
-function outstr = handle_TM ()
-  outstr = "\\texttrademark ";
+function outstr = do_TM ()
+  outstr = '\texttrademark ';
 endfunction
 
-function outstr = handle_R ()
-  outstr = "\\textregistered ";
+function outstr = do_R ()
+  outstr = '\textregistered ';
 endfunction
 
 function str = escape_latex (str)
   ## Escape "&", "%", "#", "_", "~", "^", "<", ">"
-  ## TODO: "\", "{", "}"
-  str = regexprep (str, '(?<!\\)(&)', "\\&");
-  str = regexprep (str, '(?<!\\)(%)', "\\%");
-  str = regexprep (str, '(?<!\\)(#)', "\\#");
-  str = regexprep (str, '(?<!\\)(_)', "\\_");
+  ## FIXME: What about: "\", "{", "}"
+  str = regexprep (str, '(?<!\\)(&|%|#|_)', '\\$1');
   str = regexprep (str, '(?<!\\)(~)', "\\ensuremath{\\tilde{\;}}");
   str = regexprep (str, '(?<!\\)(\^)', "\\^{}");
   str = regexprep (str, '(?<!\\)(<)', "\\ensuremath{<}");
   str = regexprep (str, '(?<!\\)(>)', "\\ensuremath{>}");
 endfunction
+
--- a/scripts/general/publish.m	Mon Oct 31 12:22:43 2016 -0700
+++ b/scripts/general/publish.m	Mon Oct 31 22:33:00 2016 -0700
@@ -18,108 +18,110 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} publish (@var{filename})
-## @deftypefnx {} {} publish (@var{filename}, @var{output_format})
-## @deftypefnx {} {} publish (@var{filename}, @var{option1}, @var{value1}, @dots{})
-## @deftypefnx {} {} publish (@var{filename}, @var{options})
-## @deftypefnx {} {@var{output_file} =} publish (@var{filename}, @dots{})
+## @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 reports from Octave script files in several output formats.
+## Generate a report from the Octave script file @var{file} in one of several
+## output formats.
 ##
-## The generated reports consider 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 content
-## of a script file named @samp{example.m}:
+## 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*>.
-## %%
+## ## 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 ()
 ##
-## ## Octave comment style supported as well
-## #
-## # * Bulleted list item 1
-## # * Bulleted list item 2
-## #
-## # # Numbered list item 1
-## # # Numbered list item 2
+## %% @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 ("example.m")}.
+## To publish this script file, type @code{publish ("pub_example.m")}.
 ##
-## With only @var{filename} given, a HTML report is generated in a
-## subdirectory @samp{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{filename} is treated according
-## to the specified output format and included in the report.
+## 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{filename}, @var{output_format})} is
-## equivalent to the function call using a structure
+## 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{filename}, @var{options})
+## publish (@var{file}, @var{options})
 ## @end group
 ## @end example
 ##
 ## @noindent
-## which is described below.  The same holds for using option-value-pairs
+## which is described below.  The same holds for using option/value pairs
 ##
 ## @example
 ## @group
 ## @var{options}.@var{option1} = @var{value1};
-## publish (@var{filename}, @var{options})
+## 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 considered:
+## 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{xml}, or @samp{pdf}.
+## @samp{pdf}, or @samp{xml}.
 ##
-## The output formats @samp{doc}, @samp{ppt}, and @samp{xml} are currently
-## not supported.  To generate a @samp{doc} report, open a generated
-## @samp{html} report with your office suite.
+## 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.
 ##
 ## @item
-## @samp{outputDir} --- Full path string of a directory, where the generated
-## report will be located.  If no directory is given, the report is generated
-## in a subdirectory @samp{html} relative to the current working directory.
+## @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.
+## @samp{createThumbnail} --- Not supported, only for @sc{matlab}
+## compatibility.
 ##
 ## @item
-## @samp{figureSnapMethod} --- Not supported, only for @sc{matlab} compatibility.
+## @samp{figureSnapMethod} --- Not supported, only for @sc{matlab}
+## compatibility.
 ##
 ## @item
-## @samp{imageFormat} --- Desired format for images produced, while
-## evaluating the code.  The allowed image formats depend on the output
-## format:
+## @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} and @samp{xml} --- @samp{png} (default), any other
-## image format supported by Octave
+## @item @samp{html}, @samp{xml} --- @samp{png} (default), any image format
+## supported by Octave
 ##
-## @item @samp{latex} --- @samp{epsc2} (default), any other 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
@@ -129,15 +131,15 @@
 ## @end itemize
 ##
 ## @item
-## @samp{maxHeight} and @samp{maxWidth} --- Maximum height (width) of the
+## @samp{maxWidth} and @samp{maxHeight} --- Maximum width (height) of the
 ## produced images in pixels.  An empty value means no restriction.  Both
-## values have to be set, to work properly.
+## 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
+## @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}
@@ -148,18 +150,18 @@
 ## @samp{true} (default) or @samp{false}
 ##
 ## @item
-## @samp{catchError} --- Catch errors while code evaluation and continue
+## @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
+## @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 shown output lines of the
-## code evaluation
+## @samp{maxOutputLines} --- Maximum number of output lines from code
+## evaluation which are included in output.
 ##
 ## @samp{Inf} (default) or integer value > 0
 ##
@@ -170,18 +172,20 @@
 ## @samp{true} (default) or @samp{false}
 ## @end itemize
 ##
-## The returned @var{output_file} is a string with the path and file name
+## 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)
-  narginchk (1, Inf);
-  nargoutchk (0, 1);
+
+  if (nargin < 1)
+    print_usage ();
+  endif
 
   if (exist (file, "file") != 2)
-    error ("publish: FILE does not exist.");
+    error ("publish: FILE does not exist");
   endif
 
   ## Check file to be in Octave's load path
@@ -189,14 +193,15 @@
   if (isempty (file_path))
     file_path = pwd;
   endif
-  if (isempty (which ([file_name, file_ext])))
-    error (["publish: ", file, " is not in the load path."]);
+  if (exist ([file_name, file_ext]) != 2)
+    error (["publish: " file " is not in the load path"]);
   endif
 
   ## Check file extension and for an Octave script
+
   file_info = __which__ (file_name);
-  if ((! strcmp (file_ext, ".m")) || (! strcmp (file_info.type, "script")))
-    error ("publish: Only Octave script files can be published.");
+  if (! strcmp (file_ext, ".m") || ! strcmp (file_info.type, "script"))
+    error ("publish: only script files can be published");
   endif
 
   ## Check file to be parsable
@@ -212,38 +217,35 @@
     elseif (isstruct (varargin{1}))
       options = varargin{1};
     else
-      error ("publish: Invalid second argument.");
+      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))))
-    for i = 1:2:numel(varargin)
-      options = setfield (options, varargin{i}, varargin{i + 1});
-    endfor
+  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 or inappropriate arguments.");
+    error ("publish: invalid arguments");
   endif
 
-  ##
   ## Validate options struct
-  ##
 
   ## Options for the output
   if (! isfield (options, "format"))
     options.format = "html";
   else
-    options.format = validatestring (options.format, ...
-      {"html", "doc", "latex", "ppt", "xml", "pdf"});
-    ## TODO: implement remaining formats
+    options.format = validatestring (options.format, {"html", "doc", "latex",
+                                                      "ppt", "xml", "pdf"});
+    ## FIXME: Implement remaining formats
     if (any (strcmp (options.format, {"doc", "ppt", "xml"})))
-      error ("publish: Output format currently not supported");
+      error ('publish: Output format "%s" is not yet supported',
+             options.format);
     endif
   endif
 
   if (! isfield (options, "outputDir"))
-    ## Matlab R2016a doc says default is "", but specifies to create a sub
-    ## directory named "html" in the current working directory.
-    options.outputDir = [file_path, filesep(), "html"];
+    ## 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
@@ -257,8 +259,8 @@
   ## Options for the figures
   if (! isfield (options, "createThumbnail"))
     options.createThumbnail = true;
-  elseif ((! isscalar (options.createThumbnail)) ...
-          || (! isbool (options.createThumbnail)))
+  elseif (! isscalar (options.createThumbnail)
+          || ! isreal (options.createThumbnail))
     error ("publish: CREATETHUMBNAIL must be TRUE or FALSE");
   endif
 
@@ -267,8 +269,8 @@
   else
     options.figureSnapMethod = validatestring (options.figureSnapMethod, ...
       {"entireGUIWindow", "print", "getframe", "entireFigureWindow"});
-    ## TODO: implement
-    warning ("publish: option FIGURESNAPMETHOD currently not supported")
+    ## FIXME: implement other SnapMethods
+    warning ("publish: option FIGURESNAPMETHOD currently not supported");
   endif
 
   if (! isfield (options, "imageFormat"))
@@ -284,22 +286,21 @@
   elseif (! ischar (options.imageFormat))
     error ("publish: IMAGEFORMAT must be a string");
   else
-    ## check valid imageFormat for chosen format
+    ## 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"});
+        options.imageFormat = validatestring (options.imageFormat,
+                                              {"png", "jpg", "bmp", "tiff"});
       case "pdf"
-        options.imageFormat = validatestring (options.imageFormat, ...
-          {"bmp", "jpg"});
+        options.imageFormat = validatestring (options.imageFormat,
+                                              {"bmp", "jpg"});
     endswitch
   endif
 
   if (! isfield (options, "maxHeight"))
     options.maxHeight = [];
-  elseif ((! isscalar (options.maxHeight)) ...
-          || (uint64 (options.maxHeight) == 0))
+  elseif (! isscalar (options.maxHeight) || options.maxHeight < 1)
     error ("publish: MAXHEIGHT must be a positive integer");
   else
     options.maxHeight = uint64 (options.maxHeight);
@@ -307,8 +308,7 @@
 
   if (! isfield (options, "maxWidth"))
     options.maxWidth = [];
-  elseif ((! isscalar (options.maxWidth)) ...
-          || (uint64 (options.maxWidth) == 0))
+  elseif (! isscalar (options.maxWidth) || options.maxWidth < 1)
     error ("publish: MAXWIDTH must be a positive integer");
   else
     options.maxWidth = uint64 (options.maxWidth);
@@ -316,24 +316,24 @@
 
   if (! isfield (options, "useNewFigure"))
     options.useNewFigure = true;
-  elseif (! isbool (options.useNewFigure))
+  elseif (! isscalar (options.useNewFigure) || ! isreal (options.useNewFigure))
     error ("publish: USENEWFIGURE must be TRUE or FALSE");
   endif
 
   ## Options for the code
-  if (!isfield (options, "evalCode"))
+  if (! isfield (options, "evalCode"))
     options.evalCode = true;
-  elseif ((! isscalar (options.evalCode)) || (! isbool (options.evalCode)))
+  elseif (! isscalar (options.evalCode) || ! isreal (options.evalCode))
     error ("publish: EVALCODE must be TRUE or FALSE");
   endif
 
-  if (!isfield (options, "catchError"))
+  if (! isfield (options, "catchError"))
     options.catchError = true;
-  elseif ((! isscalar (options.catchError)) || (! isbool (options.catchError)))
+  elseif (! isscalar (options.catchError) || ! isreal (options.catchError))
     error ("publish: CATCHERROR must be TRUE or FALSE");
   endif
 
-  if (!isfield (options, "codeToEvaluate"))
+  if (! isfield (options, "codeToEvaluate"))
     options.codeToEvaluate = "";
   elseif (! ischar (options.codeToEvaluate))
     error ("publish: CODETOEVALUTE must be a string");
@@ -341,48 +341,48 @@
 
   if (! isfield (options, "maxOutputLines"))
     options.maxOutputLines = Inf;
-  elseif (! isscalar (options.maxOutputLines))
+  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"))
+  if (! isfield (options, "showCode"))
     options.showCode = true;
-  elseif ((! isscalar (options.showCode)) || (! isbool (options.showCode)))
+  elseif (! isscalar (options.showCode) || ! isreal (options.showCode))
     error ("publish: SHOWCODE must be TRUE or FALSE");
   endif
 
-  doc_struct.title = "";
-  doc_struct.intro = "";
-  doc_struct.body = cell ();
-  doc_struct.m_source = deblank (read_file_to_cellstr (file));
-  doc_struct.m_source_file_name = file;
+  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_struct = parse_m_source (doc_struct);
+  doc = parse_m_source (doc);
 
   ## Create output directory
-  [mkdir_stat, mkdir_msg] = mkdir (options.outputDir);
-  if (mkdir_stat != 1)
-    error ("publish: cannot create output directory. %s", mkdir_msg);
+  [status, msg] = mkdir (options.outputDir);
+  if (status != 1)
+    error ("publish: cannot create output directory: %s", msg);
   endif
 
   if (options.evalCode)
-    doc_struct = eval_code (doc_struct, options);
+    doc = eval_code (doc, options);
   endif
 
-  output_file = create_output (doc_struct, options);
+  output_file = create_output (doc, options);
+
 endfunction
 
 
-
-function doc_struct = parse_m_source (doc_struct)
+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_struct.m_source.
+  ##   sections) given in doc.m_source.
   ##
-  ##   The result is written to doc_struct.body, which then contains a cell
+  ##   The result is written to doc.body, which then contains a cell
   ##   vector of structs, either of
   ##
   ##     a) {struct ("type", "code", ...
@@ -392,12 +392,10 @@
   ##                 "content", title_str)}
   ##
   ##   Second parsing level is invoked for the paragraph contents, resulting
-  ##   in more elements for doc_struct.body.
-  ##
+  ##   in more elements for doc.body.
 
-  ## If there is nothing to parse
-  if (isempty (doc_struct.m_source))
-    return;
+  if (isempty (doc.m_source))
+    return;  # Nothing to parse
   endif
 
   ## Parsing helper functions
@@ -416,31 +414,29 @@
   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_struct.m_source) ...
-    | cellfun (is_no_break_head, doc_struct.m_source));
+  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_struct.body{end + 1}.type = "code";
-    doc_struct.body{end}.content = strtrim (strjoin (...
-      doc_struct.m_source(1:length(doc_struct.m_source)), "\n"));
-    doc_struct.body{end}.lines = [1, length(doc_struct.m_source)];
-    doc_struct.body{end}.output = {};
+    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_struct.m_source)];
-  for i = 1:length(par_end_idx)
-    idx = find (! cellfun (is_paragraph, ...
-                    doc_struct.m_source(par_start_idx(i) + 1:par_end_idx(i))));
+  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_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)
@@ -448,9 +444,9 @@
     code_end_idx = [par_start_idx(1) - 1, code_end_idx];
   endif
   ## Code at the end?
-  if (par_end_idx(end) < length (doc_struct.m_source))
+  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_struct.m_source)];
+    code_end_idx = [code_end_idx, length(doc.m_source)];
   endif
   ## Remove overlaps
   idx = code_start_idx > code_end_idx;
@@ -458,9 +454,9 @@
   code_end_idx(idx) = [];
   ## Remove empty code blocks
   idx = [];
-  for i = 1:length(code_start_idx)
-    if (all (cellfun (@(cstr) isempty (char (cstr)), ...
-                      doc_struct.m_source(code_start_idx(i):code_end_idx(i)))))
+  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
@@ -471,70 +467,70 @@
   ##   1. First paragraph must start in first line
   ##   2. Second paragraph must start before any code
   title_offset = 0;
-  if ((is_head (doc_struct.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_struct.title = doc_struct.m_source{1};
-    doc_struct.title = doc_struct.title(4:end);
-    content = doc_struct.m_source(2:par_end_idx(1));
+  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_struct.intro = parse_paragraph_content (content);
+    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_struct
+  ## Add non-empty paragraphs and code to doc
   j = 1;
   i = (1 + title_offset);
-  while ((i <= length(par_start_idx)) || (j <= length(code_start_idx)))
+  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 <= length(code_start_idx))
-           && ((i > length(par_start_idx))
-               || (par_start_idx(i) > code_start_idx(j))))
-      doc_struct.body{end + 1}.type = "code";
+    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_struct.body{end}.content = strtrim (strjoin (...
-        doc_struct.m_source(lines(1):lines(2)), "\n"));
-      doc_struct.body{end}.lines = lines;
-      doc_struct.body{end}.output = {};
+      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 <= length(par_start_idx))
+    if (i <= numel (par_start_idx))
       type_str = "section";
-      title_str = doc_struct.m_source{par_start_idx(i)};
-      if (is_head (doc_struct.m_source(par_start_idx(i))))
+      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_struct.body{end + 1}.type = type_str;
-        doc_struct.body{end}.content = title_str;
+        doc.body{end+1}.type = type_str;
+        doc.body{end}.content = title_str;
       endif
 
-      content = doc_struct.m_source(par_start_idx(i) + 1:par_end_idx(i));
+      content = doc.m_source(par_start_idx(i) + 1:par_end_idx(i));
       ## Strip leading "# "
-      content = cellfun(@(c) cellstr (c(3:end)), content);
-      doc_struct.body = [doc_struct.body, parse_paragraph_content(content)];
+      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)
+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_struct.body, either of
+  ##   returns a cell vector of structs, that can be appended to doc.body,
+  ##   either of
   ##
   ##     a) {struct ("type", "preformatted_code", ...
   ##                 "content", code_str)}
@@ -561,7 +557,6 @@
   ##     * Inline "$" and block "$$" LaTeX math
   ##     * Links
   ##     * Trademark symbols
-  ##
 
   p_content = cell ();
 
@@ -569,16 +564,16 @@
     return;
   endif
 
-  ## Split into blocks seperated by empty lines
+  ## 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)
+  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);
+      block = cellfun (@(c) cellstr (c(3:end)), block);
       p_content{end}.content = strjoin (block, "\n");
       continue;
     endif
@@ -586,7 +581,7 @@
     ## 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);
+      block = cellfun (@(c) cellstr (c(2:end)), block);
       p_content{end}.content = strjoin (block, "\n");
       continue;
     endif
@@ -594,28 +589,29 @@
     ## Bulleted list starts with "* "
     if (strncmp (block{1}, "* ", 2))
       p_content{end+1}.type = "bulleted_list";
-      p_content{end}.content = strjoin (block, "\n");
+      tmpstr = strjoin (block, "\n");
       ## Revove first "* "
-      p_content{end}.content = p_content{end}.content(3:end);
+      tmpstr = tmpstr(3:end);
       ## Split items
-      p_content{end}.content = strsplit (p_content{end}.content, "\n* ");
+      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";
-      p_content{end}.content = strjoin (block, "\n");
+      tmpstr = strjoin (block, "\n");
       ## Revove first "# "
-      p_content{end}.content = p_content{end}.content(3:end);
+      tmpstr = tmpstr(3:end);
       ## Split items
-      p_content{end}.content = strsplit (p_content{end}.content, "\n# ");
+      p_content{end}.content = strsplit (tmpstr, "\n# ");
       continue;
     endif
 
     ## Include <include>fname.m</include>
-    if (! isempty ([~,~,~,~,fname] = regexpi (strjoin (block, ""), ...
-                                              '^<include>(.*)<\/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}));
@@ -625,8 +621,9 @@
     endif
 
     ## Graphic <<myGraphic.png>>
-    if (! isempty ([~,~,~,~,fname] = regexpi (strjoin (block, ""), ...
-                                              '^<<(.*)>>$')))
+    if (! isempty (fname = regexpi (strjoin (block, ""),
+                                    '^<<(.*)>>$',
+                                    "tokens")))
       p_content{end+1}.type = "graphic";
       p_content{end}.content = strtrim ((fname{1}){1});
       continue;
@@ -634,14 +631,14 @@
 
     ## Parse remaining blocks line by line
     j = 1;
-    while (j <= length(block))
+    while (j <= numel (block))
       ## HTML markup
       if (strcmpi (block{j}, "<html>"))
         start_html = j + 1;
-        while ((j < length(block)) && ! strcmpi (block{j}, "</html>"))
+        while (j < numel (block) && ! strcmpi (block{j}, "</html>"))
           j++;
         endwhile
-        if ((j == length(block)) && ! strcmpi (block{j}, "</html>"))
+        if (j == numel (block) && ! strcmpi (block{j}, "</html>"))
           warning ("publish: no closing </html> found");
         else
           j++;  ## Skip closing tag
@@ -653,13 +650,13 @@
       ## LaTeX markup
       elseif (strcmpi (block{j}, "<latex>"))
         start_latex = j + 1;
-        while ((j < length(block)) && ! strcmpi (block{j}, "</latex>"))
+        while (j < numel (block) && ! strcmpi (block{j}, "</latex>"))
           j++;
         endwhile
-        if ((j == length(block)) && ! strcmpi (block{j}, "</latex>"))
+        if (j == numel (block) && ! strcmpi (block{j}, "</latex>"))
           warning ("publish: no closing </latex> found");
         else
-          j++;  ## Skrip closing tag
+          j++;  ## Skip closing tag
         endif
         if (j > start_latex)
           p_content{end+1}.type = "latex";
@@ -672,9 +669,8 @@
       ## * Inline "$" and block "$$" LaTeX math
       ## * Links
       ## * Trademark symbols
-      ##
       else
-        if ((j == 1) || isempty (p_content) ...
+        if (j == 1 || isempty (p_content)
             || ! strcmp (p_content{end}.type, "text"))
           p_content{end+1}.type = "text";
           p_content{end}.content = block{j};
@@ -689,25 +685,21 @@
 endfunction
 
 
-
 function m_source = read_file_to_cellstr (file)
   ## READ_FILE_TO_CELLSTR reads a given file line by line to a cellstring
+
   fid = fopen (file, "r");
-  i = 1;
-  m_source{i} = fgetl (fid);
-  while (ischar (m_source{i}))
-    i++;
-    m_source{i} = fgetl (fid);
-  endwhile
-  fclose(fid);
-  m_source = cellstr (m_source(1:end-1)); ## No EOL
+  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_struct, options)
+function ofile = create_output (doc, options)
   ## CREATE_OUTPUT creates the desired output file
-  ##
 
   formatter = [];
   ofile_ext = "";
@@ -720,31 +712,32 @@
       ofile_ext = ".tex";
   endswitch
 
-  ## Use title, or if not given the m-file name
-  title_str = doc_struct.title;
+  ## Use title, or if not given, the m-file name
+  title_str = doc.title;
   if (isempty (title_str))
-    [~,title_str] = fileparts (doc_struct.m_source_file_name);
+    [~, title_str] = fileparts (doc.m_source_file_name);
   endif
 
-  content = formatter ("header", title_str, ...
-    format_output (doc_struct.intro, formatter, options), ...
-    get_toc (doc_struct.body, formatter));
-  content = [content, format_output(doc_struct.body, formatter, options)];
-  content = [content, formatter("footer", strjoin (doc_struct.m_source, "\n"))];
+  content = formatter ("header", 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_struct.m_source_file_name);
+  [~, ofile] = fileparts (doc.m_source_file_name);
   ofile_name = [ofile, ofile_ext];
-  ofile = [options.outputDir, filesep(), ofile_name];
+  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");
+    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
@@ -752,33 +745,29 @@
 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.
 
-function toc_cstr = get_toc (cstr, formatter)
-  ## GET_TOC extracts the table of contents from a cellstring (e.g.
-  ##   doc_struct.body) with each section headline as a cell in a returned
-  ##   cellstring.
-  ##
   toc_cstr = cell ();
-  for i = 1:length(cstr)
+  for i = 1:numel (cstr)
     if (strcmp (cstr{i}.type, "section"))
-      toc_cstr{end + 1} = format_text (cstr{i}.content, formatter);
+      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_struct.intro or
-  ##   doc_struct.body) in cstr and produces a single result string
-  ##   with the source code in the desired output format.
+  ## 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 knowlegde how to enforce the target 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:length(cstr)
+  for i = 1:numel (cstr)
     switch (cstr{i}.type)
       case "code"
         if (options.showCode)
@@ -789,23 +778,22 @@
         endif
       case {"text", "section"}
         str = [str, formatter(cstr{i}.type, ...
-          format_text (cstr{i}.content, formatter))];
+                              format_text (cstr{i}.content, formatter))];
       case {"bulleted_list", "numbered_list"}
         items = cellfun (@(str) format_text(str, formatter), ...
-          cstr{i}.content, "UniformOutput", false);
+                         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, bold, italic, monospaced, (TM), (R)
-  ##
 
   ## Regular expressions for the formats:
   ##
@@ -813,7 +801,6 @@
   ## * Links "<octave:Function TEXT>"
   ## * Links "<http://www.someurl.com TEXT>"
   ## * inline "$" and block "$$" LaTeX math
-  ##
   regexes = {'<\S{3,}[^\s<>]*>', ...
              '<octave:[^\s<>]* *[^<>$]*>', ...
              '<\S{3,}[^\s<>]* *[^<>$]*>', ...
@@ -821,28 +808,27 @@
              '\*[^*]*\*', ...  # Bold
              '_[^_]*_', ...    # Italic
              '\|[^|]*\|'};     # Monospaced
-             
 
-  ##  Helper 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
+  ## 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 occurances with placeholders
+  ## Substitute all occurrences with placeholders
   placeholder_cstr = {};
   plh = 0;
-  for i = 1:length(regexes)
-    [~,~,~,cstr] = regexp (str, regexes{i});
-    for j = 1:length(cstr)
-      plh = plh + 1;
-      str = regexprep (str, regexes{i}, ...
-        ["PUBLISHPLACEHOLDER", num2str(plh)], "once");
+  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>"
+          ## 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>"
+          ## Links "<octave:Function TEXT>"
           idx = strfind (cstr{j}, " ");
           url = cstr{j};
           url = ["https://www.gnu.org/software/octave/doc/interpreter/", ...
@@ -851,7 +837,7 @@
           txt = format_text (txt(idx+1:end-1), formatter);
           cstr{j} = formatter ("link", url, txt);
         case 3
-          # Links "<http://www.someurl.com TEXT>"
+          ## Links "<http://www.someurl.com TEXT>"
           idx = strfind (cstr{j}, " ");
           url = cstr{j};
           url = url(2:idx-1);
@@ -859,51 +845,50 @@
           txt = format_text (txt(idx+1:end-1), formatter);
           cstr{j} = formatter ("link", url, txt);
         case 4
-          # inline "$" and block "$$" LaTeX math --> do nothing
+          ## inline "$" and block "$$" LaTeX math --> do nothing
         case 5
-          # Bold
+          ## Bold
           txt = cstr{j};
           cstr{j} = formatter ("bold", format_text (txt(2:end-1), formatter));
         case 6
-          # Italic
+          ## Italic
           txt = cstr{j};
           cstr{j} = formatter ("italic", format_text (txt(2:end-1), formatter));
         case 7
-          # Monospaced
+          ## Monospaced
           txt = cstr{j};
           cstr{j} = formatter ("monospaced", format_text (txt(2:end-1), ...
-            formatter));
+                               formatter));
       endswitch
     endfor
     placeholder_cstr = [placeholder_cstr, cstr];
   endfor
 
   ## Replace special symbols
-  str = strrep (str, "(TM)", formatter("TM"));
-  str = strrep (str, "(R)", formatter("R"));
+  str = strrep (str, "(TM)", formatter ("TM"));
+  str = strrep (str, "(R)", formatter ("R"));
 
   ## Restore placeholders
   for i = plh:-1:1
-    str = strrep (str, ["PUBLISHPLACEHOLDER", num2str(i)], ...
-      placeholder_cstr{i});
+    str = strrep (str, ["PUBLISHPLACEHOLDER" sprintf("%d", i)],
+                       placeholder_cstr{i});
   endfor
+
 endfunction
 
 
-
-function doc_struct = eval_code (doc_struct, options)
-  ## EVAL_CODE Thrid level parsing
+function doc = eval_code (doc, options)
+  ## EVAL_CODE Third level parsing
   ##
   ##   Generates the output of the script code and takes care of generated
   ##   figures.
-  ##
 
-  ## Neccessary as the code does not run interactively
-  page_screen_output (0, "local");
+  ## 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_struct.m_source_file_name);
+  [~, fig_name] = fileparts (doc.m_source_file_name);
   fig_num = 1;
   fig_list = struct ();
 
@@ -918,44 +903,44 @@
     figure ();
   endif
 
-  for i = 1:length(doc_struct.body)
-    if (strcmp (doc_struct.body{i}.type, "code"))
-      r = doc_struct.body{i}.lines;
-      code_str = strjoin (doc_struct.m_source(r(1):r(2)), "\n");
+  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_struct.body{i}.output = eval_code_helper (tmp_context, code_str);
+          doc.body{i}.output = eval_code_helper (tmp_context, code_str);
          catch err
-          doc_struct.body{i}.output = cellstr (["error: ", err.message, ...
-            "\n\tin:\n\n", code_str]);
+          doc.body{i}.output = cellstr (["error: ", err.message, ...
+                                                "\n\tin:\n\n", code_str]);
         end_try_catch
       else
-        doc_struct.body{i}.output = eval_code_helper (tmp_context, code_str);
+        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:length(fig_ids_new)
+      for j = 1:numel (fig_ids_new)
         drawnow ();
         if (isempty (get (fig_ids_new(j), "children")))
           continue;
         endif
-        fname = [fig_name, "-", num2str(fig_num), "."];
+        fname = [fig_name, "-", sprintf("%d", fig_num)];
         if (strncmp (options.imageFormat, "eps", 3))
-          fname = [fname, "eps"];
+          fname = [fname ".eps"];
         else
-          fname = [fname, options.imageFormat];
+          fname = [fname "." options.imageFormat];
         endif
         print_opts = {fig_ids_new(j), ...
-          [options.outputDir, filesep(), fname], ...
-          ["-d", options.imageFormat], "-color"};
+                      fullfile(options.outputDir, fname), ...
+                      ["-d" options.imageFormat], "-color"};
         if (! isempty (options.maxWidth) && ! isempty (options.maxHeight))
-          print_opts{end + 1} = ["-S", num2str(options.maxWidth), ...
-            num2str(options.maxHeight)];
+          print_opts{end+1} = sprintf("-S%d,%d", options.maxWidth,
+                                                 options.maxHeight);
         elseif (! isempty (options.maxWidth) || ! isempty (options.maxWidth))
           warning (["publish: specify both options.maxWidth ", ...
-            "and options.maxWidth"]);
+                              "and options.maxWidth"]);
         endif
         print (print_opts{:});
         fig_num++;
@@ -963,26 +948,25 @@
         fig_elem = cell ();
         fig_elem{1} = struct ("type", "graphic", "content", fname);
         if (isfield (fig_list, num2str (i)))
-          fig_elem = [getfield(fig_list, num2str (i)), fig_elem];
+          fig_elem = [getfield(fig_list, sprintf ("%d", i)), fig_elem];
         endif
-        fig_list = setfield (fig_list, num2str (i), fig_elem);
+        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)
+            && ! isempty (fig_ids) && options.useNewFigure)
           figure ();
         endif
       endfor
 
       ## Truncate output to desired length
-      if (options.maxOutputLines < length (doc_struct.body{i}.output))
-        doc_struct.body{i}.output = ...
-          doc_struct.body{i}.output(1:options.maxOutputLines);
+      if (options.maxOutputLines < length (doc.body{i}.output))
+        doc.body{i}.output = doc.body{i}.output(1:options.maxOutputLines);
       endif
-      doc_struct.body{i}.output = strjoin (doc_struct.body{i}.output, "\n");
+      doc.body{i}.output = strjoin (doc.body{i}.output, "\n");
     endif
   endfor
 
-  ## Close any by publish opened figures
+  ## Close any figures opened by publish function
   delete (setdiff (findall (0, "type", "figure"), fig_ids));
 
   ## Remove temporary context
@@ -991,23 +975,23 @@
   ## Insert figures to document
   fig_code_blocks = fieldnames (fig_list);
   body_offset = 0;
-  for i = 1:length(fig_code_blocks)
+  for i = 1:numel (fig_code_blocks)
     elems = getfield (fig_list, fig_code_blocks{i});
-    ## Compute index, where the figure(s) has to be inserterd
-    j = str2num (fig_code_blocks{i}) + body_offset;
-    doc_struct.body = [doc_struct.body(1:j), elems, doc_struct.body(j+1:end)];
-    body_offset = body_offset + length (elems);
+    ## 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
+  ##   temporary context and returns a cellstring with the eval output.
 
-  ## TODO: potential conflicting variables sourrounded by "___".  Maybe there
-  ##       is a better solution.
+  ## FIXME: Potential conflicting variables surrounded by "___".
+  ##        Maybe there is a better solution?
   if (isempty (___code___))
     return;
   endif
@@ -1018,17 +1002,18 @@
 
   ___cstr___ = strsplit (evalc (___code___), "\n");
 
-  clear ___code___
+  clear ___code___;
   save (___context___);
 endfunction
 
 
+## FIXME: Missing any functional BIST tests
 
-## Bad function calls
-
+## Test input validation
 %!error publish ()
 %!error publish (1)
 %!error publish ("non_existing_file.m")
 %!error<Only Octave script files can be published> publish ("publish.m")
 %!error publish ("test_script.m", "format", "html", "showCode")
 %!error [str1, str2] = publish ("test_script.m")
+