changeset 24942:f0a427d09dba stable

Use Perl to generate Qt help files to minimize external dependencies (bug #53371). * doc/interpreter/mk_qthelp.pl: New file. * module.mk: Add mk_qthelp.pl to build system. Use it in rules to generate $OCTAVE_QTHELP_FILES.
author Rik <rik@octave.org>
date Wed, 21 Mar 2018 10:17:23 -0700
parents 7edf1fb1d4b2
children 23b5c0678051
files doc/interpreter/mk_qthelp.pl doc/interpreter/module.mk
diffstat 2 files changed, 199 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/interpreter/mk_qthelp.pl	Wed Mar 21 10:17:23 2018 -0700
@@ -0,0 +1,196 @@
+#!/usr/bin/env perl
+
+################################################################################
+# File    : mk_qthelp.pl
+# Purpose : Transform Octave HTML documentation into intermediate formats
+#           for Qt Help Project (.qhp) and Qt Help Collection Project (.qhcp).
+# Usage   : mk_qthelp.pl input_htmldir output_filename 
+################################################################################
+use warnings;              # report warnings for questionable run-time code
+use strict qw(refs subs);  # check at compile-time for bad programming style
+use autodie;               # issue an error and exit if any system call fails
+use File::Basename;        # For splitting paths between dir and file
+use File::Spec;            # For combining dirs and filenames into paths
+
+################################################################################
+# Extract command line arguments
+if ($#ARGV != 1)
+{ die "USAGE: %0 input_htmldir output_filename"; } 
+
+$htmldir = basename ($ARGV[0]);
+$basedir = File::Spec->rel2abs (dirname ($ARGV[1]));
+$fname   = File::Spec->catfile ($basedir, basename ($ARGV[1]));
+
+################################################################################
+# Parse index.html to retrieve the table of contents
+$htmlfname = File::Spec->catfile ($basedir, $htmldir, "index.html");
+open (my $HTML, "<", $htmlfname) or die "Unable to open $htmlfname";
+
+# Skip through preamble of file to find start of list
+while (($_ = <$HTML>) !~ /^<div class="contents">/ ) {;}
+while (($_ = <$HTML>) !~ /^<ul class="no-bullet">/ ) {;}
+
+$level = 0;
+while (<$HTML>)
+{
+  if (/^\s*<li>/)
+  {
+    ($href, $text) = m|href="([^"]*)">(.*)</a>|;
+    # Sanitize text
+    $text =~ s/<[^>]*>//g;         # remove xml-looking blocks like <code>
+    $text =~ s/&rsquo;/&#8217;/g;  # Code for apostrophe 
+
+    push (@toc, { "href" => $href, "text" => $text,
+                  "level" => $level, "sectionstart" => 0 }); 
+  }
+  elsif (/^\s+<ul /)
+  {
+    $level++;
+    # Get last node and amend it to have a section start
+    %node = %{ $toc[-1] };
+    $node{sectionstart} = 1;
+    $toc[-1] = { %node };
+  }
+  elsif (m|^\s+</ul>|)
+  {  $level--; }
+  elsif (m|^</ul>$|)
+  {  last;  }
+  else
+  {  die "error:unrecognized input:$htmlfname:$.:$_"; }
+}
+
+close ($HTML);
+
+die "Failed to parse index.html" if ($level != 0);
+
+################################################################################
+# Parse Function-Index.html to retrieve the function reference
+$htmlfname = File::Spec->catfile ($basedir, $htmldir, "Function-Index.html");
+open ($HTML, "<", $htmlfname) or die "Unable to open $htmlfname";
+
+# Skip through preamble of file to find start of list
+while (($_ = <$HTML>) !~ /^<table class="index-fn/ ) {;}
+
+while (<$HTML>)
+{
+  if (m|<a href="([^"]*)"><code>(.*)</code>|)
+  {
+    $href = $1, $name = $2;
+    # Keep only the first link for each entry
+    if (! $kword{$name})
+    { $kword{$name} = $href; }
+  }
+  elsif (m|^</table>$|)
+  { last; }
+}
+
+close ($HTML);
+
+die "Failed to parse Function-Index.html" if (! m|^</table>$|);
+
+################################################################################
+# Prepare Qt Help Project document (.qhp file)
+open (my $FH, ">", "$fname.qhp") or die "Unable to open $fname.qhcp";
+
+$htmlfname = File::Spec->catfile ($htmldir, "index.html");
+
+# Add header to file
+print $FH <<__EOT1__;
+<?xml version="1.0" encoding="UTF-8"?>
+<!--DO NOT EDIT!  Generated automatically by $0-->
+<QtHelpProject version="1.0">
+  <namespace>org.octave.interpreter-1.0</namespace>
+  <virtualFolder>doc</virtualFolder>
+  <customFilter name="Octave Manual">
+    <filterAttribute>core</filterAttribute>
+    <filterAttribute>manual</filterAttribute>
+  </customFilter>
+  <customFilter name="Octave C++ API">
+    <filterAttribute>core</filterAttribute>
+    <filterAttribute>cpp</filterAttribute>
+  </customFilter>
+  <filterSection>
+    <filterAttribute>core</filterAttribute>
+    <filterAttribute>manual</filterAttribute>
+    <toc>
+      <section title="GNU Octave Manual" ref="$htmlfname">
+__EOT1__
+
+# Print out an XML block for each TOC section
+$level = 0;
+$indent = 4;
+foreach $hashref (@toc)
+{
+  %node = %{$hashref};
+  while ($node{level} < $level)
+  {
+    # Unindent and close section
+    $level--;    
+    print $FH "  " x ($indent + $level);
+    print $FH "</section>\n";
+  }
+  $level = $node{level};
+
+  print $FH "  " x ($indent + $node{level});
+  print $FH qq|<section title="$node{text}" |;
+  print $FH qq|ref="|, File::Spec->catfile ($htmldir, $node{href});
+  print $FH ($node{sectionstart} ? qq|">\n| : qq|"/>\n|);
+}
+
+# Spacer between TOC and Keywords
+print $FH <<__EOT2__;
+      </section>
+    </toc>
+    <keywords>
+__EOT2__
+
+# Print out sorted keywords
+foreach $kw (sort {lc($a) cmp lc($b)} (keys (%kword)))
+{
+  print $FH qq|      <keyword name="$kw" id="$kw" |;
+  print $FH qq|ref="|, File::Spec->catfile ($htmldir, $kword{$kw}), qq|"/>\n|;
+}
+
+# Footer of file
+$htmlfiles = File::Spec->catfile ($htmldir, "*.html");
+$pngfiles = File::Spec->catfile ($htmldir, "*.png");
+$cssfiles = File::Spec->catfile ($htmldir, "*.css");
+print $FH <<__EOT3__;
+    </keywords>
+    <files>
+      <file>$htmlfiles</file>
+      <file>$pngfiles</file>
+      <file>$cssfiles</file>
+    </files>
+  </filterSection>
+</QtHelpProject>
+__EOT3__
+
+close ($FH);
+
+################################################################################
+# Prepare Qt Help Collection Project document (.qhcp file)
+open ($FH, ">", "$fname.qhcp") or die "Unable to open $fname.qhcp";
+
+$qhpfile = "$fname.qhp";
+$qchfile = "$fname.qch";
+
+# This is the entire file
+print $FH <<__EOT4__;
+<?xml version="1.0" encoding="UTF-8"?>
+<!--DO NOT EDIT! Generated automatically by $0-->
+<QHelpCollectionProject version="1.0">
+  <docFiles>
+    <generate>
+      <file>
+        <input>$qhpfile</input>
+        <output>$qchfile</output>
+      </file>
+    </generate>
+    <register>
+      <file>$qchfile</file>
+    </register>
+  </docFiles>
+</QHelpCollectionProject>
+__EOT4__
+
--- a/doc/interpreter/module.mk	Wed Mar 21 16:24:35 2018 +0100
+++ b/doc/interpreter/module.mk	Wed Mar 21 10:17:23 2018 -0700
@@ -202,9 +202,9 @@
 %reldir%/octave.pdf: $(DOC_IMAGES_PDF) $(octave_TEXINFOS)
 $(OCTAVE_HTML_STAMP): $(DOC_IMAGES_PNG) $(octave_TEXINFOS)
 
-$(OCTAVE_QTHELP_FILES): $(OCTAVE_HTML_STAMP) $(srcdir)/%reldir%/prepare_qhelp.py
+$(OCTAVE_QTHELP_FILES): $(OCTAVE_HTML_STAMP) $(srcdir)/%reldir%/mk_qthelp.pl
 	$(AM_V_GEN)rm -f $(OCTAVE_QTHELP_FILES) && \
-	$(PYTHON) $(srcdir)/%reldir%/prepare_qhelp.py %reldir%/octave_interpreter octave.html && \
+	$(PERL) $(srcdir)/%reldir%/mk_qthelp.pl octave.html %reldir%/octave_interpreter && \
 	$(QCOLLECTIONGENERATOR) $(QCOLLECTIONGENERATORFLAGS) %reldir%/octave_interpreter.qhcp -o %reldir%/octave_interpreter.qhc >/dev/null && \
 	rm -f %reldir%/octave_interpreter.qhcp %reldir%/octave_interpreter.qhp
 
@@ -352,6 +352,7 @@
   %reldir%/images.mk \
   %reldir%/macros.texi \
   %reldir%/mk-doc-cache.pl \
+  %reldir%/mk_qthelp.pl \
   %reldir%/mkcontrib.awk \
   %reldir%/munge-texi.pl \
   %reldir%/prepare_qhelp.py \