X-Git-Url: https://git.exim.org/exim-website.git/blobdiff_plain/9d0f50e12e32b7cf6732e7f2924f3ce290933e43..79096558caa37b1acc6af77f5e4c67720ea25662:/script/gen diff --git a/script/gen b/script/gen index dfb174e..58e399e 100755 --- a/script/gen +++ b/script/gen @@ -15,6 +15,7 @@ use JavaScript::Minifier::XS; use Pod::Usage; use XML::LibXML; use XML::LibXSLT; +use FindBin qw'$Bin'; my $canonical_url = 'https://www.exim.org/'; @@ -130,11 +131,21 @@ sub do_doc { my ( $type, $xml_path ) = @_; ## Read and validate the XML file - my $xml = XML::LibXML->new()->parse_file($xml_path) or die $!; + my $xml = XML::LibXML->new(expand_entities => 1)->parse_file($xml_path) or die $!; ## Get the version number - my $version = $xml->findvalue('/book/bookinfo/revhistory/revision/revnumber'); - die "Unable to get version number\n" unless defined $version && $version =~ /^\d+(\.\d+)*$/; + my $version = do { + my $version = $xml->findvalue('/book/bookinfo/revhistory/revision/revnumber'); + die "Unable to get version number\n" + unless defined $version and $version =~ /^ + (? + \d+ # major + (?:\.\d+(?:\.\d+)?)? # (minor(.patch)) + (?:\.\d+(?:\.\d+(?:\.\d+)?)?)? # (minor(.patch.(fixes))) + ) + (?:-RC\d+)?$/x; # -RCX + $+{version}; + }; ## Prepend chapter filenames? my $prepend_chapter = $type eq 'filter' ? 'filter_' : ''; @@ -276,6 +287,7 @@ sub xref_fixup { my $section_counter = 0; foreach my $section ( $chapter->findnodes('section') ) { ++$section_counter; + $section->setAttribute( 'sectprefix', $section_counter ); my $section_id = $section->getAttribute('id'); unless ($section_id) { # synthesise missing id @@ -290,6 +302,31 @@ sub xref_fixup { section_id => $section_counter, section_title => $section_title }; + + # 2022/07/07 jgh: added loop for sections under sections, which are resulting from the .subsection macro + # Add a "level" attribute to these nodes + ## Iterate over each subsection + my $subsec_counter = 0; + foreach my $subsection ( $section->findnodes('section') ) { + ++$subsec_counter; + + $subsection->setAttribute( 'level', "2" ); + $subsection->setAttribute( 'sectprefix', sprintf("%d.%d", $section_counter, $subsec_counter) ); + + my $subsec_id = $subsection->getAttribute('id'); + unless ($subsec_id) { # synthesise missing id + $subsec_id = sprintf( 'section_noid_%04d_%04d_%04d', $chapter_counter, $section_counter, $subsec_counter ); + $subsection->setAttribute( 'id', $subsec_id ); + } + my $subsec_title = $subsection->findvalue('title'); + + $index{$subsec_id} = { + chapter_id => $chapter_counter, + chapter_title => $chapter_title, + section_id => $subsec_counter, + section_title => $subsec_title + }; + } } } ## Build indexes as new chapters @@ -298,10 +335,11 @@ sub xref_fixup { ## Replace all of the xrefs in the XML foreach my $xref ( $xml->findnodes('//xref') ) { my $linkend = $xref->getAttribute('linkend'); + if ( exists $index{$linkend} ) { - $xref->setAttribute( 'chapter_id', $index{$linkend}{'chapter_id'} ); + $xref->setAttribute( 'chapter_id', $index{$linkend}{'chapter_id'} ) if ( $index{$linkend}{'chapter_id'} ); $xref->setAttribute( 'chapter_title', $index{$linkend}{'chapter_title'} ); - $xref->setAttribute( 'section_id', $index{$linkend}{'section_id'} ) if ( $index{$linkend}{'section_id'} ); + $xref->setAttribute( 'section_id', $index{$linkend}{'section_id'} ) if ( $index{$linkend}{'section_id'} ); $xref->setAttribute( 'section_title', $index{$linkend}{'section_title'} ) if ( $index{$linkend}{'section_title'} ); $xref->setAttribute( 'url', @@ -317,17 +355,73 @@ sub build_indexes { my ( $xml, $prepend_chapter, $xref ) = @_; my $index_hash = {}; + my $seealso_hash = {}; my $current_id; - foreach my $node ( $xml->findnodes('//section | //chapter | //indexterm') ) { + my $verterm_counter = 0; + + foreach my $node ( $xml->findnodes('//section | //chapter | //varlistentry | //indexterm') ) { if ( $node->nodeName eq 'indexterm' ) { my $role = $node->getAttribute('role') || 'concept'; my $primary = $node->findvalue('child::primary'); my $first = ( $primary =~ /^[A-Za-z]/ ) ? uc( substr( $primary, 0, 1 ) ) : ''; # first letter or marker my $secondary = $node->findvalue('child::secondary') || ''; + my $see = $node->findvalue('child::see'); + my $see_also = $node->findvalue('child::seealso'); + next unless ( $primary || $secondary ); # skip blank entries for now... + $index_hash->{$role}{$first}{$primary}{$secondary} ||= []; - push @{ $index_hash->{$role}{$first}{$primary}{$secondary} }, $current_id; + if ( $see || $see_also ) { + # The scalar value being written here assumes only one seealso on an indeed term + # It would be nice to have the $see displayed in bold rather than in quotes + $seealso_hash->{$role}{$first}{$primary}{$secondary} = 'see "' . $see .'"' if ($see); + $seealso_hash->{$role}{$first}{$primary}{$secondary} = 'see also "' . $see_also .'"' if ($see_also); + } + + else { + push @{ $index_hash->{$role}{$first}{$primary}{$secondary} }, $current_id; + } } + elsif ( $node->nodeName eq 'varlistentry' ) { + + foreach my $vitem ( $node->findnodes('listitem') ) { + + # Add an anchorname xml attribute. + # chapter.xsl spots this and places a " " + + my $anchorname = sprintf("vi%d", $verterm_counter++); + $vitem->setAttribute( 'anchorname', $anchorname ); + $current_id = $anchorname; + + # Set the latest indexable id to be picked up by the next indexterm, + # which should be in the content of the listitem + + my ($chapter_title, $sec_id, $sec_title); + + foreach my $chap ( $node->findnodes('ancestor::chapter') ) { + $chapter_title = $chap->findvalue('title'); + } + next unless ($chapter_title); + + # Search upward to find a subsection or section id & title + foreach my $ssec ( $node->findnodes("ancestor::section[\@level='2']") ) { + $sec_id = $ssec->getAttribute('id'); + $sec_title = $ssec->findvalue('title'); + last; + } + if (!defined($sec_id)) { + foreach my $sec ( $node->findnodes('ancestor::section') ) { + $sec_id = $sec->getAttribute('id'); + $sec_title = $sec->findvalue('title'); + last; + } + } + + $xref->{$anchorname}{'chapter_title'} = $chapter_title; + $xref->{$anchorname}{'section_id'} = $anchorname; + $xref->{$anchorname}{'section_title'} = $sec_title if ($sec_title); + } + } else { $current_id = $node->getAttribute('id'); } @@ -372,6 +466,10 @@ sub build_indexes { $slist->appendChild($sentry)->appendTextChild( 'term', $secondary ); $sentry->appendChild($sitem)->appendChild($para); } + + my $seealso = $seealso_hash->{$role}{$first}{$primary}{$secondary}; + $para->appendText($seealso) if ($seealso); + my $count = 0; foreach my $ref ( @{ $index_hash->{$role}{$first}{$primary}{$secondary} } ) { $para->appendText(', ') @@ -408,7 +506,7 @@ sub transform { $xml->documentElement()->appendTextChild( 'old_versions', $_ ) foreach old_docs_versions(); ## Parse the ".xsl" file as XML - my $xsl = XML::LibXML->new()->parse_file($xsl_path) or die $!; + my $xsl = XML::LibXML->new(expand_entities => 1)->parse_file($xsl_path) or die $!; ## Generate a stylesheet from the ".xsl" XML. my $stylesheet = XML::LibXSLT->new()->parse_stylesheet($xsl); @@ -464,7 +562,7 @@ sub error_help { ## Parse arguments sub parse_arguments { - my %opt = ( spec => [], filter => [], help => 0, man => 0, web => 0, minify => 1, verbose => 0, localstatic => 0 ); + my %opt = ( spec => [], filter => [], help => 0, man => 0, web => 0, minify => 1, verbose => 0, localstatic => 0, tmpl => "$Bin/../templates" ); GetOptions( \%opt, 'help|h!', 'man!', 'web!', 'spec=s{1,}', 'filter=s{1,}', 'latest=s', 'tmpl=s', 'docroot=s', 'minify!', 'verbose!', 'localstatic!' @@ -506,11 +604,11 @@ __END__ =head1 NAME -gen.pl - Generate exim html documentation and website +gen - Generate exim html documentation and website =head1 SYNOPSIS -gen.pl [options] +gen [options] Options: --help display this help and exits @@ -590,7 +688,7 @@ Generates the exim website and HTML documentation. =head1 EXAMPLE - script/gen.pl \ + script/gen \ --web \ --spec docbook/*/spec.xml \ --filter docbook/*/filter.xml \