#+##############################################################################
#
# latex2html.pm: interface to LaTeX2HTML
#
# Copyright (C) 1999, 2000, 2003, 2005, 2006, 2009, 2011-2023
# Free Software Foundation, Inc.
#
# 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 .
#
# This code was taken from the main texi2html file in 2006.
# Certainly originally written by Olaf Bachmann.
# Adapted from texi2html T2h_l2h.pm in 2011.
#
#-##############################################################################
require 5.0;
use strict;
# To check if there is no erroneous autovivification
#no autovivification qw(fetch delete exists store strict);
use Cwd;
use File::Copy;
use File::Spec;
use Encode qw(encode);
# also for __(
use Texinfo::Common;
use Texinfo::Convert::Texinfo;
# to implement CONVERT_TO_LATEX_IN_MATH
use Texinfo::Convert::LaTeX;
texinfo_register_handler('structure', \&l2h_process);
texinfo_register_handler('finish', \&l2h_finish);
texinfo_register_command_formatting('math', \&l2h_convert_command);
texinfo_register_command_formatting('tex', \&l2h_convert_command);
texinfo_register_command_formatting('latex', \&l2h_convert_command);
texinfo_register_command_formatting('displaymath', \&l2h_convert_command);
# name/location of latex2html program
texinfo_set_from_init_file('L2H_L2H', 'latex2html');
# If this is set the actual call to latex2html is skipped. The previously
# generated content is reused, instead.
# If set to 0, the cache is not used.
# If undef the cache is used for as many tex fragments as possible
# and for the remaining the command is run.
texinfo_set_from_init_file('L2H_SKIP', undef);
# If this is set l2h uses the specified directory for temporary files. The path
# leading to this directory may not contain a dot (i.e., a ".");
# otherwise, l2h will fail.
texinfo_set_from_init_file('L2H_TMP', '');
# If set, l2h uses the file as latex2html init file
texinfo_set_from_init_file('L2H_FILE', undef);
# if this is set the intermediate files generated by texi2html in relation with
# latex2html are cleaned (they all have the prefix _l2h_).
texinfo_set_from_init_file('L2H_CLEAN', 1);
# latex2html conversions consist of 2 stages:
# 1) l2h_process
# to latex: Put "latex" code into a latex file
# (l2h_to_latex)
# to html: Use latex2html to generate corresponding html code and images
# (l2h_to_html)
# from html: Extract generated code and images from latex2html run
# (l2h_retrieve_from_html)
# 2) l2h_convert_command called each time an handled @-command (@math, ...) is
# encountered in the tree conversion.
my ($l2h_name, $l2h_cache_path_name);
my $debug;
my $verbose;
my $destination_directory;
my $destination_directory_string;
my $docu_name;
my %commands_counters;
my %commands_text_index;
my %commands_ignored;
my $extract_error_count;
my $invalid_text_index_count;
# change_image_file_names
my %l2h_img;
my $image_count;
my $html_output_count;
##########################
#
# First stage: Generation of Latex file
sub l2h_to_latex($$$$$)
{
my $self = shift;
my $l2h_latex_path_string = shift;
my $l2h_latex_path_name = shift;
my $latex_text_indices_to_convert = shift;
my $latex_texts = shift;
unless (open(L2H_LATEX, ">$l2h_latex_path_string")) {
$self->document_error($self, sprintf(__(
"l2h: could not open latex file %s for writing: %s"),
$l2h_latex_path_name, $!));
return 0;
}
# according to the .log file latex2html is expecting utf-8 if no information
# is provided
binmode(L2H_LATEX, ':utf8');
warn "# l2h: use $l2h_latex_path_string as latex file\n" if ($verbose);
print L2H_LATEX <\n";
print L2H_LATEX "\\end{rawhtml}\n";
print L2H_LATEX "$latex_texts->[$latex_text_index]\n";
print L2H_LATEX "\\begin{rawhtml}\n";
print L2H_LATEX "\n\n";
print L2H_LATEX "\\end{rawhtml}\n";
}
# print closing into latex file and close it
print L2H_LATEX '\end{document}'."\n";
# FIXME error condition not checked
close (L2H_LATEX);
return 1;
}
my $latex_commands_count;
my @latex_texts;
my $latex_texts_count;
my $latex_to_convert_count;
my $latex_converted_count;
my $html_converted_count;
# our because the file lexicals are not visible in the do loading the cache
our %l2h_cache;
my @l2h_from_html;
sub l2h_process($$)
{
my $self = shift;
my $document_root = shift;
@latex_texts = (); # array used to associate the index with
# a latex text.
$latex_commands_count = undef;
# number of latex Texinfo commands collected
$latex_texts_count = 0; # number of latex texts stored, two same text
# are only stored once
$latex_to_convert_count = 0; # number of latex texts that should pass through
# latex2html
$latex_converted_count = 0; # number of latex texts passed through latex2html
$html_converted_count = 0; # number of html texts retrieved
%l2h_cache = (); # the cache hash. Associate latex text with
# html from the previous run
@l2h_from_html = (); # array of resulting html
%commands_counters = (); # associate an element to the global counter
# of processed elements
%commands_text_index = (); # associate an element to the index of latex text,
# also the index in the HTML results array
%commands_ignored = (); # empty commands not processed. In general,
# should correspond to ignored block commands.
$extract_error_count = 0; # number of fragments that cannot be retrieved
# when @-commands are converted
$invalid_text_index_count = 0;
%l2h_img = (); # associate src file to destination file
# such that files are not copied twice
$image_count = 1;
$html_output_count = 0; # html text outputed in html result file
$docu_name = $self->get_info('document_name');
# destination dir -- generated images are put there, should be the same
# as dir of enclosing html document --
$destination_directory = $self->get_info('destination_directory');
$destination_directory = '' if (!defined($destination_directory));
my $dir = $destination_directory;
$dir = File::Spec->curdir() if ($dir eq '');
my $dir_encoding;
# $destination_directory_string is used in binary file path strings
($destination_directory_string, $dir_encoding)
= $self->encoded_output_file_name($dir);
$l2h_name = "${docu_name}_l2h";
my $l2h_latex_file_name = "${l2h_name}.tex";
my $l2h_latex_path_name = File::Spec->catfile($destination_directory,
$l2h_latex_file_name);
# we use utf-8 encoding irrespective of what is used in texi2any
# because latex2html use the file name in the resulting file and
# it needs to be utf-8
my $encoded_l2h_latex_file_name = encode('UTF-8', $l2h_latex_file_name);
my $l2h_latex_path_string = File::Spec->catfile($destination_directory_string,
$encoded_l2h_latex_file_name);
$l2h_cache_path_name = File::Spec->catfile($destination_directory,
"${docu_name}-l2h_cache.pm");
# set consistently with $l2h_latex_file_name to ensure that
# latex2html will create a file with this name.
my $l2h_html_file_name = "${l2h_name}.html";
$debug = $self->get_conf('DEBUG');
$verbose = $self->get_conf('VERBOSE');
# no point in doing anything in that case. Reusing cached information
# may have been relevant, but the cache file should not exist
# (cache file is /dev/null-l2h_cache.pm).
return 0 if (defined($self->get_conf('OUTFILE'))
and $Texinfo::Common::null_device_file{$self->get_conf('OUTFILE')});
my $options_latex_math;
if ($self->get_conf('CONVERT_TO_LATEX_IN_MATH')) {
$options_latex_math
= {Texinfo::Convert::LaTeX::copy_options_for_convert_to_latex_math($self)};
}
my $l2h_skip = $self->get_conf('L2H_SKIP');
# open the database that holds cached text
l2h_init_cache($self) if (!defined($l2h_skip) or $l2h_skip);
my @replaced_commands = ('displaymath', 'latex', 'math', 'tex');
my $collected_commands = Texinfo::Common::collect_commands_list_in_tree(
$document_root, \@replaced_commands);
my $texinfo_command_index = 0; # index of latex elements/commands processed
my @latex_text_indices_to_convert; # indices of latex texts that should be converted
my %latex_text_indices; # associate a latex text with the index in the
# html result array. Allows to do each text
# only once
my $cached_count = 0; # number of cached latex texts
if (scalar(@{$collected_commands})) {
foreach my $element (@{$collected_commands}) {
my $command = $element->{'cmdname'};
my $tree;
if ($command eq 'math') {
$tree = $element->{'args'}->[0];
} else {
$tree = {'contents' => [@{$element->{'contents'}}]};
if ($tree->{'contents'}->[0]
and $tree->{'contents'}->[0]->{'type'}
and ($tree->{'contents'}->[0]->{'type'} eq 'empty_line_after_command'
or $tree->{'contents'}->[0]->{'type'} eq 'elided_rawpreformatted')) {
shift @{$tree->{'contents'}};
}
if ($tree->{'contents'}->[-1]->{'cmdname'}
and $tree->{'contents'}->[-1]->{'cmdname'} eq 'end') {
pop @{$tree->{'contents'}};
}
}
if (scalar(@{$tree->{'contents'}}) == 0) {
# should correspond to an ignored block
$commands_ignored{$element} = 1;
next;
}
$texinfo_command_index++;
my $texinfo_text;
if ($self->get_conf('CONVERT_TO_LATEX_IN_MATH')) {
$texinfo_text = Texinfo::Convert::LaTeX::convert_to_latex_math(undef,
$tree, $options_latex_math);
} else {
$texinfo_text = Texinfo::Convert::Texinfo::convert_to_texinfo($tree);
}
# print $texinfo_text into latex file (if not already there nor in cache)
# which can be later on replaced by the latex2html generated text.
my $latex_text = $texinfo_text;
if ($command eq 'tex' or $command eq 'latex') {
$latex_text .= ' ';
} elsif ($command eq 'math') {
$latex_text = "\$".$latex_text."\$";
} elsif ($command eq 'displaymath') {
$latex_text = "\\[".$latex_text."\\]";
}
$latex_text =~ s/(\s*)$//;
# try whether we have text already on things to do
my $latex_text_index = $latex_text_indices{$latex_text};
unless ($latex_text_index) {
$latex_texts_count++;
$latex_text_index = $latex_texts_count;
# try whether we can get it from cache
my $cached_text = l2h_from_cache($self, $latex_text);
if (defined($cached_text)) {
$cached_count++;
# put the cached result in the html result array
$l2h_from_html[$latex_text_index] = $cached_text;
} else {
# the text indexed by $latex_text_index should be converted
push @latex_text_indices_to_convert, $latex_text_index;
}
$latex_texts[$latex_text_index] = $latex_text;
$latex_text_indices{$latex_text} = $latex_text_index;
}
$commands_counters{$element} = $texinfo_command_index;
$commands_text_index{$element} = $latex_text_index;
}
} else {
# no handled command, nothing to do
warn "# l2h: no handled commands\n" if ($verbose);
$latex_commands_count = 0;
return 0;
}
$latex_to_convert_count = scalar(@latex_text_indices_to_convert);
$latex_commands_count = $texinfo_command_index;
my $reused = $latex_commands_count - $latex_to_convert_count - $cached_count;
warn "# l2h: to latex ($cached_count cached, $reused reused, $latex_to_convert_count to process)\n" if ($verbose);
# when there are tex constructs to convert (not everything
# comes from the cache)
if ($latex_to_convert_count > 0) {
unless ($l2h_skip) {
my $l2h_to_latex_status
= l2h_to_latex($self, $l2h_latex_path_string, $l2h_latex_path_name,
\@latex_text_indices_to_convert, \@latex_texts);
return 1 unless ($l2h_to_latex_status);
# the non equality of $latex_converted_count and $latex_to_convert_count
# is the preferred indicator of skipping this stage or failure.
$latex_converted_count = $latex_to_convert_count;
}
if ($latex_converted_count > 0) {
my $l2h_to_html_status = l2h_to_html($self, $l2h_latex_path_string,
$l2h_latex_path_name);
return 1 unless($l2h_to_html_status);
my @html_retrieved_text_indices = l2h_retrieve_from_html($self,
$l2h_html_file_name);
$html_converted_count = scalar(@html_retrieved_text_indices);
# Not the same number of converted elements and retrieved elements.
if ($latex_converted_count != $html_converted_count) {
# unless latex2html somewhat mangles the output this cannot
# actually happen, so it could also be presented as an error or a bug.
$self->document_warn($self, sprintf(__(
"latex2html.pm: processing produced %d items in HTML; expected %d"),
$html_converted_count, $latex_converted_count));
}
# It could be checked, in addition, that @html_retrieved_text_indices
# contains the same indices as @latex_text_indices_to_convert.
warn "# l2h: retrieved converted $html_converted_count of $latex_texts_count html contents\n"
if ($verbose);
} else {
warn "# l2h: skipping latex2html run\n" if ($verbose);
}
} else {
warn "# l2h: no latex2html run needed\n" if ($verbose);
}
return 0;
}
###################################
# Use latex2html to generate corresponding html code and images
#
# l2h_to_html():
# Call latex2html on $l2h_latex_path_string
# Put images (prefixed with $l2h_name."_") and html file(s) in $destination_directory_string
# Return 1, on success
# 0, otherwise
#
sub l2h_to_html($$$)
{
my $self = shift;
my $l2h_latex_path_string = shift;
my $l2h_latex_path_name = shift;
my $l2h_prefix = "${l2h_name}_";
my $dotbug;
# Check for dot in directory where dvips will work
if ($self->get_conf('L2H_TMP')) {
if ($self->get_conf('L2H_TMP') =~ /\./) {
$self->document_warn($self,
__("l2h: L2H_TMP directory contains a dot"));
$dotbug = 1;
}
} else {
if (cwd() =~ /\./) {
$self->document_warn($self,
__("l2h: current directory contains a dot"));
$dotbug = 1;
}
}
my $latex2html_command = $self->get_conf('L2H_L2H');
if (not defined($latex2html_command) or $latex2html_command !~ /\S/) {
$self->document_error($self, __("l2h: command not set"));
return 0;
}
# the final call is obtained by concatenating $call_start encoded
# and strings based on already encoded file paths.
my $call_start = $latex2html_command;
# use init file, if specified
my $init_file = $self->get_conf('L2H_FILE');
# FIXME not clear whether encoded_input_file_name or encoded_output_file_name
# should be used here
if (defined($init_file) and $init_file ne '') {
# FIXME likely incorrect, should use the same encoding as
# the encoding used to encode call
my ($encoded_init_file, $init_path_encoding)
= $self->encoded_input_file_name($init_file);
$call_start .= " -init_file " . $init_file
if -f $encoded_init_file and -r $encoded_init_file;
}
# set output dir
my $encoded_destination_dir_option = ' -no_subdir';
my $destination_dir_option = $encoded_destination_dir_option;
if ($destination_directory ne '') {
$encoded_destination_dir_option = " -dir ".$destination_directory_string;
$destination_dir_option = " -dir ".$destination_directory;
}
# use l2h_tmp, if specified
$call_start .= " -tmp ".$self->get_conf('L2H_TMP')
if (defined($self->get_conf('L2H_TMP'))
and $self->get_conf('L2H_TMP') ne '');
# use a given html version if specified
$call_start .= " -html_version ".$self->get_conf('L2H_HTML_VERSION')
if (defined($self->get_conf('L2H_HTML_VERSION'))
and $self->get_conf('L2H_HTML_VERSION') ne '');
# options we want to be sure of
$call_start .= " -address 0 -info 0 -split 0 -no_navigation -no_auto_link";
# FIXME use utf-8 here?
my $encoding = $self->get_conf('MESSAGE_ENCODING');
my $encoded_call_start;
if (defined($encoding)) {
$encoded_call_start = encode($encoding, $call_start);
} else {
$encoded_call_start = $call_start;
}
my $l2h_prefix_string = encode('UTF-8', $l2h_prefix);
# concatenante strings containing already encoded file paths
my $encoded_call = $encoded_call_start . $encoded_destination_dir_option
." -prefix $l2h_prefix_string $l2h_latex_path_string";
my $call = $call_start . $destination_dir_option
." -prefix $l2h_prefix $l2h_latex_path_name";
warn "# l2h: executing '$encoded_call'\n" if ($verbose);
if (system($encoded_call)) {
$self->document_error($self, sprintf(__("l2h: command did not succeed: %s"),
$call));
return 0;
} else {
warn "# l2h: latex2html terminated successfully\n" if ($verbose);
return 1;
}
}
##########################
# Third stage: Extract generated contents from latex2html run
# Retrieve with: l2h_retrieve_from_html
# open $l2h_html_path_string for reading
# reads in contents into array indexed by text indices
# return the indices of retrieved fragments
# the images generated by latex2html have names like ${docu_name}_l2h_img?.png
# they are copied to ${docu_name}_?.png, and html is changed accordingly.
# FIXME is it really necessary to bother doing that? Looks like an unneeded
# complication to me (pertusus, 2009), and it could go bad if there is some
# SRC="(.*?)" in the text (though the regexp could be made more specific).
# %l2h_img; # associate src file to destination file
# such that files are not copied twice
sub l2h_change_image_file_names($$)
{
my $self = shift;
my $content = shift;
my @images = ($content =~ /SRC="(.*?)"/g);
foreach my $src (@images) {
my $dest = $l2h_img{$src};
unless (defined($dest)) {
my $ext = '';
if ($src =~ /.*\.(.*)$/ and (!defined($self->get_conf('EXTENSION'))
or $1 ne $self->get_conf('EXTENSION'))) {
$ext = ".$1";
} else {
# A warning when the image extension is the same than the
# document extension. copying the file could result in
# overwriting an output file (almost surely if the default
# texi2html file names are used).
$self->document_warn($self, sprintf(__(
"l2h: image has invalid extension: %s"), $src));
next;
}
while (1) {
my $image_file_name = "${docu_name}_${image_count}$ext";
# encode in UTF-8 as latex2html uses $l2h_latex_path_string, which
# is UTF-8 encoded to setup the file names
my $encoded_image_file_name = encode('UTF-8', $image_file_name);
my $image_file_path = File::Spec->catfile($destination_directory_string,
$encoded_image_file_name);
unless (-e $image_file_path) {
last;
}
$image_count++;
}
my $src_file = File::Spec->catfile($destination_directory, $src);
my $encoded_src = Encode::encode('UTF-8', $src);
my $encoded_file_src
= File::Spec->catfile($destination_directory_string, $encoded_src);
$dest = "${docu_name}_${image_count}$ext";
my $file_dest
= File::Spec->catfile($destination_directory, $dest);
my $encoded_dest = Encode::encode('UTF-8', $dest);
my $encoded_file_dest = File::Spec->catfile($destination_directory_string,
$encoded_dest);
if ($debug) {
copy($encoded_file_src, $encoded_file_dest);
} else {
if (!rename($encoded_file_src, $encoded_file_dest)) {
$self->document_warn($self,
sprintf(__("l2h: rename %s as %s failed: %s"),
$src_file, $file_dest, $!));
}
}
$l2h_img{$src} = $dest;
}
$content =~ s/SRC="$src"/SRC="$dest"/g;
}
return $content;
}
sub l2h_retrieve_from_html($$)
{
my $self = shift;
my $l2h_html_file_name = shift;
my @html_retrieved_text_indices; # the text indices retrieved
my $l2h_html_path_name = File::Spec->catfile($destination_directory,
$l2h_html_file_name);
my $encoded_l2h_html_file_name = encode('UTF-8', $l2h_html_file_name);
my $l2h_html_path_string = File::Spec->catfile($destination_directory_string,
$encoded_l2h_html_file_name);
if (! open(L2H_HTML, "<$l2h_html_path_string")) {
$self->document_error($self,
sprintf(__("l2h: could not open %s: %s"),
$l2h_html_path_name, $!));
# return empty array
return @html_retrieved_text_indices;
}
# the file content is UTF-8 encoded
binmode(L2H_HTML, ':utf8');
warn "# l2h: use $l2h_html_path_string as html file\n" if ($verbose);
my ($latex_text_index, $h_line);
while ($h_line = ) {
if ($h_line =~ /!-- l2h_begin $l2h_name ([0-9]+) --/) {
$latex_text_index = $1;
my $h_content = '';
my $h_end_found = 0;
while ($h_line = ) {
if ($h_line =~ /!-- l2h_end $l2h_name $latex_text_index --/) {
$h_end_found = 1;
chomp $h_content;
chomp $h_content;
push @html_retrieved_text_indices, $latex_text_index;
# transform image file names and copy image files
$h_content = l2h_change_image_file_names($self, $h_content);
# store result in the html result array
$l2h_from_html[$latex_text_index] = $h_content;
# also add the result in cache hash
$l2h_cache{$latex_texts[$latex_text_index]} = $h_content;
last;
}
$h_content = $h_content.$h_line;
}
unless ($h_end_found) {
# couldn't found the closing comment. Should be a bug.
$self->document_warn($self,
sprintf(__("latex2html.pm: end of \@%s text %d not found"),
$l2h_name, $latex_text_index));
last;
}
}
}
# FIXME error/warning if close fails
close(L2H_HTML);
return @html_retrieved_text_indices;
}
# called each time an element handled by latex2html is encountered, should
# output the corresponding html
sub l2h_convert_command($$$;$$)
{
my $self = shift;
my $cmdname = shift;;
my $command = shift;
my $args = shift;
my $content = shift;
# if not defined($latex_commands_count) the initialization did not
# went to the point of commands collections.
# The default formatting will lead to a warning message since the
# raw format is not html, so simply return an empty string.
if (not defined($latex_commands_count) or $commands_ignored{$command}) {
return '';
}
#if (not defined($latex_commands_count)) {
# return &{$self->default_command_conversion($cmdname)}($self,
# $cmdname, $command, $args, $content);
#}
my $command_count = $commands_counters{$command};
my $latex_text_index = $commands_text_index{$command};
################################## begin debug section (incorrect counts)
if (!defined($command_count)) {
$self->present_bug_message("l2h: conversion of ${cmdname}, undef command_count");
$command_count = -1;
}
if (!defined($latex_text_index)) {
# counter is undefined
$invalid_text_index_count++;
$self->present_bug_message(
"l2h: could not determine the fragment $command_count, for \@$cmdname");
return ("")
if ($debug);
return '';
} elsif(($latex_text_index <= 0) or ($latex_text_index > $latex_texts_count)) {
# counter out of range
$invalid_text_index_count++;
$self->present_bug_message("l2h: request of $latex_text_index out of range [0,$latex_texts_count]");
return ("")
if ($debug);
return '';
}
################################## end debug section (incorrect counts)
# this seems to be a valid counter
my $result = '';
$result = "" if ($debug);
if (defined($l2h_from_html[$latex_text_index])) {
$html_output_count++;
$result .= $l2h_from_html[$latex_text_index];
$result .= "\n" if ($cmdname eq 'tex' or $cmdname eq 'latex');
} else {
# if the result is not in @l2h_from_html, it should in general mean that
# the conversion was skipped or there was an error or maybe latex2html
# somehow mangled the output.
$extract_error_count++;
# Expected error if the conversion to html failed or was skipped,
# additional warning only if the conversion seems to have proceeded normally.
if ($latex_converted_count == $latex_to_convert_count
and $latex_converted_count == $html_converted_count) {
# it could also probably be marked as a bug (or error) as there is no
# situation in which this could happen with the conditions on succeeding
# conversion.
$self->document_warn($self, sprintf(__(
"l2h: could not extract the fragment %d for \@%s, text %d, from HTML"),
$command_count, $cmdname, $latex_text_index));
} elsif ($verbose) {
warn "# l2h: incomplete l2h. No conversion command $command_count \@$cmdname, text index $latex_text_index\n";
}
# simple (ordinary) substitution (without l2h)
$result .= "" if ($debug);
$result .= &{$self->default_command_conversion($cmdname)}($self,
$cmdname, $command, $args, $content);
}
$result .= "" if ($debug);
return $result;
}
# store results in the cache and remove temporary files.
sub l2h_finish($)
{
my $self = shift;
return 0 if (not defined($latex_commands_count));
if ($verbose) {
if ($extract_error_count + $invalid_text_index_count) {
warn "# l2h: finish ($extract_error_count extract errors, $invalid_text_index_count invalid index errors)\n";
} else {
warn "# l2h: finish (no error)\n";
}
if ($html_output_count != $latex_converted_count) {
# this happens if texts are reused, or cache is used,
# and if commands are not expanded later.
warn "# l2h: $html_output_count html outputed for $latex_converted_count converted\n";
}
if ($html_output_count != $latex_commands_count) {
# this may happen if @-commands are collected at some places
# but @-command at those places are not expanded later. For
# example @math on @multitable lines, or in @copying.
warn "# l2h: $html_output_count html outputed for $latex_commands_count collected\n";
}
}
# return in case of error or skipped run
return 0 if ($latex_converted_count != $latex_to_convert_count
or $latex_converted_count != $html_converted_count);
l2h_store_cache($self);
if ($self->get_conf('L2H_CLEAN') and $latex_converted_count > 0) {
warn "# l2h: removing temporary files generated by l2h extension\n"
if ($verbose);
my $quoted_l2h_name = quotemeta($l2h_name);
if (opendir (DIR, $destination_directory_string)) {
foreach my $file (readdir(DIR)) {
# we have made sure that all the files names are encoded
# in UTF-8, but doing it above or by passing UTF-8 encoded
# file names to latex2html
my $file_name = decode('UTF-8', $file);
if ($file_name =~ /^$quoted_l2h_name/) {
# FIXME error condition not checked
unlink File::Spec->catfile($destination_directory_string, $file);
}
}
}
}
warn "# l2h: end\n" if $verbose;
return 0;
}
##############################
# stuff for l2h caching
#
# FIXME it is clear that l2h stuff can take very long compared with texi2any
# which is already quite long. However this also adds some complexity
# It was originally tried with a dbm data base, but it did not store all
# keys/values. Hence, do as latex2html does
sub l2h_init_cache($)
{
my $self = shift;
my ($encoded_l2h_cache_path_name, $l2h_cache_path_encoding)
= $self->encoded_output_file_name($l2h_cache_path_name);
if (-r $encoded_l2h_cache_path_name) {
my $loaded_path;
# do require a relative path, or to have . in INC
if (not File::Spec->file_name_is_absolute($l2h_cache_path_name)) {
$loaded_path = File::Spec->catfile(File::Spec->curdir(),
$encoded_l2h_cache_path_name);
} else {
$loaded_path = $encoded_l2h_cache_path_name;
}
my $rdo = do "$loaded_path";
unless ($rdo) {
# FIXME error or warning?
$self->document_error($self,
sprintf(__("l2h: could not compile %s: %s"),
$l2h_cache_path_name, $@))
if ($@);
if (! defined($rdo)) {
$self->document_error($self,
sprintf(__("l2h: could not load %s: %s"),
$l2h_cache_path_name, $!));
} else {
$self->document_error($self,
sprintf(__("l2h: error loading %s"),
$l2h_cache_path_name));
}
}
}
warn "# l2h: Cached: ".join('|', sort(keys(%l2h_cache)))."\n"
if ($verbose and scalar(keys(%l2h_cache)));
}
# store all the text obtained through latex2html or from previous runs cache
sub l2h_store_cache($)
{
my $self = shift;
# do not reset the cache if there was no new conversion
return unless ($html_converted_count);
my ($key, $value);
my ($encoded_l2h_cache_path_name, $l2h_cache_path_encoding)
= $self->encoded_output_file_name($l2h_cache_path_name);
unless (open(FH, ">$encoded_l2h_cache_path_name")) {
$self->document_error($self,
sprintf(__("l2h: could not open %s for writing: %s"),
$l2h_cache_path_name, $!));
return;
}
binmode(FH, ':utf8');
print FH "# Automatically generated\nuse utf8;\n";
print FH "our %l2h_cache;\n";
foreach my $key(sort(keys(%l2h_cache))) {
my $value = $l2h_cache{$key};
# escape stuff
$key =~ s|/|\\/|g;
$key =~ s|\\\\/|\\/|g;
# weird, a \ at the end of the key results in an error
# maybe this also broke the dbm database stuff
$key =~ s|\\$|\\\\|;
$value =~ s/\|/\\\|/go;
$value =~ s/\\\\\|/\\\|/go;
$value =~ s|\\\\|\\\\\\\\|g;
print FH "\n\$l2h_cache_key = q/$key/;\n";
print FH "\$l2h_cache{\$l2h_cache_key} = q|$value|;\n";
}
# this can be used when debugging, but otherwise this is not such a
# good idea, as it will be read by the next run
#print FH 'warn "# cache: Cached: ".join("|", sort(keys(%l2h_cache)))."\n"'.";\n"
# if ($verbose);
print FH "\n1;\n";
# FIXME error condition not checked
close(FH);
}
# return cached html, if it exists for text, and if all pictures
# are there, as well
sub l2h_from_cache($$)
{
my $self = shift;
my $text = shift;
my $cached = $l2h_cache{$text};
if (defined($cached)) {
while ($cached =~ m/SRC="(.*?)"/g) {
my $cached_image_file_name = $1;
my $encoded_cached_image_file_name
= encode('UTF-8', $cached_image_file_name);
my $cached_image_path_string
= File::Spec->catfile($destination_directory_string,
$encoded_cached_image_file_name);
unless (-e $cached_image_path_string) {
return undef;
}
}
return $cached;
}
return undef;
}
1;