#!/usr/bin/perl5 -w

use strict;
use vars qw($VERSION $scanners_dir $utils_dir $xsl_dir %options);
use lib '/usr/lib64/texitheque/modules';

use Pod::Usage;
use Getopt::Long qw(:config gnu_getopt);
use File::Spec;
use File::Copy   qw(cp mv);

BEGIN {
    $VERSION      = '0.3';
    $scanners_dir = '/usr/lib64/texitheque';
    $utils_dir    = '/usr/lib64/texitheque';
    $xsl_dir      = '/usr/lib64/texitheque/xsl';

    # Default options
    %options = (
	makeinfo => 'makeinfo',
	output   => '-',
	images   => '',
	icon     => '',
	banner   => '',
	css      => 'css/',
	targets  => '',
    );

    # Adjust $SGML_CATALOG_FILES environment variable to include $utils_dir
    my $catalog = File::Spec->catfile($utils_dir, 'xsl', 'catalog');
    $ENV{SGML_CATALOG_FILES} = $ENV{SGML_CATALOG_FILES} ? ($catalog . ':' . $ENV{SGML_CATALOG_FILES}) : $catalog;
}

sub help {
    pod2usage(
	'-message' => qq{texitheque: Collection of tools that help working with Texinfo.},
	'-verbose' => 1,
	'-exit'    => 0,
    );
}

sub version {
  print <<EOT;
texitheque $VERSION
Written by Alper Ersoy and Tim Janik

Copyright (C) 2003 Alper Ersoy and Tim Janik.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOT

  exit;
}

sub verbose {
    # Let the user know what we are doing

    return unless $options{verbose};
    return unless @_;
    
    print STDERR "@_\n";
}

sub check_tool {
    while ($_ = shift) {
	$_ = (split /\s+/, $_)[0];
	verbose "Executing: which '$_' &>/dev/null";
	qx(which '$_' &>/dev/null);
	return unless $? eq 0;
    }

    # All found
    return 1;
}

sub basename {
    # /usr/bin/basename clone

    my $file = shift;

    return unless defined $file;

    return ((File::Spec->splitpath($file))[2]);
}

sub cat {
    # Mimic /usr/bin/cat
    
    my $file = shift;

    return unless defined $file;

    die "FATAL: Cannot cat unreadable file '$file'" unless -r $file;

    open my $cat, $file or die "FATAL: Cannot open $file for reading: $!\n";
    while (<$cat>) {
	print;
    }
    close $cat;

    # Return gracefully
    return 1;
}

sub current_dir {
  return File::Spec->rel2abs(File::Spec->curdir);
}

sub get_temp_name {
    # Return a temporary file name
    my $orig = shift;

    return unless defined $orig;

    my $orig_base = basename $orig;

    $orig_base .= ".$$";

    return File::Spec->catfile(File::Spec->tmpdir, $orig_base);
}

sub get_man_section {
    my $file = shift;

    return unless defined $file;

    if ($file =~ m/\.([0-9n]+)\.xml$/i) {
	return $1
    }

    return ''
}

sub scankeys {
    my @params = @_;

    # Protect parameters from being interpolated via shell
    map { $_ = "'" . $_ . "'"; } @params;

    # Command to execute
    my $command = qq{$utils_dir/scankeys @params};

    verbose 'Executing:', $command;
    exec $command or exit 127;
}

sub log2texi {
    my @params = @_;

    # Do we have enough number of parameters?
    pod2usage(
	'-message' => qq{Invalid number of parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 4,
    ) unless scalar @params eq 1;

    pod2usage(
	'-message' => qq{Use --title option to set document title, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 5,
    ) unless defined $options{title};

    my $log2texi = File::Spec->catfile($utils_dir, 'log2texi.sh');

    # Maybe log2texi.sh is not available
    die "FATAL: Cannot find '$log2texi' executable\n" unless -x $log2texi;

    # Command to execute
    my $command = qq{$log2texi @params '$options{title}'};

    verbose 'Executing:', $command;

    # Execute the thing, and save the output
    my $output = qx{$command} or exit 127;

    # Do we use STDOUT, or a file for output?
    unless ($options{output} eq '-') {
	verbose 'IO: Opening', $options{output}, 'for writing';
	open my $out_fh, ">$options{output}"
	    or die "FATAL: Cannot open '$options{output}' for writing\n";

	verbose 'IO: Writing to file';
	print $out_fh $output;

	verbose 'IO: Closing file';
	close $out_fh;
    } else {
	print $output;
    }

    # Return gracefully
    1;
}

sub xmlantispace {
    # Don't remove whitespaces if --whitespace options is used
    return 1 if $options{whitespace};

    my $file = shift;
    return unless defined $file;

    die "FATAL: Cannot read file '$file': $!\n" unless -r $file;

    my $antispace = File::Spec->catfile($utils_dir, 'xmlantispace');

    # Maybe xmlantispace is not available
    die "FATAL: Cannot find '$antispace' executable\n" unless -x $antispace;

    # Use filename.xml-ns as output file name
    # MNEMONIC: "no space"
    my $output = $file . '-ns';

    my $command = qq{$antispace <'$file' >'$output'};

    verbose 'Executing:', $command;

    system($command);

    my $exit_value = $? >> 8;

    # xmlantispace failed for some reason
    if ($exit_value) {
	warn "FATAL: $antispace failed with $exit_value as exit value while processing '$file'\n";
	unless ($options{keep}) {
	    verbose "WARNING: Removing temporary file '$output', use --keep option to keep it\n";
	    unlink $output;
	}

	return;
    }

    # Done
    mv $output, $file or die "FATAL: cannot mv '$output' '$file'\n";

    # Just in case
    unlink $output;

    return 1;
}

sub fix_dtd {
    my $file = shift;
    return unless defined $file;

    die "FATAL: Cannot read file '$file': $!\n" unless -r $file;

    # Use filename.xml-fdtd as output file name
    # MNEMONIC: "fixing dtd"
    my $output = $file . '-fdtd';

    # Input file
    verbose 'IO: Opening', $file, 'for reading';
    open my $xml, "<$file" or die "FATAL: Cannot open $file for reading: $!\n";

    # Output file
    verbose 'IO: Opening', $output, 'for writing';
    open my $out, ">$output" or die "FATAL: Cannot open $output for writing $!\n";

    my $bad_dtd  = quotemeta q{<!DOCTYPE texinfo SYSTEM "texinfo.dtd">};
    my $good_dtd = q{<!DOCTYPE texinfo PUBLIC "texinfo" "texinfo.dtd">};

    # Substitute makeinfo generated DOCTYPE with ours
    while (<$xml>) {
	s/^$bad_dtd$/$good_dtd/gi;

	print $out $_;
    }

    verbose 'IO: Closing', $file;
    close $xml;

    verbose 'IO: Closing', $output;
    close $out;

    # Done
    mv $output, $file or die "FATAL: cannot mv '$output' '$file'\n";

    # Just in case
    unlink $output;

    return 1;
}

sub fix_setfilename {
    my $file = shift;
    return unless defined $file;

    die "FATAL: Cannot read file '$file': $!\n" unless -r $file;

    # Use filename.xml-sfn as output file name
    # MNEMONIC: "set_file_name"
    my $output = $file . '-sfn';

    # Input file
    verbose 'IO: Opening', $file, 'for reading';
    open my $xml, "<$file" or die "FATAL: Cannot open $file for reading: $!\n";

    # Output file
    verbose 'IO: Opening', $output, 'for writing';
    open my $out, ">$output" or die "FATAL: Cannot open $output for writing $!\n";

    my $orig_setfilename = quotemeta qq{<setfilename>$file</setfilename>};
    my $good_setfilename = qq{<setfilename>$options{output}</setfilename>};

    # Substitute makeinfo generated <setfilename> tag with ours
    while (<$xml>) {
	s/$orig_setfilename/$good_setfilename/gi;

	print $out $_;
    }

    verbose 'IO: Closing', $file;
    close $xml;

    verbose 'IO: Closing', $output;
    close $out;

    # Done
    mv $output, $file or die "FATAL: cannot mv '$output' '$file'\n";

    # Just in case
    unlink $output;

    return 1;
}

{

my %item_index;

sub cross_reference {
    # Don't try to resolve references unless we have indices
    return 1 unless defined $options{index} and scalar @{$options{index}} gt 0;

    my $file = shift;
    return unless defined $file;

    die "FATAL: Cannot read file '$file': $!\n" unless -r $file;

    # Use filename.xml-cr as output file name
    # MNEMONIC: "cross reference"
    my $output = $file . '-cr';

    # Read the index files into a hash table
    foreach my $index_file (@{$options{index}}) {
	die "FATAL: Cannot read index '$index_file'\n" unless -r $index_file;

	verbose 'IO: Opening', $index_file, 'for reading';
	open my $index, "<$index_file" or die "FATAL: Cannot open $index_file for reading: $!\n";

	while (<$index>) {
	    chomp;
	    my ($function, $url) = split /\s+/, $_, 2;
	    $item_index{$function} = $url;
	}

	verbose 'IO: Closing', $index_file;
	close $index;
    }

    # Don't bother if we didn't get any entries
    unless (%item_index) {
	warn "WARNING: cross reference index empty\n";
	return 1;
    }

    # Input file
    verbose 'IO: Opening', $file, 'for reading';
    open my $xml, "<$file" or die "FATAL: Cannot open $file for reading: $!\n";

    # Output file
    verbose 'IO: Opening', $output, 'for writing';
    open my $out, ">$output" or die "FATAL: Cannot open $output for writing $!\n";

    # Substitute function and type names with their targets
    while (<$xml>) {
	# Match functions
	s{(<reference-function>)([^<]+)(</reference-function>)}
	 {make_xref($2, $1, $3)}ge;

	# Match structs
	s{(<reference-type>)([^<]+)(</reference-type>)}
	 {make_xref($2, $1, $3)}ge;

	# Move no-link functions to normal ones
	s{<(/?)reference-function-nolink>}
	 {<$1reference-function>}g;

	print $out $_;
    }

    verbose 'IO: Closing', $file;
    close $xml;

    verbose 'IO: Closing', $output;
    close $out;

    # Done
    mv $output, $file or die "FATAL: cannot mv '$output' '$file'\n";

    # Just in case
    unlink $output;

    return 1;
}

sub make_xref {
    my $item    = shift;
    my $prefix  = shift;
    my $postfix = shift;

    # Get rid of unwanted characters (non-alphanumeric)
    my $item_tmp = $item;
    $item_tmp =~ y/A-Za-z0-9_-//cd;

    unless (defined $item_index{$item_tmp}) {
	return $prefix . $item . $postfix;
    }

    return 
	"<uref><urefurl>$item_index{$item_tmp}</urefurl><urefreplacement>$prefix$item$postfix</urefreplacement></uref>";
}

}

sub create_xml {
    my @params = @_;

    # We want exactly 1 parameter to operate on
    pod2usage(
	'-message' => qq{Invalid number of parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 6,
    ) unless scalar @params eq 1;

    # Cannot go further without a working makeinfo
    die "FATAL: Cannot find a usable makeinfo command as `$options{makeinfo}'\n" unless check_tool $options{makeinfo} or -x $options{makeinfo};

    my $param = shift;

    die "FATAL: Unreadable file '$param'\n" if $param ne '-' and not -r $param;

    # Get the last modification time of $param.
    # Using _ as file name saves us a system call
    my $revision = localtime ((stat _)[9]);

    # Use a temporary file until we are done
    my $temp_file = get_temp_name $param;

    die "FATAL: Cannot find a suitable temporary file for '$param'\n" unless defined $temp_file;

    # Append xml extension so it's obvious what that file is, if for some
    # reason it gets stuck there
    $temp_file .= '.xml';

    my $command = qq{$options{makeinfo} --xml --force -I $utils_dir -D 'TexiStamp $revision' --output='$temp_file' '$param'};

    verbose 'Executing:', $command;

    system $command;
    my $exit_value = $? >> 8;

    # Trouble with makeinfo
    if ($exit_value) {
	warn "FATAL: $options{makeinfo} failed with $exit_value as exit value while processing '$param'\n";
	unless ($options{keep}) {
	    verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	    unlink $temp_file;
	}

	# Let the parent process know what happened to makeinfo
	exit $exit_value;
    }

    # Remove spaces from XML file
    unless (xmlantispace $temp_file and not $options{keep}) {
	verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	unlink $temp_file;

	exit 10;
    }

    # Fix document identifier so that xsltproc will find our DTD
    unless (fix_dtd $temp_file and not $options{keep}) {
	verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	unlink $temp_file;

	exit 10;
    }

    # Fix <setfilename> tag so reference-filter stylesheet can make use of it
    unless (fix_setfilename $temp_file and not $options{keep}) {
	verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	unlink $temp_file;

	exit 10;
    }

    # Fix cross-references
    unless (cross_reference $temp_file and not $options{keep}) {
	verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	unlink $temp_file;

	exit 10;
    }

    # Move the file to where it is desired
    unless ($options{output} eq '-') {
	verbose "Moving temporary file '$temp_file' to", $options{output};
	mv $temp_file, $options{output} or die "FATAL: cannot mv '$temp_file' '$options{output}'\n";
    } else {
	cat $temp_file;
    }

    # Keep everything clean, just in case
    unlink $temp_file;

    # Return gracefully
    1;
}

sub create_markup {
    my @params = @_;

    # We want exactly 1 parameter to operate on
    pod2usage(
	'-message' => qq{Invalid number of parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 6,
    ) unless scalar @params eq 1;

    # Cannot go further without xsltproc
    die "FATAL: Cannot find 'xsltproc' in the path\n" unless check_tool 'xsltproc';

    # And the markup stylesheet...
    my $stylesheet = File::Spec->catfile($utils_dir, 'xsl', 'markup.xsl');
    die "FATAL: Cannot find '$stylesheet'" unless -r $stylesheet;

    my $param = shift;

    die "FATAL: Unreadable file '$param'\n" if $param ne '-' and not -r $param;

    my $command = qq{xsltproc --catalogs --output '$options{output}' '$stylesheet' '$param'};

    verbose 'Executing:', $command;

    system $command;
    my $exit_value = $? >> 8;

    # Trouble with xsltproc
    if ($exit_value) {
	warn "FATAL: xsltproc failed with $exit_value as exit value while processing '$param'\n";
	unless ($options{keep}) {
	    verbose "WARNING: Removing output file '$options{output}', use --keep option to keep it\n";
	    unlink $options{output};
	}

	# Let the parent process know what happened to xsltproc
	exit $exit_value;
    }

    # Return gracefully
    1;
}

sub create_html {
    my @params = @_;

    # We want exactly 1 parameter to operate on
    pod2usage(
	'-message' => qq{Invalid number of parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 6,
    ) unless scalar @params eq 1;

    # --images option is mandatory if --icon is used
    pod2usage(
	'-message' => qq{Use --images option to specify (relative) path to icon, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 7,
    ) if $options{icon} and not $options{images};

    # Cannot go further without xsltproc
    die "FATAL: Cannot find 'xsltproc' in the path\n" unless check_tool 'xsltproc';

    # And the html stylesheet...
    my $stylesheet = File::Spec->catfile($utils_dir, 'xsl', 'html.xsl');
    die "FATAL: Cannot find '$stylesheet'" unless -r $stylesheet;

    my $param = shift;

    die "FATAL: Unreadable file '$param'\n" if $param ne '-' and not -r $param;

    my $dir = current_dir;

    my $command  = join(' ',
	qq{xsltproc --catalogs --output '$options{output}'},
	qq{--stringparam 'this_file' '$options{output}'},
	qq{--stringparam 'this_dir' '$dir'},
	qq{--stringparam 'images_prefix' '$options{images}'},
	qq{--stringparam 'banner_prefix' '$options{banner}'},
	qq{--stringparam 'site_icon' '$options{icon}'},
	qq{--stringparam 'stylesheet_prefix' '$options{css}'},
	qq{--stringparam 'targets_prefix' '$options{targets}'},
	qq{'$stylesheet' '$param'},
    );

    verbose 'Executing:', $command;

    system $command;
    my $exit_value = $? >> 8;

    # Trouble with xsltproc
    if ($exit_value) {
	warn "FATAL: xsltproc failed with $exit_value as exit value while processing '$param'\n";
	unless ($options{keep}) {
	    verbose "WARNING: Removing output file '$options{output}', use --keep option to keep it\n";
	    unlink $options{output};
	}

	# Let the parent process know what happened to xsltproc
	exit $exit_value;
    }

    # Return gracefully
    1;
}

sub create_nroff {
    my @params = @_;

    # We want exactly 1 parameter to operate on
    pod2usage(
	'-message' => qq{Invalid number of parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 6,
    ) unless scalar @params eq 1;

    # Cannot go further without xsltproc
    die "FATAL: Cannot find 'xsltproc' in the path\n" unless check_tool 'xsltproc';

    # And the nroff stylesheet...
    my $stylesheet = File::Spec->catfile($utils_dir, 'xsl', 'man.xsl');
    die "FATAL: Cannot find '$stylesheet'" unless -r $stylesheet;

    my $param = shift;

    die "FATAL: Unreadable file '$param'\n" if $param ne '-' and not -r $param;

    # Use a temporary file until we are done
    my $temp_file = get_temp_name $param;

    die "FATAL: Cannot find a suitable temporary file for '$param'\n" unless defined $temp_file;

    # Append nro extension so it's obvious what that file is, if for some
    # reason it gets stuck there
    $temp_file .= '.nro';

    # Extract section name from file name
    my $man_section = get_man_section $param;

    my $command = qq{xsltproc --catalogs --output '$temp_file' --stringparam 'man_section' '$man_section' '$stylesheet' '$param'};

    verbose 'Executing:', $command;

    system $command;
    my $exit_value = $? >> 8;

    # Trouble with xsltproc
    if ($exit_value) {
	warn "FATAL: xsltproc failed with $exit_value as exit value while processing '$param'\n";
	unless ($options{keep}) {
	    verbose "WARNING: Removing temporary file '$temp_file', use --keep option to keep it\n";
	    unlink $temp_file;
	}

	# Let the parent process know what happened to xsltproc
	exit $exit_value;
    }

    # Move the file to where it is desired
    unless ($options{output} eq '-') {
	verbose "Moving temporary file '$temp_file' to", $options{output};
	mv $temp_file, $options{output} or die "FATAL: cannot mv '$temp_file' '$options{output}'\n";
    } else {
	cat $temp_file;
    }

    # Keep everything clean, just in case
    unlink $temp_file;

    # Return gracefully
    1;
}

sub make_index {
    my @params = @_;

    # We need at least 1 parameter to operate on
    pod2usage(
	'-message' => qq{Not enough parameters, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 6,
    ) unless scalar @params gt 0;

    # --protocol option is mandatory for reference-filter stylesheet
    pod2usage(
	'-message' => qq{Use --protocol option to set url targets, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 7,
    ) unless defined $options{protocol};

    # Cannot go further without xsltproc
    die "FATAL: Cannot find 'xsltproc' in the path\n" unless check_tool 'xsltproc';

    # And the reference-filter stylesheet...
    my $stylesheet = File::Spec->catfile($utils_dir, 'xsl', 'reference-index.xsl');
    die "FATAL: Cannot find '$stylesheet'" unless -r $stylesheet;

    my @files = map { "'$_'" } @params;

    my $command = qq{xsltproc --catalogs --output '-' --stringparam 'protocol' '$options{protocol}' '$stylesheet' @files};

    # Redirect output if a file is specified
    $command .= qq{ >$options{output}} unless $options{output} eq '-';

    verbose 'Executing:', $command;

    system $command;
    my $exit_value = $? >> 8;

    # Trouble with xsltproc
    if ($exit_value) {
	warn "FATAL: xsltproc failed with $exit_value as exit value while processing: @params\n";
	unless ($options{output} eq '-' and $options{keep}) {
	    verbose "WARNING: Removing output file '$options{output}', use --keep option to keep it\n";
	    unlink $options{output};
	}

	# Let the parent process know what happened to xsltproc
	exit $exit_value;
    }

    # Return gracefully
    1;
}

sub main {
    my ($command, @params) = @_;

    # We need a command
    pod2usage(
	'-message' => qq{Missing command, try 'texitheque --help' for more information.},
	'-verbose' => 0,
	'-exit'    => 2,
    ) unless defined $command;

    # Call the appropriate subroutine according to the command
    SWITCH: {
	if ($command eq 'log2texi')   { log2texi      @params; last SWITCH; }
	if ($command eq 'scankeys')   { scankeys      @params; last SWITCH; }
	if ($command eq 'texi2xml')   { create_xml    @params; last SWITCH; }
	if ($command eq 'xml2markup') { create_markup @params; last SWITCH; }
	if ($command eq 'xml2html')   { create_html   @params; last SWITCH; }
	if ($command eq 'xml2nroff')  { create_nroff  @params; last SWITCH; }
	if ($command eq 'xml2index')  { make_index    @params; last SWITCH; }

	# Man, unknown command!
	pod2usage(
	    '-message' => qq{Invalid command '$command', try 'texitheque --help' for more information.},
	    '-verbose' => 0,
	    '-exit'    => 3,
	);
    }
}

# Parse command line parameters
GetOptions(\%options,
    # General options
    'verbose|V!',
    'help|?|h',
    'version|v',
    'output|o=s',
    'keep|k!',

    # log2texi options
    'title|t=s',

    # xml options
    'whitespace!',
    'index|i=s@',
    'makeinfo=s',

    # index options
    'protocol=s',

    # html options
    'images=s',
    'banner=s',
    'icon=s',
    'css=s',
    'targets=s',

) or pod2usage(
    '-message' => qq{Try 'texitheque --help' for more information.},
    '-verbose' => 0,
    '-exit'    => 1,
);

# Print help message if requested
help if $options{help};

# Or version
version if $options{version};

# Get the work done already
main @ARGV;

# Keeping a clean documentation is one nice behaviour

__END__

=head1 NAME

texitheque - Collection of tools that help working with Texinfo

=head1 SYNOPSIS

texitheque [options] command [files...]

=head1 OPTIONS

=head2 General options

  --verbose         be more verbose during operations
  --help            display this help and exit
  --version         output version information and exit

=head2 Input/Output options

  --output=FILE     use FILE instead of standard output
  --keep            keep temporary files in case of errors

=head2 Commands

  texi2xml          convert a Texinfo document to XML data
  xml2index         generate a function index from XML data
  xml2html          generate an HTML file from XML data
  xml2markup        generate a Tag-Span-Markup file from XML data
  xml2nroff         generate a nroff document from XML data
  log2texi          convert a ChangeLog to a Texinfo document
  scankeys          scan text files for specific macro or function
                    sequences

=head2 C<texi2xml> options

  --makeinfo=FILE   use FILE as a makeinfo replacement
  --whitespace      do not strip unnecessary whitespace from output
                    (Warning: output with whitespace is generally
                    unsuitable for nroff conversion.)
  --index=INDEX     use pointers in INDEX file for function definitions

=head2 C<xml2index> options

  --protocol=PROTO  use PROTO for targets

=head2 C<xml2html> options

  --images=DIR      specify image directory
  --css=DIR         specify directory for stylesheets
  --banner=BANNER   use BANNER as a basename for banner image for HTML
  --icon=ICO        favicon file
  --targets=PREFIX  prepend PREFIX to links

=head2 C<log2texi> options

  --title=TITLE     use TITLE as the title for log

=head1 DESCRIPTION

B<texitheque> is a collection of useful tools which:

=over 4

=item *

transform B<makeinfo>'s XML output into a variety of formats using XSL
stylesheets,

=item *

generate texinfo documents from other sources, such as ChangeLogs,

=item *

fixes or works around some errors and glitches in XML files created by
B<makeinfo>.

=back

=head2 General Options

These options relate to all texitheque operations in general, or none at all.

=over 8

=item B<--help>

Print a brief help message and exit.

=item B<--version>

Print version, authors and copyright information.

=item B<--verbose>

Print diagnostic messages during operations.

=back

=head2 Input/Output Options

These options help B<texitheque> decide what files to read, where to output,
etc.

=over 8

=item B<--output>=I<FILE>

Use I<FILE> for output.  B<texitheque> defaults to using standard output (-).

=item B<--keep>

Keep temporary files in case of errors.  This is useful if you want to track
down bugs in final outputs.

=back

=head2 Commands

These commands tell B<texitheque> to what action to perform.  Each operation
has a separate command, and most of them take arguments.

=head3 texi2xml

Creates XML data from a Texinfo document.  Optionally processes output to
provide pointers for functions to their definitions.

=over 8

=item B<--makeinfo>=I<FILE>

Make B<texitheque> use I<FILE> as the C<makeinfo> command.  Useful if
you want to test different versions of C<makeinfo>.

=item B<--whitespace>

Causes B<texitheque> to not strip whitespace from the output XML data.
This is handy if you want to read the output file with a pager.  However,
whitespace will make the output generally unsuitable for further operations.

=item B<--index>=I<FILE>

Use I<FILE> to read indices from.  You can generate one with C<xml2index>
command.  Refer to the appropriate section below.

=back

=head3 xml2index

Collects the locations of function definitions in files.  Generated index file
then can be used to provide cross references between documents.  Output file is
simply consisting of the following information per line:

  <function name> <url>

Due to the simplicity of the output, it is perfectly possible to provide your
own index files to commands that accept one.

E<lt>I<function name>E<gt> can be called a node name for the E<lt>I<url>E<gt>.
E<lt>I<url>E<gt> is almost anything that Texitheque XSL stylesheets can make
sense of.  You may refer to the Texitheque Manual to read about further
URL processing.

=over 8

=item B<--protocol>=I<PROTO>

Prepend I<PROTO> to the generated C<URL>s.  This highly depends on the final
delivery method of files.  However, C<beast-man> can be considered as an
all-around solution.

=back

=head3 xml2html

Creates an HTML file from XML data.

=over 8

=item B<--images>=I<DIR>

Specify the directory that holds the images used in the generated HTML file.
This is useful, if documents and images go to different locations in web
environments.  There is no processing applied to the I<DIR> option, so it
is necessary to provide enough information so that web browsers can easily
locate images.  Examples:

  Documents in:  /htdocs/mydocs/
  Images in:     /htdocs/mydocs/images/
  DIR should be: images/

  Documents in:  /htdocs/mydocs/docs/
  Images in:     /htdocs/mydocs/images/
  DIR should be: ../images/

=item B<--css>=I<DIR>

Similar to the B<--images> option, specifies the directory that web browsers
should read CSS stylesheets from.  It is necessary to provide one, if you make
use of stylesheets.  Default stylesheet referred to is I<DIR>C</default.css>.

=item B<--banner>=I<BANNER>

Specify the prefix for banner (header) images in HTML documents.  Since these
images relate to the page style, it should be located in I<css dir>C</images/>
directory, and not the directory specified with B<--images> option (I<css dir>
is specified with B<--css> option.)  Three images for large style banners, and
one for small style banners are needed.  Please refer to the Texitheque Manual
to learn more about these styles and images.

=item B<--icon>=I<ICO>

If you want the documents to have a Favicon, you can specify it with this
option.  I<ICO> file should be located in the directory you specified with
B<--images> option.

=item B<--targets>=I<PREFIX>

This option may be necessary if you make use of navigation features of
Texitheque, and the final HTML documents are supposed to end up in different
directories.  This option specifies the prefix that should be added to targets
in the XML file with navigational data.  Example:

  File 1: /htdocs/manual/index.html
  File 2: /htdocs/api/overview.html
  File 3: /htdocs/api/index.html
  File 4: /htdocs/contact.html

  In navigation XML, nodes respectively:
    <node title="User Manual"   target="manual/index.html" />
    <node title="API Overview"  target="api/overview.html" />
    <node title="API Reference" target="api/index.html" />
    <node title="Contacts"      target="contacts.html" />

  Required --targets options when creating files:
    File 1: --targets='../'
    File 2: --targets='../'
    File 3: --targets='../'
    File 4: --targets=''

=back

=head3 xml2markup

=head3 xml2nroff

These commands create Tag-Span-Markup and nroff files from XML data,
respectively.  Currently they take no options.

=head3 log2texi

Creates a I<Texinfo> document from a ChangeLog file.  Mandatory arguments are
I<log name> and I<log file>.  Former argument is used in the document title,
as in I<ChangeLog for E<lt>log nameE<gt>>.

=head1 EXIT CODES

=over 4

=item B<0>

Success.

=item B<1>

Unknown/ambigous option.

=item B<2>

Missing command.

=item B<3>

Invalid command.

=item B<4>

Wrong number of parameters for command.

=item B<127>

Fatal error while executing a utility.

=back

=head1 VERSION

This manual documents version 0.3 of texitheque.

=cut

# vim: ts=8 sw=4
