summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/linuxdoc75
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools.pm668
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm185
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm176
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/FixRef.pm76
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm583
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm357
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Lang.pm238
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Utils.pm392
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Vars.pm22
-rw-r--r--tools/linuxdoc-tools/Text/EntityMap.pm121
-rw-r--r--tools/linuxdoc-tools/copyright85
12 files changed, 2978 insertions, 0 deletions
diff --git a/tools/linuxdoc b/tools/linuxdoc
new file mode 100755
index 00000000..51110e79
--- /dev/null
+++ b/tools/linuxdoc
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+#
+# linuxdoc.in
+#
+# LinuxDoc-Tools driver. Calls all other LinuxDoc-Tools components,
+# contains configuration information, etcetera.
+# -------------------------------------------------------------------
+
+package main;
+
+sub BEGIN {
+ require 5.004;
+}
+
+use strict;
+
+use vars qw($prefix
+ $isoentities_prefix
+ $DataDir
+ $AuxBinDir
+ $progs);
+
+use FindBin;
+
+$prefix = "/usr";
+$isoentities_prefix = "/usr";
+$DataDir = "$FindBin::Bin/../doc/sbase";
+$AuxBinDir = "/usr/lib/linuxdoc-tools";
+
+use lib "$FindBin::Bin/linuxdoc-tools";
+
+# ---------------------------------------------------------------------
+sub ldt_which {
+# ---------------------------------------------------------------------
+# ---------------------------------------------------------------------
+ die "ldt_which: No filename(s) array given. Aborting ...\n" unless scalar @_;
+
+ foreach my $file ( @_ ){
+ if ( $file =~ m/\// ) {
+ return $file if -x $file;
+ } else {
+ foreach my $path ( split(':',$ENV{'PATH'}) ){
+ $path =~ s/\/+$//;
+ return $file if -x "$path/$file";
+ }
+ }
+ }
+ die "No executable found in path for (", join(' ',@_) ,"). Aborting ...\n";
+}
+
+$progs = {
+ "SGMLSASP" => ldt_which("sgmlsasp"),
+ "NSGMLS" => ldt_which("nsgmls","onsgmls"),
+ "GROFF" => ldt_which("groff"),
+ "GROFFMACRO" => "-ms",
+# "NKF" => "@NKF@"
+};
+
+$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
+ (defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
+
+require LinuxDocTools;
+&LinuxDocTools::init;
+
+my @FileList = LinuxDocTools::process_options ($0, @ARGV);
+
+foreach my $curfile (@FileList) {
+ &LinuxDocTools::process_file ($curfile);
+}
+
+exit 0;
+
+# Local Variables:
+# mode: perl
+# End:
diff --git a/tools/linuxdoc-tools/LinuxDocTools.pm b/tools/linuxdoc-tools/LinuxDocTools.pm
new file mode 100644
index 00000000..12b77319
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools.pm
@@ -0,0 +1,668 @@
+#! /usr/bin/perl
+#
+# LinuxDocTools.pm
+#
+# LinuxDoc-Tools driver core. This contains all the basic functionality
+# we need to control all other components.
+#
+# Copyright © 1996, Cees de Groot.
+# Copyright © 2000, Taketoshi Sano
+# Copyright © 2006-2018, Agustin Martin
+# --------------------------------------------------------------------------------
+
+package LinuxDocTools;
+
+require 5.006;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools - SGML conversion utilities for LinuxDoc DTD.
+
+=head1 SYNOPSIS
+
+ use LinuxDocTools;
+ LinuxDocTools::init;
+ @files = LinuxDocTools::process_options ($0, @ARGV);
+ for $curfile (@files) {
+ LinuxDocTools::process_file ($curfile);
+ }
+
+=head1 DESCRIPTION
+
+The LinuxDocTools package encapsulates all the functionality offered by
+LinuxDoc-Tools. It is used, of course, by LinuxDoc-Tools;
+but the encapsulation should provide for a simple interface for other users as well.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use File::Copy;
+use File::Temp qw(tempdir);
+use File::Basename qw(fileparse);
+use LinuxDocTools::Lang;
+use LinuxDocTools::Utils qw(usage cleanup trap_signals remove_tmpfiles create_temp);
+use LinuxDocTools::Vars;
+
+sub BEGIN
+{
+ #
+ # Make sure we're always looking here. Note that "use lib" adds
+ # on the front of the search path, so we first push dist, then
+ # site, so that site is searched first.
+ #
+ use lib "$main::DataDir/dist";
+ use lib "$main::DataDir/site";
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_searchfile {
+# -----------------------------------------------------------------------------------
+# Look for a readable file in the locations. Return first math.
+# -----------------------------------------------------------------------------------
+ my $files = shift;
+ foreach my $file ( @$files ){
+ return $file if -r $file;
+ }
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_getdtd_v1 {
+# -----------------------------------------------------------------------------------
+# Get the dtd
+# -----------------------------------------------------------------------------------
+ my $file = shift;
+ my $error_header = "LinuxdocTools::ldt_getdtd_v1";
+ my $dtd;
+
+ open ( my $FILE, "< $file")
+ or die "$error_header: Could not open \"$file\" for reading. Aborting ...\n";
+
+ while ( <$FILE> ) {
+ tr/A-Z/a-z/;
+ # check for [<!doctype ... system] type definition
+ if ( /<!doctype\s*(\w*)\s*system/ ) {
+ $dtd = $1;
+ last;
+ # check for <!doctype ... PUBLIC ... DTD ...
+ } elsif ( /<!doctype\s*\w*\s*public\s*.*\/\/dtd\s*(\w*)/mi ) {
+ $dtd = $1;
+ last;
+ # check for <!doctype ...
+ # PUBLIC ... DTD ...
+ # (multi-line version)
+ } elsif ( /<!doctype\s*(\w*)/ ) {
+ $dtd = "precheck";
+ next;
+ } elsif ( /\s*public\s*.*\/\/dtd\s*(\w*)/ && $dtd eq "precheck" ) {
+ $dtd = $1;
+ last;
+ }
+ }
+ close $FILE;
+
+ return $dtd;
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_getdtd_v2 {
+# -----------------------------------------------------------------------------------
+# Second way of getting dtd, fron nsgmls output.
+# -----------------------------------------------------------------------------------
+ my $preaspout = shift;
+ my $error_header = "LinuxdocTools::ldt_getdtd_v2";
+ my $dtd2;
+
+ open (my $TMP,"< $preaspout")
+ or die "%error_header: Could not open $preaspout for reading. Aborting ...\n";
+ while ( defined ($dtd2 = <$TMP>) && ! ( $dtd2 =~ /^\(/) ) { };
+ close $TMP;
+ $dtd2 =~ s/^\(//;
+ $dtd2 =~ tr/A-Z/a-z/;
+ chomp $dtd2;
+ return $dtd2;
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_latin1tosgml {
+# -----------------------------------------------------------------------------------
+# Convert latin1 chars in input filehandle to sgml entities in the returned string
+# -----------------------------------------------------------------------------------
+ my $FILE = shift;
+ my $sgmlout;
+
+ while (<$FILE>){
+ # Outline these commands later on - CdG
+ #change latin1 characters to SGML
+ #by Farzad Farid, adapted by Greg Hankins
+ s/À/\&Agrave;/g;
+ s/Á/\&Aacute;/g;
+ s/Â/\&Acirc;/g;
+ s/Ã/\&Atilde;/g;
+ s/Ä/\&Auml;/g;
+ s/Å/\&Aring;/g;
+ s/Æ/\&AElig;/g;
+ s/Ç/\&Ccedil;/g;
+ s/È/\&Egrave;/g;
+ s/É/\&Eacute;/g;
+ s/Ê/\&Ecirc;/g;
+ s/Ë/\&Euml;/g;
+ s/Ì/\&Igrave;/g;
+ s/Í/\&Iacute;/g;
+ s/Î/\&Icirc;/g;
+ s/Ï/\&Iuml;/g;
+ s/Ñ/\&Ntilde;/g;
+ s/Ò/\&Ograve;/g;
+ s/Ó/\&Oacute;/g;
+ s/Ô/\&Ocirc;/g;
+ s/Õ/\&Otilde;/g;
+ s/Ö/\&Ouml;/g;
+ s/Ø/\&Oslash;/g;
+ s/Ù/\&Ugrave;/g;
+ s/Ú/\&Uacute;/g;
+ s/Û/\&Ucirc;/g;
+ s/Ü/\&Uuml;/g;
+ s/Ý/\&Yacute;/g;
+ s/Þ/\&THORN;/g;
+ s/ß/\&szlig;/g;
+ s/à/\&agrave;/g;
+ s/á/\&aacute;/g;
+ s/â/\&acirc;/g;
+ s/ã/\&atilde;/g;
+ s/ä/\&auml;/g;
+ s/å/\&aring;/g;
+ s/æ/\&aelig;/g;
+ s/ç/\&ccedil;/g;
+ s/è/\&egrave;/g;
+ s/é/\&eacute;/g;
+ s/ê/\&ecirc;/g;
+ s/ë/\&euml;/g;
+ s/ì/\&igrave;/g;
+ s/í/\&iacute;/g;
+ s/î/\&icirc;/g;
+ s/ï/\&iuml;/g;
+ s/µ/\&mu;/g;
+ s/ð/\&eth;/g;
+ s/ñ/\&ntilde;/g;
+ s/ò/\&ograve;/g;
+ s/ó/\&oacute;/g;
+ s/ô/\&ocirc;/g;
+ s/õ/\&otilde;/g;
+ s/ö/\&ouml;/g;
+ s/ø/\&oslash;/g;
+ s/ù/\&ugrave;/g;
+ s/ú/\&uacute;/g;
+ s/û/\&ucirc;/g;
+ s/ü/\&uuml;/g;
+ s/ý/\&yacute;/g;
+ s/þ/\&thorn;/g;
+ s/ÿ/\&yuml;/g;
+ $sgmlout .= $_;
+ }
+ return $sgmlout;
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::init
+
+Takes care of initialization of package-global variables (which are actually
+defined in L<LinuxDocTools::Vars>). The package-global variables are I<$global>,
+a reference to a hash containing numerous settings, I<%Formats>, a hash
+containing all the formats, and I<%FmtList>, a hash containing the currently
+active formats for help texts.
+
+Apart from this, C<LinuxDocTools::init> also finds all distributed and site-local
+formatting backends and C<require>s them.
+
+=cut
+
+# -----------------------------------------------------------------------------------
+sub init {
+# -----------------------------------------------------------------------------------
+ trap_signals;
+
+ # Register the ``global'' pseudoformat. Apart from the global settings, we
+ # also use $global to keep the global variable name space clean everything
+ # that we need to provide to other modules is stuffed into $global.
+ $global = {};
+ $global->{NAME} = "global";
+ $global->{HELP} = "";
+ $global->{OPTIONS} = [
+ { option => "backend",
+ type => "l",
+ 'values' => [ "html", "info", "latex", "lyx", "rtf", "txt", "check" ],
+ short => "B" },
+ { option => "papersize",
+ type => "l",
+ 'values' => [ "a4", "letter" ],
+ short => "p" },
+ { option => "language",
+ type => "l",
+ 'values' => [ @LinuxDocTools::Lang::Languages ],
+ short => "l" },
+ { option => "charset", type => "l",
+ 'values' => [ "latin", "ascii", "nippon", "euc-kr" ], short => "c" },
+ { option => "style", type => "s", short => "S" },
+ { option => "tabsize", type => "i", short => "t" },
+ # { option => "verbose", type => "f", short => "v" },
+ { option => "debug", type => "f", short => "d" },
+ { option => "define", type => "s", short => "D" },
+ { option => "include", type => "s", short => "i" },
+ { option => "pass", type => "s", short => "P" }
+ ];
+ $global->{backend} = "linuxdoc";
+ $global->{papersize} = "a4";
+ $global->{language} = "en";
+ $global->{charset} = "ascii";
+ $global->{style} = "";
+ $global->{tabsize} = 8;
+ $global->{verbose} = 0;
+ $global->{define} = "";
+ $global->{debug} = 0;
+ $global->{include} = "";
+ $global->{pass} = "";
+ $global->{InFiles} = [];
+ $global->{fmtlist} = ""; # List of loaded fmt files
+ $Formats{$global->{NAME}} = $global; # All formats we know.
+ $FmtList{$global->{NAME}} = $global; # List of formats for help msgs.
+
+ $global->{sgmlpre} = "$main::AuxBinDir/sgmlpre";
+ my $error_header = "LinuxdocTools::init";
+
+ if ( -e "/etc/papersize" ){
+ open (my $PAPERSIZE,"< /etc/papersize") ||
+ die "$error_header: Count not open \"/etc/papersize\" for reading\n";
+ chomp (my $paper = <$PAPERSIZE>);
+ $global->{papersize} = "letter" if ( $paper eq "letter");
+ close $PAPERSIZE;
+ }
+
+ # automatic language detection: disabled by default
+ # {
+ # my $lang;
+ # foreach $lang (@LinuxDocTools::Lang::Languages)
+ # {
+ # if (($ENV{"LC_ALL"} =~ /^$lang/i) ||
+ # ($ENV{"LC_CTYPE"} =~ /^$lang/i) ||
+ # ($ENV{"LANG"} =~ /^$lang/i)) {
+ # $global->{language} = Any2ISO($lang);
+ # }
+ # }
+ # }
+
+ # --------------------------------------------------------------------------------
+ $global->{preNSGMLS} = sub {
+ # ------------------------------------------------------------------------------
+ # Define a fallback preNSGMLS. Used when the format is "global" (from sgmlcheck).
+ # ------------------------------------------------------------------------------
+ $global->{NsgmlsOpts} .= " -s ";
+ $global->{NsgmlsPrePipe} = "cat $global->{file}";
+ };
+
+ # We need to load all fmt files here, so the allowed options for all
+ # format are put into $global and a complete usage message is built,
+ # including options for all formats.
+ my %locations = ();
+ foreach my $path ("$main::DataDir/site",
+ "$main::DataDir/dist",
+ "$main::DataDir/fmt"){
+ foreach my $location (<$path/fmt_*.pl>){
+ my $fmt = $location;
+ $fmt =~ s/^.*_//;
+ $fmt =~ s/\.pl$//;
+ $locations{$fmt} = $location unless defined $locations{$fmt};
+ }
+ }
+
+ foreach my $fmt ( keys %locations ){
+ $global->{fmtlist} .= " Loading $locations{$fmt}\n";
+ require $locations{$fmt};
+ }
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::process_options ($0, @ARGV)
+
+This function contains all initialization that is bound to the current
+invocation of LinuxDocTools. It looks in C<$0> to deduce the backend that
+should be used (ld2txt activates the I<txt> backend) and parses the
+options array. It returns an array of filenames it encountered during
+option processing.
+
+As a side effect, the environment variable I<SGML_CATALOG_FILES> is
+modified and, once I<$global->{format}> is known, I<SGMLDECL> is set.
+
+=cut
+
+# ------------------------------------------------------------------------
+sub process_options {
+# ------------------------------------------------------------------------
+ my $progname = shift;
+ my @tmpargs = @_;
+ my @args = ();
+ my $format = '';
+
+ # Try getting the format. We need to do this here so process_options
+ # knows which is the format and which format options are allowed
+
+ # First, see if we have an explicit backend option by looping over command line.
+ # Do not shift in the while condition itself, 0 in options like '-s 0' will
+ # otherwise stop looping
+ while ( @tmpargs ){
+ $_ = shift @tmpargs;
+ if ( s/--backend=// ){
+ $format = $_;
+ } elsif ( $_ eq "-B" ){
+ $format = shift @tmpargs;
+ } else {
+ push @args, $_;
+ }
+ }
+
+ unless ( $format ){
+ my ($tmpfmt, $dummy1, $dummy2) = fileparse($progname, "");
+ if ( $tmpfmt =~ s/^sgml2// ) { # Calling program through sgml2xx symlinks
+ $format = $tmpfmt;
+ } elsif ( $tmpfmt eq "sgmlcheck" ) { # Calling program through sgmlcheck symlink
+ $format = "global";
+ }
+ }
+
+ if ( $format ) {
+ if ( $format eq "check" ){
+ $format = "global";
+ } elsif ( $format eq "latex" ){
+ $format = "latex2e";
+ }
+ $FmtList{$format} = $Formats{$format} or
+ usage("$format: Unknown format");
+ $global->{format} = $format;
+ } else {
+ usage("");
+ }
+
+ # Parse all the options from @args, and return files.
+ my @files = LinuxDocTools::Utils::process_options(@args);
+
+ # Check the number of given files
+ $#files > -1 || usage("No filenames given");
+
+ # Normalize language string
+ $global->{language} = Any2ISO($global->{language});
+
+ # Setup the SGML environment.
+ my @sgmlcatalogs =
+ (# SGML iso-entities catalog location in Debian sgml-data package
+ "$main::isoentities_prefix/share/sgml/entities/sgml-iso-entities-8879.1986/catalog",
+ # SGML iso-entities catalog location in ArchLinux, Fedora and Gentoo
+ "$main::isoentities_prefix/share/sgml/sgml-iso-entities-8879.1986/catalog",
+ # SGML iso-entities catalog location when installed from linuxdoc-tools
+ "$main::isoentities_prefix/share/sgml/iso-entities-8879.1986/iso-entities.cat",
+ # dtd/catalog for SGML-Tools
+ "$main::DataDir/linuxdoc-tools.catalog",
+ # The super catalog
+ "/etc/sgml/catalog");
+
+ @sgmlcatalogs = ($ENV{SGML_CATALOG_FILES}, @sgmlcatalogs) if defined $ENV{SGML_CATALOG_FILES};
+
+ $ENV{SGML_CATALOG_FILES} = join(':', @sgmlcatalogs);
+
+ # Set to one of these if readable, nil otherwise
+ $ENV{SGMLDECL} = ldt_searchfile(["$main::DataDir/dtd/$global->{format}.dcl",
+ "$main::DataDir/dtd/$global->{style}.dcl",
+ "$main::DataDir/dtd/sgml.dcl"]);
+
+ # Show the list of loaded fmt_*.pl files if debugging
+ print STDERR $global->{fmtlist} if $global->{debug};
+
+ # Return the list of files to be processed
+ return @files;
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::process_file
+
+With all the configuration done, this routine will take a single filename
+and convert it to the currently active backend format. The conversion is
+done in a number of steps in tight interaction with the currently active
+backend (see also L<LinuxDocTools::BackEnd>):
+
+=over
+
+=item 1. Backend: set NSGMLS options and optionally create a pre-NSGMLS pipe.
+
+=item 2. Here: Run the preprocessor to handle conditionals.
+
+=item 3. Here: Run NSGMLS.
+
+=item 4. Backend: run pre-ASP conversion.
+
+=item 5. Here: Run SGMLSASP.
+
+=item 6. Backend: run post-ASP conversion, generating the output.
+
+=back
+
+All stages are influenced by command-line settings, currently active format,
+etcetera. See the code for details.
+
+=cut
+
+# ------------------------------------------------------------------------
+sub process_file {
+# ------------------------------------------------------------------------
+ my $file = $global->{origfile} = shift (@_);
+ my $saved_umask = umask;
+ my $error_header = "LinuxdocTools::process_file";
+
+ print "Processing file $file\n";
+ umask 0077;
+
+ my ($filename, $filepath, $filesuffix) = fileparse($file, "\.sgml");
+ $global->{filename} = $filename;
+ $global->{filepath} = $filepath;
+ $global->{file} = ldt_searchfile(["$filepath/$filename.sgml",
+ "$filepath/$filename.SGML"])
+ or die "$error_header: Cannot find $file. Aborting ...\n";
+
+ my $dtd = ldt_getdtd_v1("$global->{file}");
+ print STDERR "DTD: " . $dtd . "\n" if $global->{debug};
+
+ # Prepare temporary directory
+ my $tmpdir = $ENV{'TMPDIR'} || '/tmp';
+ $tmpdir = tempdir("linuxdoc-tools.XXXXXXXXXX", DIR => "$tmpdir");
+
+ # Set common base name for temp files and temp file names
+ my $tmpbase = $global->{tmpbase} = $tmpdir . '/sgmltmp.' . $filename;
+ my $precmdout = "$tmpbase.01.precmdout";
+ my $nsgmlsout = "$tmpbase.02.nsgmlsout"; # Was $tmpbase.1
+ my $preaspout = "$tmpbase.03.preaspout"; # Was $tmpbase.2
+ my $aspout = "$tmpbase.04.aspout"; # Was $tmpbase.3
+
+ # Set up the preprocessing command. Conditionals have to be
+ # handled here until they can be moved into the DTD, otherwise
+ # a validating SGML parser will choke on them.
+
+ # Check if output option for latex is pdf or not
+ if ($global->{format} eq "latex2e") {
+ if ($Formats{$global->{format}}{output} eq "pdf") {
+ $global->{define} .= " pdflatex=yes";
+ }
+ }
+
+ # Set the actual pre-processing command
+ my($precmd) = "| $global->{sgmlpre} output=$global->{format} $global->{define}";
+
+ # Make sure path of file to be processed is in SGML_SEARCH_PATH
+ $ENV{"SGML_SEARCH_PATH"} .= ":$filepath";
+
+ # You can hack $NsgmlsOpts here, etcetera.
+ $global->{NsgmlsOpts} .= "-D $main::prefix/share/sgml -D $main::DataDir";
+ $global->{NsgmlsOpts} .= "-i$global->{include}" if ($global->{include});
+
+ # If a preNSGMLS function is defined in the fmt file, pipe its output to $FILE,
+ # otherwise just open $global->{file} as $IFILE
+ # ----------------------------------------------------------------------------
+ my $IFILE;
+ if ( defined $Formats{$global->{format}}{preNSGMLS} ) {
+ $global->{NsgmlsPrePipe} = &{$Formats{$global->{format}}{preNSGMLS}};
+ open ($IFILE,"$global->{NsgmlsPrePipe} |")
+ || die "$error_header: Could not open pipe from $global->{NsgmlsPrePipe}. Aborting ...\n";
+ } else {
+ open ($IFILE,"< $global->{file}")
+ || die "$error_header: Could not open $global->{file} for reading. Aborting ...\n";
+ }
+
+ # Create a temp file with $precmd output
+ my $precmd_command = "$precmd > $precmdout";
+
+ open (my $PRECMDOUT, "$precmd_command")
+ or die "$error_header: Could not open pipe to $precmdout. Aborting ...\n";
+
+ if ($global->{charset} eq "latin") {
+ print $PRECMDOUT ldt_latin1tosgml($IFILE);
+ } else {
+ copy($IFILE,$PRECMDOUT);
+ }
+
+ close $IFILE;
+ close $PRECMDOUT;
+
+ # Process with nsgmls.
+ my $nsgmls_command = "$main::progs->{NSGMLS} $global->{NsgmlsOpts} $ENV{SGMLDECL} $precmdout > $nsgmlsout";
+ system($nsgmls_command) == 0
+ or die "Error: \"$nsgmls_command\" failed with exit status: ",$? >> 8,"\n";
+
+ # Special case: if format is global, we're just checking.
+ cleanup if ( $global->{format} eq "global");
+
+ # If output file does not exists or is empty, something went wrong.
+ if ( ! -e "$nsgmlsout" ) {
+ die "$error_header: Can't create file $nsgmlsout. Aborting ...\n";
+ } elsif ( -z "$nsgmlsout" ){
+ die "$error_header: $nsgmlsout empty, SGML parsing error. Aborting ...\n";
+ }
+
+ print "- Nsgmls stage finished.\n" if $global->{debug};
+
+ # If a preASP stage is defined, let the format handle it.
+ # --------------------------------------------------------
+ open (my $PREASP_IN, "< $nsgmlsout")
+ or die "$error_header: Could not open $nsgmlsout for reading. Aborting ...\n";
+ open (my $PREASP_OUT, "> $preaspout")
+ or die "$error_header: Could not open $preaspout for writing. Aborting ...\n";
+
+ if (defined $Formats{$global->{format}}{preASP}) {
+ # Usage: preASP ($INHANDLE, $OUTHANDLE);
+ &{$Formats{$global->{format}}{preASP}}($PREASP_IN, $PREASP_OUT) == 0
+ or die "$error_header: Error pre-processing $global->{format}.\n";
+ } else {
+ copy ($PREASP_IN, $PREASP_OUT);
+ }
+
+ close $PREASP_IN;
+ close $PREASP_OUT;
+
+ die "$error_header: Can't create $preaspout file. Aborting ...\n"
+ unless -e "$preaspout";
+
+ print "- PreASP stage finished.\n" if ( $global->{debug} );
+
+ # Run sgmlsasp, with an optional style if specified.
+ # -----------------------------------------------------------
+ my $dtd2 = ldt_getdtd_v2($preaspout)
+ or die "$error_header: Could not read dtd from $preaspout. Aborting ...\n";
+
+ unless ( $dtd eq $dtd2 ){
+ print STDERR "Warning: Two different values for dtd, dtd1: $dtd, dtd2: $dtd2\n";
+ $dtd = $dtd2;
+ }
+
+ $global->{'dtd'} = $dtd;
+
+ # Search order:
+ # - datadir/site/<dtd>/<format>
+ # - datadir/dist/<dtd>/<format>
+
+ my $style = ($global->{style}) ?
+ ldt_searchfile(["$main::DataDir/site/$dtd/$global->{format}/$global->{style}mapping",
+ "$main::DataDir/dist/$dtd/$global->{format}/$global->{style}mapping",
+ "$main::DataDir/mappings/$global->{format}/$global->{style}mapping"])
+ :
+ '';
+
+ my $mapping = ldt_searchfile(["$main::DataDir/site/$dtd/$global->{format}/mapping",
+ "$main::DataDir/dist/$dtd/$global->{format}/mapping",
+ "$main::DataDir/mappings/$global->{format}/mapping"])
+ or die "$error_header: Could not find mapping file for $dtd/$global->{format}. Aborting ...\n";
+
+ $mapping = "$style $mapping" if $style;
+
+ $global->{charset} = "nippon" if ($global->{language} eq "ja");
+
+ # We don't have Korean groff so charset should be latin1.
+ if ($global->{language} eq "ko") {
+ if ($global->{format} eq "groff") {
+ $global->{charset} = "latin1";
+ } else {
+ $global->{charset} = "euc-kr";
+ }
+ }
+
+ if ($global->{format} eq "groff"){
+ if ($dtd eq "linuxdoctr") {
+ $mapping = "$main::DataDir/mappings/$global->{format}/tr-mapping";
+ }
+ }
+
+ my $sgmlsasp_command = "$main::progs->{SGMLSASP} $mapping < $preaspout |
+ expand -t $global->{tabsize} > $aspout";
+ system ($sgmlsasp_command) == 0
+ or die "$error_header: Error running $sgmlsasp_command. Aborting ...\n";
+
+ die "$error_header: Can't create $aspout file. Aborting ...\n"
+ unless -e "$aspout";
+
+ print "- ASP stage finished.\n" if ( $global->{debug} );
+
+ # If a postASP stage is defined, let the format handle it.
+ # ----------------------------------------------------------------
+ umask $saved_umask;
+
+ open (my $INPOSTASP, "< $aspout" )
+ or die "$error_header: Could not open $aspout for reading. Aborting ...\n";
+ if (defined $Formats{$global->{format}}{postASP}) {
+ # Usage: postASP ($INHANDLE)
+ # Should leave whatever it thinks is right based on $INHANDLE.
+ &{$Formats{$global->{format}}{postASP}}($INPOSTASP) == 0
+ or die "$error_header: Error post-processing $global->{format}. Aborting ...\n";
+ }
+ close $INPOSTASP;
+
+ print "- postASP stage finished.\n" if ( $global->{debug} );
+
+ # All done, remove the temporaries.
+ remove_tmpfiles($tmpbase) unless ( $global->{debug} );
+}
+
+=pod
+
+=back
+
+=head1 SEE ALSO
+
+Documentation for various sub-packages of LinuxDocTools.
+
+=head1 AUTHOR
+SGMLTools are written by Cees de Groot, C<E<lt>cg@cdegroot.comE<gt>>,
+and various SGML-Tools contributors as listed in C<CONTRIBUTORS>.
+Taketoshi Sano C<E<lt>sano@debian.org<gt>> rename to LinuxDocTools.
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm b/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm
new file mode 100644
index 00000000..e402cc5d
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm
@@ -0,0 +1,185 @@
+#
+# BackEnd.pm
+#
+# $Id: BackEnd.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Dummy module containing backend specification.
+#
+# © Copyright 1997, Cees de Groot
+#
+package LinuxDocTools::BackEnd;
+
+die "This is a documentation package only!";
+
+=head1 NAME
+
+LinuxDocTools::BackEnd - LinuxDocTools back-end specification
+
+=head1 SYNOPSIS
+
+ require LinuxDocTools::BackEnd;
+ $BackEnd->{...};
+
+=head1 DESCRIPTION
+
+LinuxDoc-Tools backend modules need to conform to a certain interface which is
+detailed in this document. The interface makes sure that new backend modules
+(or customer overrides) are compatible with what the main B<LinuxDocTools>
+package expects. Note that this interface is still subject to change, you
+should check this document on new releases of LinuxDoc-Tools.
+
+=head1 INTERFACE
+
+The interface between the main package and individual backends is very
+minimal - only one global variable is modified, everything else is local. It
+relies heavily on references and complex datatypes, so you want to make
+sure that you're up-to-date with Perl5.
+
+Every backend creates a reference to a hash and stores this reference in
+the global I<%Formats> hash:
+
+ my $BackEnd = {};
+ $Formats{"BackEnd"} = $BackEnd;
+
+The rest of this document will deal with the entries in the local hash
+referenced by I<$BackEnd>.
+
+=head1 HASH ENTRIES
+
+=over 4
+
+=item NAME
+
+Specify the name of the backend, for help messages etcetera.
+
+ $BackEnd->{NAME} = "BackEnd";
+
+=item HELP
+
+Specify an optional extra help message printed when the default usage
+function is executed (see L<LinuxDocTools::Utils>).
+
+ $BackEnd->{HELP} = "This is just and example message";
+
+=item OPTIONS
+
+This specifies the local set of options, which is added to the global set
+of options (available in I<$global>). The options are specified as an
+array of hashes containing a number of keys:
+
+=over 4
+
+=item option
+
+The long option name
+
+=item type
+
+The type of the option, one of B<f> (flag), B<l> (list of allowed values),
+B<s> (string), or B<i> (integer).
+
+=item values
+
+An array of allowed values, in case the option is of the list type.
+
+=item short
+
+A short (single-letter) version of the option name.
+
+=back
+
+Options can be specified as long options:
+
+ --papersize=a4
+
+or as short options:
+
+ -p a4
+
+Note that both the long options as the short options must not conflict with
+the global options (an override is not - yet - possible) and should not
+conflict with other backends.
+
+ $BackEnd->{OPTIONS} = [
+ { option => "split", type => "l",
+ 'values' => [ "0", "1", "2" ], short => "s" },
+ { option => "dosnames", type => "f", short => "D" },
+ { option => "imagebuttons", type => "f", short => "I"}
+ ];
+
+The long names themselves function as hash keys; a default can be given
+here and the option processing function will store any values found
+at the same place:
+
+ $BackEnd->{'split'} = 1;
+ $BackEnd->{dosnames} = 0;
+ $BackEnd->{imagebuttons} = 0;
+
+=item preNSGMLS
+
+If defined, this should contain a subroutine that normally does two things: it
+can modify the global value C<$global-E<gt>{NsgmlsOpts}> and it can set the
+global value C<$global-E<gt>{NsgmlsPrePipe}>. The first variable contains
+the option string passed to B<nsgmls>, and the second variable can contain
+a command that generates the input for B<nsgmls>, presumably using the
+current input file in some way (the current input file can be found
+in C<$global-E<gt>{file}>).
+
+ $BackEnd->{preNSGMLS} = sub {
+ $global->{NsgmlsOpts} .= " -ifmtBackEnd ";
+ $global->{NsgmlsPrePipe} = "sed 's/\@/\@\@/g' $global->{file}";
+ };
+
+=item preASP
+
+If defined, this should contain a subroutine accepting an input and an output
+file descriptor. The input file descriptor contains the raw output from
+B<nsgmls>, and the output file descriptor should be filled with input
+to B<sgmlsasp>. This stage is often used to munch character entities
+before they're fed to B<sgmlsasp>, see L<LinuxDocTools::CharEnts>. If the routine
+doesn't return C<0>, LinuxDocTools aborts.
+
+ $BackEnd->{preASP} = sub
+ {
+ my ($infile, $outfile) = @_;
+
+ while (<$infile>)
+ {
+ s/([^\\])\\n/$1 \\n/g;
+ print $outfile $_;
+ }
+ return 0;
+ };
+
+=item postASP
+
+This entry should always be defined, because it needs to contain a routine
+that receives the output from B<sgmlsasp> which normally needs finalization.
+LinuxDocTools itself doesn't know about file-naming conventions, etcetera, of
+the backend so writing the final file is left to the backend. The subroutine
+receives a reference to a filehandle (containing B<sgmlsasp> output) and
+should do whatever it likes with this datastream.
+
+ $BackEnd->{postASP} = sub
+ {
+ my $infile = shift;
+
+ copy ($infile, "$global->{filename}.ext");
+ return 0;
+ };
+
+=back
+
+=head1 SEE ALSO
+
+L<LinuxDocTools> and subpackages.
+
+=head1 AUTHOR
+
+SGML-Tools are written by Cees de Groot, C<E<lt>cg@cdegroot.comE<gt>>,
+and various SGML-Tools contributors as listed in C<CONTRIBUTORS>.
+Taketoshi Sano C<E<lt>sano@debian.org<gt>> rename it to LinuxDocTools,
+and do some bug-fixes and updates on it.
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm b/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm
new file mode 100644
index 00000000..b0bcd532
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm
@@ -0,0 +1,176 @@
+#
+# CharEnts.pm
+#
+# $Id: CharEnts.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# SGML Character Entity utilities -- interface to Perl module
+# Text::EntityMap.
+#
+package LinuxDocTools::CharEnts;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools::CharEnts - Interface to Text::EntityMap
+
+=head1 SYNOPSIS
+
+ my $char_maps = load_char_maps ('.2ext', [ Text::EntityMap::sdata_dirs() ]);
+
+ $value = parse_data ($value, $char_maps, $escape_sub);
+
+=head1 DESCRIPTION
+
+This module provides a simple interface to the entity map handling provided by
+B<Text::EntityMap>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use Text::EntityMap;
+use Exporter;
+
+use vars qw(@ISA @EXPORT $VERSION);
+@ISA = qw(Exporter);
+@EXPORT = qw(load_char_maps parse_data);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+
+# `%warn_map' tracks entities that were not able to be mapped so they
+# are only warned once.
+my %warn_map = ();
+
+=item parse_data ($data, $char_map, $escape_sub)
+
+B<parse_data> takes a string of I<$data> in the output format of
+B<nsgmls> (see SP's C<sgmlsout.htm> document) without the leading dash.
+B<parse_data> calls I<$char_map>'s lookup method for each sdata
+entity reference. If the entity reference is undefined, it is
+left alone (without the (n)sgmls C<\|>). For all remaining data,
+B<parse_data> calls back into I<$escape_sub> to properly escape
+characters for the backend formatter. Strings returned from the
+lookup method are assumed to be already escaped.
+
+This routine is derived from David Megginson's SGMLSpm.
+
+=cut
+
+sub parse_data {
+ my ($data, $char_map, $escape_sub) = @_;
+ my ($result) = "";
+
+ my $sdata_flag = 0;
+ my $out = '';
+
+ while ($data =~ /\\(\\|n|\||[0-7]{1,3})/) {
+ $out .= $`;
+ $data = $';
+
+ if ($1 eq '|') {
+ # beginning or end of SDATA
+ if ("$out" ne '') {
+ if ($sdata_flag) {
+ my ($mapping) = $char_map->lookup ($out);
+ if (defined $mapping) {
+ # escape `\' in mapping for ASP
+ $mapping =~ s/\\/\\\\/g;
+ $result .= $mapping;
+ } else {
+ if (!$warn_map{$out}) {
+ warn "parse_data: no entity map for \`$out'\n";
+ $warn_map{$out} = 1;
+ }
+ # output the entity reference inside of `{}'
+ $result .= &$escape_sub ("{" . $out . "}");
+ }
+ } else {
+ $result .= &$escape_sub ($out);
+ }
+ $out = '';
+ }
+ $sdata_flag = !$sdata_flag;
+
+ } elsif ($1 eq 'n') {
+ # record end
+
+ # pass '\\n' through to ASP
+ $result .= &$escape_sub ($out) . '\\n';
+ $out = '';
+ } elsif ($1 eq '\\') {
+ # backslash
+
+ $result .= &$escape_sub ($out);
+
+ $out = '[bsol ]'; # bsol == entity name for backslash
+ my ($mapping) = $char_map->lookup ($out);
+ if (defined $mapping) {
+ # escape `\' in mapping for ASP
+ $mapping =~ s/\\/\\\\/g;
+ $result .= $mapping;
+ } else {
+ if (!$warn_map{$out}) {
+ warn "parse_data: no entity map for \`$out'\n";
+ $warn_map{$out} = 1;
+ }
+ # output the entity reference inside of `{}'
+ $result .= &$escape_sub ("{" . $out . "}");
+ }
+ $out = '';
+ } else {
+ # other octal character
+ $result .= &$escape_sub ($out . chr(oct($1)));
+ $out = '';
+ }
+ }
+ $out .= $data;
+ if ("$out" ne '') {
+ $result .= &$escape_sub ($out);
+ }
+
+ return ($result);
+}
+
+=item load_char_maps ($format, $paths)
+
+B<load_char_maps> takes an EntityMap format suffix and loads all of the
+character entity replacement sets for that suffix into an EntityMapGroup.
+It searches every directory in I<@{$path}>.
+
+=cut
+
+sub load_char_maps {
+ my ($format, $paths) = @_;
+
+ my (@char_maps) = ();
+ my ($path, $file_name, $char_map);
+
+ foreach $path (@{$paths}) {
+ if (-d $path) {
+ opendir (SDATADIR, $path)
+ || die "load_char_map: opening directory \`$path' for reading: $!\n";
+ foreach $file_name (readdir (SDATADIR)) {
+ next if ($file_name !~ /$format$/);
+ eval {$char_map = Text::EntityMap->load ("$path/$file_name")}
+ || die "load_char_map: loading \`$path/$file_name'\n$@\n";
+ push (@char_maps, $char_map);
+ }
+ closedir (SDATADIR);
+ }
+ }
+
+ warn "load_char_maps: no entity maps found\n"
+ if ($#char_maps == -1);
+
+ return (Text::EntityMap->group (@char_maps));
+}
+
+=back
+
+=head1 AUTHOR
+
+Ken MacLeod, C<E<lt>ken@bitsko.slc.ut.usE<gt>>
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm b/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm
new file mode 100644
index 00000000..d2549857
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm
@@ -0,0 +1,76 @@
+#
+# FixRef.pm
+#
+# $Id: FixRef.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Start conversion from parsed linuxdoc-sgml to html.
+# - Identify references and file count
+#
+# Rules based on fixref.l
+#
+package LinuxDocTools::FixRef;
+
+# Externally visible variables
+$fixref = {};
+
+# Initialize: set splitlevel before using rules
+# Usage: &{$fixref->{init}}(<split level>);
+ # 0 - super page mode
+ # 1 - big page mode
+ # 2 - small page mode
+$fixref->{init} = sub {
+ $splitlevel = shift;
+};
+
+# Outputs: Read after using rules
+$fixref->{filenum} = 0; # Count of files we will create
+$fixref->{lrec} = {}; # label -> filenum
+
+# Package variables
+$chapter_mode = 0; # <report> vs. <article>
+$splitlevel = 0; # See $fixref->{init} above;
+ # Automatically reduced by 1 for chapter mode
+
+# Finalize parsing
+$fixref->{finish} = sub { }; # Do nothing when we're done
+
+# Ruleset
+$fixref->{rules} = {}; # Individual parsing rules
+$fixref->{defaultrule} = sub { }; # If line does not match any rules
+
+# Set the rules
+# <@@ssect> - split file if necessary
+$fixref->{rules}->{'^<@@ssect>.*$'} = sub { &splitfile(2); };
+
+# <@@sect> - split file if necessary
+$fixref->{rules}->{'^<@@sect>.*$'} = sub { &splitfile(1); };
+
+# <@@chapt> - set chapter mode; reduce splitlevel if needed; split file
+$fixref->{rules}->{'^<@@chapt>.*$'} = sub {
+ $splitlevel-- if (!$chapter_mode);
+ $chapter_mode = 1; &splitfile(0);
+};
+
+# <@@label> - Identify label location
+$fixref->{rules}->{'^<@@label>(.*)$'} = sub {
+ $fixref->{lrec}->{$1} = $fixref->{filenum};
+};
+
+#==============================
+# Split the file (-split option; level in parentheses):
+# non-chapter mode: -0 -> don't split
+# -1 -> split at sect (1)
+# -2 -> split at sect (1) and ssect (2)
+# chapter mode: -0 -> split at chapt (0)
+# -1 -> split at chapt (0)
+# -2 -> split at chapt (0) and sect (1)
+sub splitfile
+{
+ my ($level) = @_;
+ if (($level == 0) || ($splitlevel >= $level)) {
+ $fixref->{filenum}++;
+ }
+}
+
+1;
+
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm b/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm
new file mode 100644
index 00000000..9ff2e4cc
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm
@@ -0,0 +1,583 @@
+#
+# Html2Html.pm
+#
+# $Id: Html2Html.pm,v 1.4 2001/08/31 23:09:10 sano Exp $
+#
+# Convert parsed linuxdoc-sgml to html.
+# - Split files; match references, generate TOC and navigation
+# aids, etc.
+#
+# Rules based on html2html.l
+#
+package LinuxDocTools::Html2Html;
+
+use FileHandle;
+use LinuxDocTools::Lang;
+
+# Externally visible variables
+$html2html = {};
+
+# Initialize: set splitlevel, extension, images, filename,
+# filenumber, label, header, footer, toclevel,
+# tmpbase, debug.
+# Usage:
+# &{$html2html->{init}}(split,ext,img,filename,filenum,label,hdr,ftr,toc,tmpbase, debug);
+# split level: 0 - super page mode
+# 1 - big page mode
+# 2 - small page mode
+$html2html->{init} = sub {
+ $splitlevel = shift;
+ SWITCH: {
+ $super_page_mode = 0, $big_page_mode = 1, last SWITCH
+ if ($splitlevel == 1);
+ $super_page_mode = 0, $big_page_mode = 0, last SWITCH
+ if ($splitlevel == 2);
+ }
+
+ $fileext = shift;
+ $use_imgs = shift;
+ $firstname = shift;
+ $filecount = 1 + shift;
+ $lprec = shift;
+
+ $header = shift;
+ $footer = shift;
+
+ $toclevel = shift;
+ if ($toclevel == -1) {
+ if ($splitlevel == 0) {
+ $toclevel = 0;
+ } else {
+ $toclevel = 2;
+ }
+ }
+
+ $tmpbase = shift;
+ $content_file = $tmpbase . ".content";
+
+ $debug = shift;
+
+ $nextlabel = Xlat ("Next");
+ $prevlabel = Xlat ("Previous");
+ $toclabel = Xlat ("Contents");
+};
+
+# Package variables
+$big_page_mode = 0; # '-2' subsection splitting
+$super_page_mode = 1; # One page vs. page/section
+$chapter_mode = 0; # <article> vs. <report>
+$current = ""; # State of section/subsection/etc.
+$filenum = 1; # Current output file number
+$filecount = 1;
+$firstname = "$$"; # Base name for file
+$headbuf = ""; # Buffer for URL's
+$fileext = "html"; # "html" vs. "htm" for 8.3
+$in_appendix = 0; # n.n vs. a.n section numbers
+$in_section_list = 0; # List of sections flag
+$language = ""; # Default English; use '-Lname'
+# $lprec{label} # Label record
+$nextlabel = ""; # Link string
+$outfh = STDOUT; # Output filehandle
+$outname = ""; # Output file name
+$prevlabel = ""; # Link string
+$refname = ""; # Ref string
+$sectname = ""; # Section name
+$secnr = 0; # Section count
+$ssectname = ""; # Subsection name
+$ssecnr = 0; # Subsection count
+$skipnewline = 0; # Flag to ignore new line
+$toclabel = ""; # Link string
+$titlename = ""; # Title of document
+$use_imgs = 0; # '-img' pictorial links
+$urlname = ""; # Name for url links
+$header = "";
+$footer = "";
+$toclevel = -1;
+$tmpbase = "/tmp/sgmltmp" . $$;
+$debug = 0;
+$content_file = $tmpbase . ".content.init";
+
+# Ruleset
+$html2html->{rules} = {}; # Individual parsing rules
+
+$html2html->{rules}->{'^<@@appendix>.*$'} = sub {
+ $in_appendix = 1; $secnr = 0; $ssecnr = 0;
+};
+
+$html2html->{rules}->{'^<@@url>(.*)$'} = sub {
+ $skipnewline = 1; $urlname = $1; $headbuf = qq(<A HREF="$1">);
+};
+
+$html2html->{rules}->{'^<@@urlnam>(.*)$'} = sub {
+ $headbuf = $headbuf . "$urlname</A>";
+};
+
+$html2html->{rules}->{'^<@@endurl>.*$'} = sub {
+ $skipnewline = -1; $outfh->print($headbuf); $headbuf = "";
+};
+
+$html2html->{rules}->{'^<@@title>(.*)$'} = sub {
+ $titlename = $1; &heading(STDOUT); print(STDOUT "<H1>$1</H1>\n\n");
+};
+
+$html2html->{rules}->{'^<@@head>(.*)$'} = sub {
+ $skipnewline = 1; $headbuf = $1;
+};
+
+$html2html->{rules}->{'^<@@part>.*$'} = sub { $current = "PART"; };
+
+$html2html->{rules}->{'^<@@endhead>.*$'} = sub {
+ SWITCH: {
+ $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH
+ if ($current eq "PART");
+ $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH
+ if ($current eq "CHAPTER");
+ $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH
+ if ($current eq "SECTION");
+ $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH
+ if ($current eq "SUBSECT");
+ $outfh->print("<H3>$headbuf</H3>\n\n"), last SWITCH;
+ }
+ $current = ""; $headbuf = ""; $skipnewline = 0;
+};
+
+$html2html->{rules}->{'^<@@chapt>(.*)$'} = sub {
+ $chapter_mode = 1; $skipnewline = 1; $sectname = $1;
+ &start_chapter($sectname);
+};
+
+$html2html->{rules}->{'^<@@sect>(.*)$'} = sub {
+ $skipnewline = 1; $ssectname = $1;
+ if ($chapter_mode) {
+ &start_section($ssectname);
+ } else {
+ $sectname = $ssectname; &start_chapter($ssectname);
+ }
+};
+
+$html2html->{rules}->{'^<@@ssect>(.*)$'} = sub {
+ $skipnewline = 1; $ssectname = $1;
+ if (!$chapter_mode) {
+ &start_section($ssectname);
+ } else {
+ $current = ""; $headbuf = $ssectname;
+ }
+};
+
+$html2html->{rules}->{'^<@@endchapt>.*$'} = sub {
+ STDOUT->print("</UL>\n") if ($in_section_list);
+ if ($outfh->fileno != STDOUT->fileno) {
+ &footing($outfh) if (!$super_page_mode);
+ $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@endsect>.*$'} = sub {
+ STDOUT->print("</UL>\n") if (!$chapter_mode && $in_section_list);
+ if (($outfh->fileno != STDOUT->fileno)
+ && ((!$chapter_mode) || (!$big_page_mode))) {
+ &footing($outfh) if (!$super_page_mode);
+ $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@endssect>.*$'} = sub {
+ if (($outfh->fileno != STDOUT->fileno)
+ && (!$chapter_mode) && (!$big_page_mode) && (!$super_page_mode)) {
+ &footing($outfh); $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@enddoc>.*$'} = sub { };
+
+$html2html->{rules}->{'^<@@label>(.*)$'} = sub {
+ if (!defined($lprec->{$1})) {
+ STDERR->print(qq(html2html: Problem with label "$1"\n)); next;
+ }
+ if ($skipnewline) {
+ $headbuf = sprintf(qq(<A NAME="%s"></A> %s), $1, $headbuf);
+ } else {
+ $outfh->print(qq(<A NAME="$1"></A> ));
+ }
+};
+
+$html2html->{rules}->{'^<@@ref>(.*)$'} = sub {
+ my $tmp;
+
+ $refname = $1;
+ if (!defined($lprec->{$1})) {
+ STDERR->print(qq(html2html: Problem with ref "$1"\n));
+ $skipnewline++; next;
+ }
+ SWITCH: {
+ $tmp = qq(<A HREF="#$1">), last SWITCH
+ if ($lprec->{$1} == $filenum - 1);
+ $tmp = qq(<A HREF="$firstname.$fileext#$1">), last SWITCH
+ if ($lprec->{$1} == 0);
+ $tmp = qq(<A HREF="$firstname-$lprec->{$1}.$fileext#$1">),
+ last SWITCH;
+ }
+ if ($skipnewline) {
+ $headbuf = "$headbuf$tmp";
+ } else {
+ $headbuf = $tmp;
+ }
+ $skipnewline++;
+};
+
+$html2html->{rules}->{'^<@@refnam>.*$'} = sub {
+ $headbuf = "$headbuf$refname</A>\n";
+};
+
+$html2html->{rules}->{'^<@@endref>.*$'} = sub {
+ if ($skipnewline == 1) {
+ $outfh->print($headbuf); $skipnewline = -1;
+ } elsif ($skipnewline == 2) {
+ $skipnewline--;
+ } else {
+ STDERR->print("html2html: Problem with endref\n");
+ $skipnewline--;
+ }
+};
+
+# Default parsing rule
+$html2html->{defaultrule} = sub {
+ $skipnewline++ if ($skipnewline < 0);
+ if ($skipnewline) {
+ chop; $headbuf = "$headbuf$_";
+ } else {
+ $outfh->print($_);
+ }
+};
+
+# Finalize parsing process
+$html2html->{finish} = sub {
+ # Finish footers
+ if ($outfh->fileno != STDOUT->fileno) {
+ if (!$super_page_mode) {
+ &footing($outfh);
+ $outfh->close;
+ }
+ }
+ #
+ if ($super_page_mode) {
+ if ($toclevel > 0) { STDOUT->print("\n<HR>\n"); }
+ $outfh->close if ($outfh->fileno != STDOUT->fileno);
+ if ( -r $content_file ) {
+ open CONTENT, "<$content_file"
+ or die "Can't open content file\n";
+ while (<CONTENT>) {
+ STDOUT->print($_);
+ }
+ close CONTENT;
+ unlink $content_file if (! $debug);
+ }
+ }
+ # Finish the TOC; ensure "next" points to the first page.
+ &browse_links(STDOUT, 1, 0) if (!$super_page_mode);
+ #
+ # add Footer
+ if ( -r "$footer" ) {
+ open FTRFILE, "<$footer" or die "Cannot open footer file\n";
+ while (<FTRFILE>) {
+ STDOUT->print($_);
+ }
+ close FTRFILE;
+ } else {
+ STDOUT->print("</BODY>\n</HTML>\n");
+ }
+};
+
+
+###################################################################
+# Secondary Functions
+###################################################################
+
+# Print standard links
+sub browse_links {
+ my ($outfh, $myfilenum, $top) = @_;
+
+ return if ($super_page_mode);
+
+ $outfh->print("<HR>\n") unless ($top);
+
+ # NOTE: For pages where a next or prev button isn't appropriate, include
+ # the graphic anyway - just don't make it a link. That way, the mouse
+ # position of each button is unchanged from page to page.
+ # Use the passed myfilenum since filenum may already be incremented
+
+ # Next link (first)
+ my $next = $use_imgs
+ ? qq(<IMG SRC="next.png" ALT="$nextlabel">)
+ : qq($nextlabel);
+ $next = qq(<A HREF="$firstname-$myfilenum.$fileext">$next</A>)
+ if ($myfilenum < $filecount);
+ $next = join "", $next, "\n";
+ $outfh->print($next);
+
+ # Previous link
+ my $prev = $use_imgs
+ ? qq(<IMG SRC="prev.png" ALT="$prevlabel">)
+ : qq($prevlabel);
+ $prev = join "", qq(<A HREF="$firstname-), ($myfilenum - 2),
+ qq(.$fileext">$prev</A>)
+ if ($myfilenum >= 3);
+ $prev = join "", $prev, "\n";
+ $outfh->print($prev);
+
+ # Table of contents link
+ my $toc = $use_imgs
+ ? qq(<IMG SRC="toc.png" ALT="$toclabel">)
+ : qq($toclabel);
+ $toc = join "", qq(<A HREF="$firstname.$fileext#toc),
+ &section_num($secnr, 0), qq(">$toc</A>)
+ if ($outfh->fileno != STDOUT->fileno);
+ $toc = join "", $toc, "\n";
+ $outfh->print($toc);
+
+ print($outfh "<HR>\n") if ($top);
+}
+
+# Print end-of-file markup
+sub footing {
+ my $outfh = shift;
+ &browse_links($outfh, $filenum, 0);
+ if ( -r "$footer" ) {
+ open FTRFILE, "<$footer" or die "Cannot open footer file\n";
+ while (<FTRFILE>) {
+ $outfh->print($_);
+ }
+ close FTRFILE;
+ } else {
+ $outfh->print("</BODY>\n</HTML>\n");
+ }
+}
+
+# Print top-of-file markup
+sub heading {
+ my $outfh = shift; my $match;
+
+ # Emit 3.2 HTML until somebody comes up with a better idea - CdG
+ if ( -r "$header" ) {
+ open HDRFILE, "<$header" or die "Cannot open header file\n";
+ while (<HDRFILE>) {
+ $outfh->print($_);
+ }
+ close HDRFILE;
+ } else {
+ $outfh->print(
+ qq(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n));
+ $outfh->print("<HTML>\n<HEAD>\n");
+ }
+ open VERSFILE, "<$main::DataDir/VERSION" or die "Cannot open version file\n";
+ $version = <VERSFILE>;
+ close VERSFILE;
+ chop $version;
+ $outfh->print(
+ " <META NAME=\"GENERATOR\" CONTENT=\"LinuxDoc-Tools $version\">\n");
+
+ $outfh->print(" <TITLE>");
+ $match = $titlename;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print($match);
+ if ($secnr > 0) {
+ $match = $sectname;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print(": $match");
+ }
+ if ($ssecnr > 0) {
+ $match = $ssectname;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print(": $match");
+ }
+ $outfh->print("</TITLE>\n");
+
+ if (!$super_page_mode) {
+ #
+ # <LINK> Information for next, previous, contents, etc...
+ #
+ $outfh->print(qq( <LINK HREF="$firstname-$filenum.$fileext" REL=next>),"\n")
+ if ($filenum < $filecount);
+ my $prev;
+ $prev = join "", qq( <LINK HREF="$firstname-), ($filenum - 2),
+ qq(.$fileext" REL=previous>)
+ if ($filenum >= 3);
+ $outfh->print($prev,"\n");
+
+ #
+ # Table of contents link
+ #
+ my $toc ;
+ $toc = join "", qq( <LINK HREF="$firstname.$fileext#toc),
+ &section_num($secnr, 0), qq(" REL=contents>)
+ if ($outfh->fileno != STDOUT->fileno);
+ $outfh->print($toc,"\n");
+ } # (!$super_page_mode)
+
+ $outfh->print("</HEAD>\n<BODY>\n");
+ &browse_links($outfh, $filenum, 1);
+}
+
+# Return the section and subsection as a dotted string
+sub section_num {
+ my ($sec, $ssec) = @_;
+ my $l = "A";
+
+ if ($in_appendix) {
+ $sec--;
+ while ($sec) { $l++; $sec--; }
+ return("$l.$ssec") if ($ssec > 0);
+ return("$l");
+ } else {
+ return("$sec.$ssec") if ($ssec > 0);
+ return("$sec");
+ }
+}
+
+# Create a chapter head; start a new file, etc.
+sub start_chapter {
+ my $sectname = shift;
+
+ if (!$super_page_mode && $outfh->fileno != STDOUT->fileno) {
+ &footing($outfh); $outfh->close;
+ }
+ $current = "SECTION"; $secnr++; $ssecnr = 0;
+ if ($super_page_mode) {
+ $outname = $content_file;
+ $outfh = new FileHandle ">>$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ if ($toclevel > 0) {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s.</A> <A HREF="#toc%s">%s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ &section_num($secnr, 0),
+ $sectname);
+ STDOUT->printf(
+ qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s#s%s">%s</A></H2>\n\n),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ "$firstname.$fileext", &section_num($secnr, 0), $sectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s. %s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $sectname);
+ }
+ } else {
+ $outname = "$firstname-$filenum.$fileext"; $filenum++;
+ $outfh = new FileHandle ">$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ &heading($outfh);
+ if ($toclevel > 0) {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s.</A> <A HREF="%s#toc%s">%s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ "$firstname.$fileext", &section_num($secnr, 0),
+ $sectname);
+ STDOUT->printf(
+ qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s">%s</A></H2>\n\n),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $outname, $sectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s. %s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $sectname);
+ }
+ }
+ $in_section_list = 0;
+}
+
+# Create a section; start a new file, etc.
+sub start_section {
+ my $ssectname = shift;
+
+ $current = "SUBSECT"; $ssecnr++;
+ if ($toclevel > 1) {
+ if (!$in_section_list) {
+ STDOUT->print("<UL>\n"); $in_section_list = 1;
+ }
+ }
+ if ($super_page_mode) {
+ if ($outfh->fileno != STDOUT->fileno && !$chapter_mode) {
+ $outfh->close;
+ }
+ $outname = $content_file;
+ $outfh = new FileHandle ">>$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ if ($toclevel > 1) {
+ $headbuf = sprintf(qq(<A NAME="ss%s">%s</A> <A HREF="#toc%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ } else {
+ $headbuf = sprintf(qq(<A NAME="ss%s">%s %s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ } else {
+ if (!$big_page_mode) {
+ if ($outfh->fileno != STDOUT->fileno) {
+ &footing($outfh); $outfh->close;
+ }
+ $outname = "$firstname-$filenum.$fileext"; $filenum++;
+ $outfh = new FileHandle ">$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ heading($outfh);
+
+ # Since only one section is on any page,
+ # don't use # so that when we
+ # jump to this page, we see the browse
+ # links at the top of the page.
+ if ($toclevel > 1) {
+ $headbuf = sprintf("%s <A HREF=\"%s#toc%s\">%s</A>",
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $outname, $ssectname);
+ } else {
+ $headbuf = sprintf("%s %s</A>",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ } else {
+ # Since many sections are on one page, we need to use #
+ if ($toclevel > 1) {
+ $headbuf = sprintf(
+ qq(<A NAME="ss%s">%s</A> <A HREF="%s#toc%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $outname,
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="ss%s">%s %s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ }
+ }
+}
+
diff --git a/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm b/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm
new file mode 100644
index 00000000..b4bd50bd
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm
@@ -0,0 +1,357 @@
+# InfoUtils.pm
+#
+# Some utils for the linuxdoc info backend.
+#
+# * Create menus
+# * Normalize node names and associated text
+# * Point references to the associated node as needed
+#
+# Copyright (C) 2009 Agustín Martín Domingo, agmartin at debian org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# --------------------------------------------------------------------
+
+
+package LinuxDocTools::InfoUtils;
+
+use base qw(Exporter);
+
+# List all exported symbols here.
+our @EXPORT_OK = qw(info_process_texi);
+
+# Import :all to get everything.
+our %EXPORT_TAGS = (all => [@EXPORT_OK]);
+
+=head1 NAME
+
+ InfoUtils - Some utils for the linuxdoc info backend.
+
+=head1 SYNOPSIS
+
+use InfoUtils q{:all};
+
+info_process_texi($infile, $outfile, $infoname)
+
+=head1 DESCRIPTION
+
+This module contains some utils to process the raw texinfo file
+creating menus, normalizing node names and associated text and
+pointing references to the associated node as needed.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+# -------------------------------------------------------------------------
+sub info_normalize_node_text {
+# -------------------------------------------------------------------------
+# Filter characters not allowed in section names
+# -------------------------------------------------------------------------
+ my $text = shift;
+
+ $text =~ s/\s+/ /g;
+ $text =~ s/\@[A-Za-z][A-Za-z0-9]*//g;
+ $text =~ s/(\{|\})//g;
+ $text =~ s/\,//g;
+# $text =~ s/\.+$//g;
+ $text =~ s/\./-/g;
+ $text =~ s/\s+$//g;
+
+ return $text;
+}
+
+# -------------------------------------------------------------------------
+sub info_normalize_node_name {
+# -------------------------------------------------------------------------
+# Filter characters not allowed in node names. Previous filtering of
+# characters not allowed in section names is supposed.
+# -------------------------------------------------------------------------
+ my $text = shift;
+# my $tmpnodedata = shift;
+
+ $text =~ s/\://g;
+ $text =~ s/\;//g;
+
+# die "Error: Reference \"$text\" already used"
+# if defined $tmpnodedata->{$text};
+
+ return $text;
+}
+
+# -------------------------------------------------------------------------
+sub info_parse_raw_file {
+# -------------------------------------------------------------------------
+# Parse raw texinfo file. It does not yet contain section names, menus,
+# correct references or title.
+# -------------------------------------------------------------------------
+ my $inputfile = shift;
+ my $INPUT;
+
+ my @inputtext = (); # Copy of input file with some preprocessing
+ my %nodedata = # A hash of hashes with all node info
+ ( 'Top' =>
+ { 'text' => "Top",
+ 'depth' => 0,
+ 'up' => "",
+ 'next' => '',
+ 'previous' => "",
+ 'sort' => 0,
+ 'debug' => "",
+ 'menu' => []}
+ );
+
+ my %levellast = (0 => "Top");
+ my %labels = ();
+ my %docdata = # Some misc data for the document
+ ( 'title' => "",
+ 'author' => "",
+ 'subtitle' => ""
+ );
+
+ my $depth = my $lastdepth = 0;
+ my $lastnode = "";
+ my $sort = 0;
+
+ my $inauthor;
+ my $authorline;
+
+ open ($INPUT, "< $inputfile")
+ or die "info-postASP: Could not open $inputfile for read. Aborting ...\n";
+
+ while (<$INPUT>){
+ chomp;
+ if ( s/^\@SUB\s+// ){
+ my $updepth = $depth;
+ my $uppernode = $levellast{$updepth};
+ $depth++;
+ $sort++;
+
+ my @levelmenu = ();
+
+ if ( defined $nodedata{$uppernode}->{'menu'} ){
+ @levelmenu = @{ $nodedata{$uppernode}->{'menu'} };
+ }
+
+ my $nodetext = info_normalize_node_text($_);
+ my $nodename = info_normalize_node_name($nodetext,\%nodedata);
+
+ # Make first appearing node the next node for top node
+ $nodedata{'Top'}->{'next'} = $nodename if ( $lastdepth eq 0);
+
+ # Fill info for current node (and 'next' for last one in level)
+ $nodedata{$nodename}->{'orig'} = $_;
+ $nodedata{$nodename}->{'text'} = $nodetext;
+ $nodedata{$nodename}->{'depth'} = $depth;
+ $nodedata{$nodename}->{'previous'} =
+ defined $levellast{$depth} ? $levellast{$depth} : "";
+ $nodedata{$levellast{$depth}}->{'next'} = $nodename
+ if defined $levellast{$depth};
+ $nodedata{$nodename}->{'up'} = $uppernode;
+ $nodedata{$nodename}->{'sort'} = $sort;
+ $nodedata{$nodename}->{'debug'} =
+ "updepth: $updepth, lastdepth: $lastdepth, up: $uppernode";
+
+ # Keep this defined in case tbere is no next node in the same level.
+ $nodedata{$nodename}->{'next'} = "";
+
+ push @inputtext, "\@SUB $nodename"; # Rewrite @SUB with the new name
+ push @levelmenu, $nodename; # Add $nodename to the level menu list
+
+ # Prepare things for next @SUB entry found
+ $levellast{$depth} = $lastnode = $nodename;
+ $lastdepth = $depth;
+ $nodedata{$uppernode}->{'menu'} = \@levelmenu;
+
+ } elsif ( s/^\@ENDSUB// ){
+ $depth--;
+ push @inputtext, $_;
+ } elsif (s/^\@LABEL\s+//){
+ # Keep record of node labels vs nodenames. Will use the last.
+ $labels{$_} = $lastnode;
+ } elsif (s/^\@title\s+//){
+ $docdata{'title'} = $_;
+ } elsif (/^\@ldt_endauthor/){
+ $inauthor = '';
+ my @authors;
+ if ( @$docdata{'authors'} ){
+ @authors = @$docdata{'authors'};
+ }
+ push @authors, $authorline;
+ $docdata{'authors'} = \@authors;
+ $authorline = "";
+ } elsif ( s/^\@author\s+// ){
+ $inauthor = 1;
+ $authorline = $_;
+ } elsif ( $inauthor ){
+ next if m/^\s*$/;
+ s/^\s+//;
+ $authorline .= " $_ ";
+ } elsif (s/^\@subtitle\s+//){
+ $docdata{'subtitle'} = $_;
+ } elsif (s/^\@ldt_translator\s+//){
+ $docdata{'translator'} = $_;
+ } elsif (s/^\@ldt_tdate\s+//){
+ $docdata{'tdate'} = $_;
+ } else {
+ push @inputtext, $_;
+ }
+ }
+ close $INPUT;
+
+ $docdata{'nodedata'} = \%nodedata;
+ $docdata{'labels'} = \%labels;
+ $docdata{'inputtext'} = \@inputtext;
+
+ return \%docdata;
+}
+
+# -------------------------------------------------------------------------
+sub info_write_preprocessed_file {
+# -------------------------------------------------------------------------
+# Write processed texinfo file. Add section names, menus, correct
+# references and title.
+# -------------------------------------------------------------------------
+ my $docdata = shift;
+ my $infoname = shift;
+ my $texiout = shift;
+
+ die "InfoUtils.pm: No info file name $infoname.\n" unless $infoname;
+ die "InfoUtils.pm: No output texi file $texiout\n" unless $texiout;
+
+ my $nodedata = $docdata->{'nodedata'};
+ my $labels = $docdata->{'labels'};
+ my $inputtext = $docdata->{'inputtext'};
+
+ my $OUTFILE;
+
+ # info_check_parsed_data($nodedata);
+
+ my %sections = ( 1 => "\@chapter",
+ 2 => "\@section",
+ 3 => "\@subsection",
+ 4 => "\@subsubsection");
+
+ my $lastdepth = 0;
+ my $lastnode = "Top";
+ my $texinfo = "\@c %** START OF HEADER
+\@setfilename $infoname
+\@c %** END OF HEADER\n";
+
+ foreach ( @$inputtext ) {
+ if ( s/^\@SUB\s+// ){
+ my $key = $_;
+ my $depth = $nodedata->{$key}->{'depth'};
+ my $name = $nodedata->{$key}->{'text'};
+
+ if ( $depth le 4 ){
+ my $next = $nodedata->{$key}->{'next'};
+ my $previous = $nodedata->{$key}->{'previous'};
+ my $up = $nodedata->{$key}->{'up'};
+ # my $txt = "\@comment nodename, next, previous, up\n";
+ my $txt = "";
+
+ # $txt .= "\@node $key, $previous, $next, $up\n";
+ $txt .= "\@node $key\n";
+ $txt .= "$sections{$depth} $name\n";
+
+ if ( $depth gt $lastdepth && defined $nodedata->{$lastnode}->{'menu'}){
+ $txt = "\n\@menu\n\* "
+ . join("::\n\* ",@{$nodedata->{$lastnode}->{'menu'}})
+ . "::\n\@end menu\n"
+ . "\n$txt";
+ }
+
+ $texinfo .= $txt;
+ $lastdepth = $depth;
+ $lastnode = $key;
+ } elsif ( $depth eq 5 ){
+ $texinfo .= "\@subsubheading $nodedata->{$key}->{'text'}\n";
+ } else {
+ die "info-postASP: Entry \"$key\" has wrong depth $depth\n";
+ }
+ } elsif (s/^\@REF\s+//){
+ if ( defined $labels->{$_} ){
+ # If this reference is to a node, use its nodename
+ $texinfo .= "\@ref{" . $labels->{$_} . "}\n";
+ } else {
+ $texinfo .= "\@ref{$_}\n";
+ }
+ } elsif (s/^\@TOP//){
+ $texinfo .= "\@node top\n"
+ . "\@top " . $docdata->{'title'} . "\n"
+ . "\@example\n";
+
+ $texinfo .= join(' and ',@{$docdata->{'authors'}}) . "\n"
+ if ( @{$docdata->{'authors'}} );
+
+ $texinfo .= $docdata->{'subtitle'} . "\n"
+ if ( defined $docdata->{'subtitle'} );
+
+ $texinfo .= $docdata->{'translator'} . "\n"
+ if ( defined $docdata->{'translator'} );
+
+ $texinfo .= $docdata->{'tdate'} . "\n"
+ if ( defined $docdata->{'tdate'} );
+
+ $texinfo .= "\@end example\n";
+ } else {
+ $texinfo .= "$_\n";
+ }
+ }
+
+ open ($OUTFILE, "> $texiout")
+ or die "Could not open \"$texiout\" for write. Aborting ...\n";
+ print $OUTFILE $texinfo;
+ close $OUTFILE;
+}
+
+# -------------------------------------------------------------------------
+sub info_check_parsed_data {
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+ my $tmpnodedata = shift;
+ my @sections = sort {
+ $tmpnodedata->{$a}->{'sort'} <=> $tmpnodedata->{$b}->{'sort'}
+ } keys %$tmpnodedata;
+
+ foreach ( @sections ){
+ my $ref = $tmpnodedata->{$_};
+ print STDERR "Node: $_\n";
+ print STDERR " orig: $ref->{'orig'}\n";
+ print STDERR " text: $ref->{'text'}\n";
+ print STDERR " debug: $ref->{'debug'}\n";
+ print STDERR " up: $ref->{'up'}\n";
+ print STDERR " depth: $ref->{'depth'}\n";
+ print STDERR " previous: $ref->{'previous'}\n";
+ print STDERR " next: $ref->{'next'}\n";
+ print STDERR " sort: $ref->{'sort'}\n";
+ print STDERR " menu:\n * " . join("\n * ",@{$ref->{'menu'}}) . "\n" if defined $ref->{'menu'};
+ }
+}
+
+# -------------------------------------------------------------------------
+sub info_process_texi {
+# -------------------------------------------------------------------------
+# info_process_texi($infile, $outfile, $infoname)
+#
+# Call the other functions.
+# -------------------------------------------------------------------------
+ my $infile = shift;
+ my $outfile = shift;
+ my $infoname = shift;
+
+ info_write_preprocessed_file(info_parse_raw_file($infile),$infoname,$outfile);
+}
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Lang.pm b/tools/linuxdoc-tools/LinuxDocTools/Lang.pm
new file mode 100644
index 00000000..2b0e99d6
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Lang.pm
@@ -0,0 +1,238 @@
+#
+# Lang.pm
+#
+# $Id: Lang.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Language support.
+#
+# © Copyright 1997, Cees de Groot
+#
+
+package LinuxDocTools::Lang;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @Languages $translations);
+
+require 5.0004;
+use Exporter;
+use LinuxDocTools::Vars;
+
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+@ISA = qw(Exporter);
+@EXPORT = qw(Any2ISO ISO2Native ISO2English Xlat);
+
+=head1 NAME
+
+LinuxDocTools::Lang - language name and translation functions
+
+=head1 SYNOPSIS
+
+ $isoname = Any2ISO ('deutsch');
+ $native = ISO2Native ('de');
+ $engname = ISO2English ('nederlands');
+
+ $global->{language} = 'nl';
+ $dutch = Xlat ('Table of Contents');
+
+=head1 DESCRIPTION
+
+B<LinuxDocTools::Lang> gives a simple interface to various forms of language
+names, and provides a translation service. Languages can be specified in
+three different ways: by their native name, by their english name, and
+by their 2-letter ISO code. For example, you can specify the German
+language as C<deutsch>, as C<german> or as C<de>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+@Languages = qw(
+ en english english
+ de deutsch german
+ nl nederlands dutch
+ fr français french
+ es español spanish
+ da dansk danish
+ no norsk norwegian
+ se svenska swedish
+ pt portuges portuguese
+ ca català catalan
+ it italiano italian
+ ro românã romanian
+ ja japanese japanese
+ pl polski polish
+ ko korean korean
+ fi suomi finnish
+);
+
+
+=item Any2ISO
+
+Maps any of the three forms of languages to the ISO name. So either of
+these invocations:
+
+ Any2ISO ('dutch');
+ Any2ISO ('nederlands');
+ Any2ISO ('nl');
+
+will return the string C<"nl">.
+
+=cut
+
+sub Any2ISO
+{
+ my $lang = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $lang) && last;
+ $i++;
+ }
+ return $Languages[(int $i / 3) * 3];
+}
+
+
+=item ISO2Native
+
+Maps the ISO code to the native name of the language.
+
+=cut
+
+sub ISO2Native
+{
+ my $iso = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $iso) && last;
+ $i++;
+ }
+ return $Languages[$i + 1];
+
+}
+
+
+=item ISO2English
+
+Maps the ISO code to the english name of the language.
+
+=cut
+
+sub ISO2English
+{
+ my $iso = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $iso) && last;
+ $i++;
+ }
+ return $Languages[$i + 2];
+}
+
+=item Xlat
+
+Translates its (English) argument to the language specified by the
+current value of C<$gobal-E<gt>{language}>. The module, in its source
+file, contains a data structure, indexed by the English strings, that
+has all available translations.
+
+=cut
+
+sub Xlat
+{
+ my ($txt) = @_;
+
+ return $txt if ($global->{language} eq "en");
+ return $translations->{$txt}{$global->{language}};
+};
+
+
+#
+# By the time this grows big, we'll make up something else.
+#
+$translations = {
+ "Previous" => {
+ "nl" => "Terug",
+ "de" => "Zurück",
+ "es" => "Página anterior",
+ "fr" => "Page précédente",
+ "da" => "Forrige",
+ "no" => "Forrige",
+ "se" => "Föregående",
+ "pt" => "Página anterior",
+ "ca" => "Pàgina anterior",
+ "it" => "Indietro",
+ "ro" => "Înapoi",
+ "ja" => "Á°¤Î¥Ú¡¼¥¸",
+ "pl" => "Poprzedni",
+ "ko" => "ÀÌÀü",
+ "fi" => "Edellinen"
+ },
+ "Next" => {
+ "nl" => "Verder",
+ "de" => "Weiter",
+ "es" => "Página siguiente",
+ "fr" => "Page suivante",
+ "da" => "Næste",
+ "no" => "Neste",
+ "se" => "Nästa",
+ "pt" => "Página seguinte",
+ "ca" => "Pàgina següent",
+ "it" => "Avanti",
+ "ro" => "Înainte",
+ "ja" => "¼¡¤Î¥Ú¡¼¥¸",
+ "pl" => "Nastny",
+ "ko" => "´ÙÀ½",
+ "fi" => "Seuraava"
+ },
+ "Contents" => {
+ "nl" => "Inhoud",
+ "de" => "Inhalt",
+ "es" => "Índice general",
+ "fr" => "Table des matières",
+ "da" => "Indhold",
+ "no" => "Innhold",
+ "se" => "Innehållsförteckning",
+ "pt" => "Índice",
+ "ca" => "Índex",
+ "it" => "Indice",
+ "ro" => "Cuprins",
+ "ja" => "Ìܼ¡¤Ø",
+ "pl" => "Spis Trei",
+ "ko" => "Â÷·Ê",
+ "fi" => "Sisällys"
+ },
+ "Table of Contents" => {
+ "nl" => "Inhoudsopgave",
+ "de" => "Inhaltsverzeichnis",
+ "es" => "Índice general",
+ "fr" => "Table des matières",
+ "da" => "Indholdsfortegnelse",
+ "no" => "Innholdsfortegnelse",
+ "se" => "Innehållsförteckning",
+ "pt" => "Índice geral",
+ "ca" => "Índex general",
+ "it" => "Indice Generale",
+ "ro" => "Cuprins",
+ "ja" => "Ìܼ¡",
+ "pl" => "Spis Trei",
+ "ko" => "Â÷·Ê",
+ "fi" => "Sisällysluettelo"
+ }
+};
+
+=back
+
+=head1 AUTHOR
+
+Cees de Groot, C<E<lt>cg@pobox.comE<gt>>
+
+=cut
+
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Utils.pm b/tools/linuxdoc-tools/LinuxDocTools/Utils.pm
new file mode 100644
index 00000000..63fe5f91
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Utils.pm
@@ -0,0 +1,392 @@
+#
+# Utils.pm
+#
+# $Id: Utils.pm,v 1.2 2001/08/31 22:39:44 sano Exp $
+#
+# Utilities, split off from other modules in order to cut down file size.
+#
+# © Copyright 1996, 1997, Cees de Groot
+#
+package LinuxDocTools::Utils;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools::Utils - various supporting routines
+
+=head1 SYNOPSIS
+
+ @files = process_options (@args);
+
+ usage ($msg);
+
+ trap_signals;
+
+ cleanup;
+
+ create_temp($tempfile)
+
+=head1 DESCRIPTION
+
+The B<LinuxDocTools::Utils> module contains a number of generic routines, mainly
+split off from the main module in order to keep file size down.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use DirHandle;
+use FileHandle;
+use Cwd;
+use File::Basename;
+use Exporter;
+use LinuxDocTools::Vars;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $in_signal);
+@ISA = qw(Exporter);
+@EXPORT = qw(usage process_options);
+@EXPORT_OK = qw(cleanup trap_signals remove_tmpfiles create_temp);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
+
+use subs qw(usage);
+
+# check whether options are unique
+sub check_option_consistency
+{
+ my $owner = {};
+ my ($fmt, $opt);
+ foreach $fmt (keys %FmtList)
+ {
+ my $add = sub { # add to options of $fmt
+ my $str = shift;
+ if ($owner->{$str}) {
+ push(@{$owner->{$str}}, $fmt);
+ }
+ else {
+ $owner->{$str} = [$fmt];
+ }
+ };
+ foreach $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ &$add("--$opt->{option}");
+ &$add("-$opt->{short}");
+ }
+ }
+ my $error = 0;
+ foreach $opt (keys %$owner)
+ {
+ if (scalar @{$owner->{$opt}} > 1)
+ {
+ warn "duplicate option: $opt in " .
+ join(', ', @{$owner->{$opt}}) . "\n";
+ $error = 1;
+ }
+ }
+ die "Internal error detected" if $error;
+}
+
+
+=item process_options
+
+This function processes the command line, and sets the variables associated
+with the options along the way. When successful, it returns the arguments
+on the command line it didn't interpret. Normally, this will be a list of
+filenames.
+
+=cut
+
+sub process_options
+{
+ my @args = @_;
+ my @retval;
+
+ OPTPROC: while ($args[0])
+ {
+ my $long;
+ my $curarg = $args[0];
+ if ($curarg =~ /^--.*/)
+ {
+ #
+ # Long option, --opt[==value]
+ #
+ $long = 1;
+ }
+ elsif ($curarg =~ /^-.*/)
+ {
+ #
+ # Short option, -o value
+ #
+ $long = 0;
+ }
+ else
+ {
+ #
+ # Filename
+ #
+ push @retval, $curarg;
+ next OPTPROC;
+ }
+
+ #
+ # Start looking for the option
+ #
+ foreach my $fmt (keys %FmtList)
+ {
+ foreach my $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ if (($long && $curarg =~ /^--$opt->{option}.*/) ||
+ $curarg =~ /^-$opt->{short}/)
+ {
+ #
+ # Found it! Get the argument and see whether all is OK
+ # with the option.
+ #
+ my $optval = "";
+ if ($long)
+ {
+ if ($curarg =~ /^--$opt->{option}=.*/)
+ {
+ $optval = $curarg;
+ $optval =~ s/[^=]*=(.*)/$1/;
+ }
+ }
+ else
+ {
+ if ($args[1] =~ /^[^-].*/)
+ {
+ $optval = $args[1];
+ }
+ }
+ $opt->{type} eq "f" && do
+ {
+ #
+ # "f" -> flag. Increment, so '-v -v' can work.
+ #
+ $Formats{$fmt}{$opt->{option}} += 1;
+ next OPTPROC;
+ };
+ #
+ # All other types require a value (for now).
+ #
+ shift @args unless $long;
+ if ($optval eq "")
+ {
+ usage "Option $curarg: value required";
+ }
+ ($opt->{type} eq "i" || $opt->{type} eq "s") && do
+ {
+ #
+ # "i" -> numeric value.
+ # "s" -> string value.
+ #
+ # No type checking yet...
+ #
+ if ($opt->{option} eq "define")
+ {
+ $Formats{$fmt}{$opt->{option}} .= " " . $optval;
+ }
+ else
+ {
+ $Formats{$fmt}{$opt->{option}} = $optval;
+ }
+ next OPTPROC;
+ };
+ $opt->{type} eq "l" && do
+ {
+ #
+ # "l" -> list of values.
+ #
+ foreach my $val (@{$opt->{'values'}})
+ {
+ if ($val eq $optval)
+ {
+ $Formats{$fmt}{$opt->{option}} = $optval;
+ next OPTPROC;
+ }
+ }
+ usage "Invalid value '$optval' for '--$opt->{option}'";
+ };
+ usage "Unknown option type $opt->{type} in $fmt/$opt";
+ }
+ }
+ }
+ usage "Unknown option $curarg";
+ }
+ continue
+ {
+ shift @args;
+ }
+ return @retval;
+}
+
+
+=item usage
+
+Prints out a generated help message about calling convention and allowed
+options, then the argument string, and finally exits.
+
+=cut
+
+sub usage
+{
+ my ($msg) = @_;
+
+ print "LinuxDoc-Tools version " . `cat $main::DataDir/VERSION` . "\n";
+ check_option_consistency;
+ print "Usage:\n";
+ print " " . $global->{myname} . " [options] <infile>\n\n";
+ my @helplist = sort(keys %Formats);
+ @helplist = sort (keys %FmtList) if ($global->{format});
+ foreach my $fmt (@helplist)
+ {
+ if ($fmt eq "global")
+ {
+ print "General options:\n";
+ }
+ else
+ {
+ print "Format: " . $fmt . "\n";
+ }
+ print $Formats{$fmt}{HELP};
+ for my $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ my $value = '';
+ if ($opt->{type} eq "i")
+ {
+ $value = "number";
+ }
+ elsif ($opt->{type} eq "l")
+ {
+ $value = "{";
+ my $first = 1;
+ for my $val (@{$opt->{'values'}})
+ {
+ $first || ($value .= ",");
+ $first = 0;
+ $value .= $val;
+ }
+ $value .= "}";
+ }
+ elsif ($opt->{type} eq "s")
+ {
+ $value = "string";
+ }
+ print " --$opt->{option}"; print "=$value" if $value;
+ print " -$opt->{short}"; print " $value" if $value;
+ print "\n";
+ }
+ print "\n";
+ }
+
+ $msg && print "Error: $msg\n\n";
+ exit 1;
+}
+
+
+=item cleanup
+
+This function cleans out all temporary files and exits. The unlink step
+is skipped if debugging is turned on.
+
+=cut
+
+sub cleanup
+{
+ my ($signame) = @_;
+
+ if( $signame ) {
+ if ( $in_signal ) {
+ if( $global->{debug} ) {
+ print STDERR "Caught SIG$signame during cleanup -- aborting\n";
+ }
+ exit -1;
+ }
+ else {
+ if( $global->{debug} ) {
+ print STDERR "Caught SIG$signame -- cleaning up\n";
+ }
+ $in_signal = 1;
+ }
+ }
+
+ if( !$global->{debug} && $global->{tmpbase} ) {
+ remove_tmpfiles($global->{tmpbase});
+ }
+ exit 0;
+}
+
+=item remove_tmpfiles( $tmpbase )
+
+This function cleans out all temporary files, using the argument $tmpbase to
+determine the directory and pattern to use to find the temporary files.
+
+=cut
+
+sub remove_tmpfiles($) {
+ my $tmpbase = shift;
+ my ($name,$tmpdir) = fileparse($tmpbase,"");
+ my $namelength = length $name;
+ my $savdir = cwd;
+
+ chdir($tmpdir);
+ my $dir = new DirHandle(".");
+
+ if (!defined($dir) ) {
+ warn "Couldn't open temp directory $tmpdir: $!\n";
+ } else {
+ foreach my $tmpfile ($dir->read()) {
+ if (substr ($tmpfile, 0, $namelength) eq $name) {
+ unlink ($tmpfile) || warn "Couldn't unlink $tmpfile: $! \n";
+ }
+ }
+ $dir->close();
+ }
+
+ chdir($savdir);
+ rmdir($tmpdir) || return -1;
+}
+
+=item trap_signals
+
+This function traps all known signals, making sure that the B<cleanup>
+function is executed on them. It should be called once at initialization
+time.
+
+=cut
+
+sub trap_signals
+{
+ foreach my $sig ( 'HUP', 'INT', 'QUIT', 'ILL',
+ 'TRAP', 'IOT', 'BUS', 'FPE',
+ 'USR1', 'SEGV', 'USR2',
+ 'PIPE', 'ALRM', 'TERM', )
+ {
+ $SIG{$sig} = \&cleanup;
+ }
+}
+
+=item create_temp ( $tmpfile )
+
+This function creates an empty temporary file with the required
+permission for security reasons.
+
+=cut
+
+sub create_temp($) {
+ my $tmpnam = shift;
+ my $fh = new FileHandle($tmpnam,O_CREAT|O_EXCL|O_WRONLY,0600);
+ $fh or die "$0: failed to create temporary file: $!";
+ $fh->close;
+}
+
+=back
+
+=head1 AUTHOR
+
+Cees de Groot, C<E<lt>cg@pobox.comE<gt>>.
+
+=cut
+
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Vars.pm b/tools/linuxdoc-tools/LinuxDocTools/Vars.pm
new file mode 100644
index 00000000..49cf630b
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Vars.pm
@@ -0,0 +1,22 @@
+#
+# Vars.pm
+#
+# $Id: Vars.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Shared variables.
+#
+# © Copyright 1996, 1997, Cees de Groot
+#
+package LinuxDocTools::Vars;
+use strict;
+
+use Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+@ISA = qw(Exporter);
+@EXPORT = qw(%Formats $global %FmtList);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+
+use vars @EXPORT;
+
+1;
diff --git a/tools/linuxdoc-tools/Text/EntityMap.pm b/tools/linuxdoc-tools/Text/EntityMap.pm
new file mode 100644
index 00000000..d878fa3c
--- /dev/null
+++ b/tools/linuxdoc-tools/Text/EntityMap.pm
@@ -0,0 +1,121 @@
+# -*- perl -*-
+#
+# Copyright (C) 1996 Ken MacLeod
+# See the file COPYING for distribution terms.
+#
+# This file is preprocessed during the build to fix-up the references
+# in `sdata_dirs'.
+#
+# $Id: EntityMap.pm.in,v 1.1.1.1 2001/05/24 15:57:40 sano Exp $
+#
+
+package Text::EntityMap;
+
+use strict;
+
+=head1 NAME
+
+Text::EntityMap - map character entities to output formats
+
+=head1 SYNOPSIS
+
+use Text::EntityMap;
+
+$tex_iso_lat1 = Text::EntityMap->load ("ISOlat1.2tex");
+$tex_iso_lat2 = Text::EntityMap->load ("ISOlat2.2tex");
+$ent_group = Text::EntityMap->group ($tex_iso_lat1, $tex_iso_lat2);
+
+$ent_group->lookup ('[copy ]');
+
+@dirs = Text::EntityMap->sdata_dirs ();
+
+=head1 DESCRIPTION
+
+Text::EntityMap is a module that can look-up an output-format
+equivalent for special character or other entities. This was inspired
+by SGML character entities but can be used in any scenario where
+output formatting codes are different for special characters.
+
+The C<load()> function takes a file name of a mapping table and
+returns an Text::EntityMap object.
+
+The C<group()> function takes a ordered list of Text::EntityMap and
+returns an Text::EntityMapGroup object. Looking up entities in a
+group object returns the entity replacement returned by the first
+EntityMap object. This can be used both to group sets of mapping
+files into one object as well as overriding entity replacements. A
+EntityMapGroup may contain other EntityMapGroup's.
+
+The C<lookup()> function can be used with either a EntityMap or
+EntityMapGroup object. It takes an entity name and returns the
+output-format equivalent.
+
+C<sdata_dirs()> returns an array containing the local site directory
+and ``this'' version of EntityMap's installed directory that contain
+the entity maps. Callers can use these paths when looking for tables
+to pass to C<load()>.
+
+=head1 AUTHOR
+
+Ken MacLeod E<lt>ken@bitsko.slc.ut.usE<gt>
+
+=cut
+
+sub sdata_dirs {
+ return ("/usr/share/entity-map", "/usr/share/entity-map/0.1.0");
+}
+
+sub load {
+ my ($type, $file_name) = @_;
+
+ my ($self) = {};
+ bless ($self, $type);
+
+ open (FILE, "$file_name")
+ || die "Can't open \`$file_name' for reading: $!\n";
+ while (<FILE>) {
+ chop;
+ m/(^[^\t]+)\t(.*)/;
+ $self->{"$1"} = $2;
+ }
+ close (FILE);
+
+ return ($self);
+}
+
+sub group {
+ my ($type) = shift;
+
+ my ($self) = [{}, @_];
+ bless ($self, 'Text::EntityMapGroup');
+
+ return ($self);
+}
+
+sub lookup {
+ my ($self, $entity) = @_;
+
+ return ($self->{$entity});
+}
+
+package Text::EntityMapGroup;
+
+sub lookup {
+ my ($self, $entity) = @_;
+
+ my ($replacement) = $self->[0]{$entity};
+ return $replacement if defined $replacement;
+
+ my ($ii);
+ for ($ii = 1; $ii <= $#{$self}; $ii ++) {
+ $replacement = $self->[$ii]->lookup($entity);
+ if (defined $replacement) {
+ $self->[0]{$entity} = $replacement;
+ return ($replacement);
+ }
+ }
+
+ return (undef);
+}
+
+1;
diff --git a/tools/linuxdoc-tools/copyright b/tools/linuxdoc-tools/copyright
new file mode 100644
index 00000000..a89b6ada
--- /dev/null
+++ b/tools/linuxdoc-tools/copyright
@@ -0,0 +1,85 @@
+
+This is `linuxdoc-tools', a series of tools to implement the Linux
+Documentation Project HOWTO and book styles in SGML.
+
+This copy was modified in order to work with birddoc DTD. It is
+based on version 0.9.73-2 from Debian 10.
+
+
+----------------------------------
+ The linuxdoc-tools license
+----------------------------------
+
+linuxdoc-tools is derived from linuxdoc-SGML, originally written by
+Matt Welsh and later maintained by Cees de Groot. Linuxdoc-SGML is
+based on James Clark's sgmls parser, and the QWERTZ DTD by Tom
+Gordon. Magnus Alvestad provided the current HTML support. For
+the rest of linuxdoc-SGML,
+
+ Copyright (C) 1994-1996 Matt Welsh <mdw@cs.cornell.edu>
+ Copyright (C) 1996-1998 Cees de Groot <cg@pobox.com>
+
+Original Linuxdoc-SGML itself does not have any limitations.
+Everything not having explicit additional conditions can be freely
+used, modified, and redistributed, under the usual fair use clauses:
+
+ * No warranty. Use at your own risk.
+ * Do not pretend to have written what you did not (Preserve credits
+ and Copyright notices of the different elements if present).
+
+Since then, lots of smaller and bigger changes resulted in a rename
+to SGML-Tools (and then to SGMLtools, the hyphen caused confusion)
+to indicate that it wasn't just for Linux anymore. See files
+CHANGES.old-v1 and CONTRIBUTORS.old-v1 for changelog and list of
+contributors to old linuxdoc-sgml and sgmltools-v1.
+
+When sgml-tools dropped support for the linuxdoc DTD, Taketoshi Sano
+<sano@debian.org> forked the code to linuxdoc-tools. See README file.
+
+Changes after the fork
+
+ Copyright (C) 1999-2002 Taketoshi Sano <sano@debian.org>
+ Copyright (C) 2000 Juan Jose Amor
+ Copyright (C) 2007-2018 Agustin Martin Domingo <agmartin@debian.org>
+
+Unless conflicting with other licenses, changes by Agustin Martin
+Domingo are free software: you can redistribute and/or modify them
+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. Otherwise they honour previous
+license.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+In Debian systems you can find a copy under /usr/share/common-licenses.
+
+
+----------------------------------
+ The entity-map license
+----------------------------------
+
+Copyright (C) 1997 Ken MacLeod
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL KEN MACLEOD BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Ken MacLeod shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from
+Ken MacLeod.