# -*-perl-*-
#+##############################################################################
#
# html32.pm: output HTML 3.2
#
# Copyright 2003, 2004, 2007, 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 .
#
# Originally written by Patrice Dumas.
#
#-##############################################################################
#
# TODO there are id attributes in many places in the default HTML output
# that should be replaced with to be compliant with HTML3.2.
# HTML3.2 is not very interesting as an output format, this file is mostly
# a check that the API allows to output different variants of HTML. Therefore
# it is not high priority to fix those cases, especially if it means copying
# a lot of code to replace id= with a separate anchor without changing anything
# else.
use strict;
# To check if there is no erroneous autovivification
#no autovivification qw(fetch delete exists store strict);
use Texinfo::Commands;
use Texinfo::Convert::Text;
texinfo_set_from_init_file('COMPLEX_FORMAT_IN_TABLE', 1);
texinfo_set_from_init_file('DOCTYPE', '');
texinfo_set_from_init_file('FRAMESET_DOCTYPE', texinfo_get_conf('DOCTYPE'));
texinfo_set_from_init_file('BODYTEXT', 'bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"');
texinfo_set_from_init_file('BEFORE_SHORT_TOC_LINES', '');
texinfo_set_from_init_file('AFTER_SHORT_TOC_LINES', '');
texinfo_set_from_init_file('BEFORE_TOC_LINES', '');
texinfo_set_from_init_file('AFTER_TOC_LINES', '');
# html version for latex2html
texinfo_set_from_init_file('L2H_HTML_VERSION', '3.2');
# no css, no class
texinfo_set_from_init_file('NO_CSS', 1);
texinfo_set_from_init_file('COPIABLE_LINKS', 0);
texinfo_set_from_init_file('NO_CUSTOM_HTML_ATTRIBUTE', 1);
# no accesskey in html 3.2
texinfo_set_from_init_file('USE_ACCESSKEY', 0);
texinfo_set_from_init_file('MENU_SYMBOL', '*');
texinfo_set_from_init_file('OPEN_QUOTE_SYMBOL', '`');
texinfo_set_from_init_file('CLOSE_QUOTE_SYMBOL', "'");
# " is not in html 3.2
sub html32_format_protect_text($$)
{
my $converter = shift;
my $text = shift;
$text =~ s/&/&/g;
$text =~ s/</g;
$text =~ s/>/>/g;
$text =~ s/\"/"/g;
$text =~ s/\f//g;
return $text;
}
texinfo_register_formatting_function('format_protect_text', \&html32_format_protect_text);
foreach my $command ('euro', 'geq', 'leq',
'bullet', 'equiv', 'expansion', 'minus', 'point', 'result', 'arrow',
'quotedblleft', 'quotedblright',
'quoteleft', 'quoteright',
'quotedblbase', 'quotesinglbase', 'guillemetleft', 'guillemetright',
'guillemotleft', 'guillemotright', 'guilsinglleft', 'guilsinglright') {
my $formatted_command = html32_format_protect_text(undef,
$Texinfo::Convert::Text::text_brace_no_arg_commands{$command});
texinfo_register_no_arg_command_formatting($command, undef, $formatted_command);
}
texinfo_register_no_arg_command_formatting('oe', undef, '');
texinfo_register_no_arg_command_formatting('OE', undef, '');
foreach my $dots ('dots') {
texinfo_register_no_arg_command_formatting($dots, undef, '...', 'small');
texinfo_register_no_arg_command_formatting($dots, 'preformatted', '...');
}
foreach my $context ('preformatted', 'normal') {
foreach my $command('sansserif', 'r') {
texinfo_register_style_command_formatting($command, undef, undef, $context);
}
texinfo_register_style_command_formatting('t', 'tt', undef, $context);
}
# no inodot in HTML3.2
texinfo_register_accent_command_formatting('dotless', '', '');
# reset BIG_RULE to HTML3.2 compatible rule if in TEXI2HTML mode
texinfo_register_handler('setup', \&html32_setup);
sub html32_setup($)
{
my $self = shift;
if (defined($self->get_conf('TEXI2HTML'))) {
$self->set_conf('BIG_RULE', '
');
}
return 0;
}
sub html32_format_separate_anchor($$;$)
{
my $self = shift;
my $id = shift;
my $class = shift;
# note that the classes argument will be ignored with NO_CSS
return $self->html_attribute_class('a', [$class])." name=\"$id\">";
}
texinfo_register_formatting_function('format_separate_anchor', \&html32_format_separate_anchor);
sub html32_convert_text($$$$)
{
my $self = shift;
my $type = shift;
my $element = shift;
my $text = shift;
# do that first because in verb and verbatim, type is 'raw'
if ($self->in_verbatim()) {
return &{$self->formatting_function('format_protect_text')}($self, $text);
}
return $text if ($self->in_raw());
$text = uc($text) if ($self->in_upper_case());
$text = &{$self->formatting_function('format_protect_text')}($self, $text);
if (!$self->in_code() and !$self->in_math()) {
$text =~ s/``/"/g;
$text =~ s/''/"/g;
$text =~ s/---/\x{1F}/g;
$text =~ s/--/-/g;
$text =~ s/\x{1F}/--/g;
}
if (!$self->in_preformatted()
and ($self->in_non_breakable_space()
or $self->in_space_protected())) {
$text .= ' ' if (chomp($text));
$text =~ s/ / /g;
}
return $text;
}
texinfo_register_type_formatting('text', \&html32_convert_text);
sub html32_convert_explained_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $with_explanation;
return '' if (!$args->[0] or !defined($args->[0]->{'normal'})
or $args->[0]->{'normal'} !~ /\S/);
if ($args->[1] and defined($args->[1]->{'string'})
and $args->[1]->{'string'} =~ /\S/) {
$with_explanation = 1;
}
my $result;
if ($with_explanation) {
$result = $self->convert_tree($self->gdt('{explained_string} ({explanation})',
{'explained_string' => $args->[0]->{'tree'},
'explanation' => $args->[1]->{'tree'} }));
} else {
$result = $args->[0]->{'normal'};
}
return $result;
}
foreach my $explained_command (keys(%Texinfo::Commands::explained_commands)) {
texinfo_register_command_formatting($explained_command,
\&html32_convert_explained_command);
}
# row in multitable. no thead/tbody in html 3.2
sub html32_convert_multitable_head_type($$$$) {
my $self = shift;
my $type = shift;
my $element = shift;
my $content = shift;
return $content if ($self->in_string());
if ($content =~ /\S/) {
return $content . "\n";
} else {
return '';
}
}
texinfo_register_type_formatting('multitable_head', \&html32_convert_multitable_head_type);
sub html32_convert_multitable_body_type($$$$) {
my $self = shift;
my $type = shift;
my $element = shift;
my $content = shift;
return $content if ($self->in_string());
if ($content =~ /\S/) {
return $content;
} else {
return '';
}
}
texinfo_register_type_formatting('multitable_body', \&html32_convert_multitable_body_type);
sub html32_convert_itemize_command($$$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $content = shift;
if ($self->in_string()) {
return $content;
}
return "\n";
}
texinfo_register_command_formatting('itemize', \&html32_convert_itemize_command);
sub html32_convert_tab_command($$$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $content = shift;
my $row = $command->{'parent'};
my $row_cmdname = $row->{'contents'}->[0]->{'cmdname'};
# FIXME is it right?
$content =~ s/^\s*//;
$content =~ s/\s*$//;
if ($self->in_string()) {
return $content;
}
if ($row_cmdname eq 'headitem') {
return "" . $content . ' | ';
} else {
return "" . $content . ' | ';
}
}
texinfo_register_command_formatting('tab',
\&html32_convert_tab_command);
sub html32_convert_item_command($$$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $content = shift;
if ($self->in_string()) {
return $content;
}
if ($command->{'parent'}->{'type'}
and $command->{'parent'}->{'type'} eq 'row') {
return &{$self->command_conversion('tab')}($self, $cmdname, $command,
$args, $content);
} elsif ($command->{'parent'}->{'cmdname'}
and $command->{'parent'}->{'cmdname'} eq 'itemize') {
my $prepend ;
my $itemize = $command->{'parent'};
if ($itemize->{'extra'}->{'command_as_argument'}
and $itemize->{'extra'}->{'command_as_argument'}->{'cmdname'} eq 'bullet') {
$prepend = '';
} else {
# Setting multiple expansion should not be needed, except in
# case of invalid constructs
$prepend = $self->convert_tree_new_formatting_context(
$itemize->{'args'}->[0],
$command->{'cmdname'}, 'item_prepended');
}
if ($content =~ /\S/) {
return '' . $prepend .' '. $content . '';
} else {
return '';
}
} else {
return &{$self->default_command_conversion($cmdname)}($self, $cmdname,
$command, $args, $content);
}
}
texinfo_register_command_formatting('item',
\&html32_convert_item_command);
texinfo_register_command_formatting('headitem',
\&html32_convert_item_command);
sub html32_convert_center_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
if ($self->in_string()) {
# FIXME use an API?
return $self->{'types_conversion'}->{'preformatted'}($self, $cmdname, $command,
$args->[0]->{'normal'}."\n");
} else {
return ''.$args->[0]->{'normal'}."\n
";
}
}
texinfo_register_command_formatting('center',
\&html32_convert_center_command);
my %html32_paragraph_style = (
'center' => 'center',
'flushleft' => 'left',
'flushright' => 'right',
);
sub html32_convert_paragraph_type($$$$)
{
my $self = shift;
my $type = shift;
my $element = shift;
my $content = shift;
$content = $self->get_associated_formatted_inline_content($element).$content;
if ($self->paragraph_number() == 1) {
my $in_format = $self->top_block_command();
if ($in_format) {
# no first paragraph in those environment to avoid extra spacing
if ($in_format eq 'itemize'
or $in_format eq 'enumerate'
or $in_format eq 'multitable') {
return $content;
}
}
}
return $content if ($self->in_string());
if ($content =~ /\S/) {
my $align = $self->in_align();
if ($align and $html32_paragraph_style{$align}) {
return "".$content."
";
} else {
return "".$content."
";
}
} else {
return '';
}
}
texinfo_register_type_formatting('paragraph', \&html32_convert_paragraph_type);
sub html32_convert_subtitle_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
return '' if (!$args->[0]);
if (!$self->in_string()) {
return "$args->[0]->{'normal'}
\n";
} else {
return $args->[0]->{'normal'};
}
}
texinfo_register_command_formatting('subtitle',
\&html32_convert_subtitle_command);
1;