\n"
. $footnote_text;
my $footnote_number_text;
if ($self->in_preformatted()) {
$footnote_number_text = "($number_in_doc)";
} else {
$footnote_number_text = "$number_in_doc";
}
return "$footnote_number_text";
}
$default_commands_conversion{'footnote'} = \&_convert_footnote_command;
sub _convert_uref_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my @args = @$args;
my $url_arg = shift @args;
my $text_arg = shift @args;
my $replacement_arg = shift @args;
my ($url, $text, $replacement);
$url = $url_arg->{'monospacestring'} if defined($url_arg);
$text = $text_arg->{'normal'} if defined($text_arg);
$replacement = $replacement_arg->{'normal'} if defined($replacement_arg);
$text = $replacement if (defined($replacement) and $replacement ne '');
$text = $url if (!defined($text) or $text eq '');
return $text if (!defined($url) or $url eq '');
return "$text ($url)" if ($self->in_string());
return "$text";
}
$default_commands_conversion{'uref'} = \&_convert_uref_command;
$default_commands_conversion{'url'} = \&_convert_uref_command;
my @image_files_extensions = ('.png', '.jpg', '.jpeg', '.gif');
sub _convert_image_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my @extensions = @image_files_extensions;
if (defined($args->[0]->{'monospacetext'}) and $args->[0]->{'monospacetext'} ne '') {
my $basefile = $args->[0]->{'monospacetext'};
return $basefile if ($self->in_string());
my $extension;
if (defined($args->[4]) and defined($args->[4]->{'monospacetext'})) {
$extension = $args->[4]->{'monospacetext'};
unshift @extensions, ("$extension", ".$extension");
}
my $image_file;
foreach my $extension (@extensions) {
if ($self->Texinfo::Common::locate_include_file ($basefile.$extension)) {
# use the basename and not the file found. It is agreed that it is
# better, since in any case the files are moved.
$image_file = $basefile.$extension;
last;
}
}
if (!defined($image_file) or $image_file eq '') {
if (defined($extension) and $extension ne '') {
$image_file = "$basefile.$extension";
} else {
$image_file = "$basefile.jpg";
}
#cluck "err ($self->{'ignore_notice'})";
$self->line_warn(sprintf(
$self->__("\@image file `%s' (for HTML) not found, using `%s'"),
$basefile, $image_file), $command->{'line_nr'});
}
if (defined($self->get_conf('IMAGE_LINK_PREFIX'))) {
$image_file = $self->get_conf('IMAGE_LINK_PREFIX') . $image_file;
}
if ($self->in_preformatted()) {
my $alt_text;
if (defined($args->[3]) and defined($args->[3]->{'normal'})) {
$alt_text = $args->[3]->{'normal'};
}
if (!defined($alt_text) or ($alt_text eq '')) {
$alt_text = $self->protect_text($basefile);
}
return "[ $alt_text ]";
} else {
my $alt_string;
if (defined($args->[3]) and defined($args->[3]->{'string'})) {
$alt_string = $args->[3]->{'string'};
}
if (!defined($alt_string) or ($alt_string eq '')) {
$alt_string = $self->protect_text($basefile);
}
return "protect_text($image_file)."\" alt=\"$alt_string\">";
}
}
return '';
}
$default_commands_conversion{'image'} = \&_convert_image_command;
#sub _convert_math_command($$$$)
#{
# my $self = shift;
# my $cmdname = shift;
# my $command = shift;
# my $args = shift;
#
# return $args->[0]->{'normal'};
#}
#$default_commands_conversion{'math'} = \&_convert_math_command;
sub _convert_accent_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
return $self->xml_accents($command, $self->in_upper_case());
}
foreach my $command (keys(%accent_commands)) {
$default_commands_conversion{$command} = \&_convert_accent_command;
}
# key is formatted as code since it is in code_style_commands
sub _convert_key_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $text = $args->[0]->{'normal'};
if (!defined($text)) {
# happens with bogus @-commands without argument, like @strong something
#print STDERR Texinfo::Parser::_print_current($command);
return '';
}
if ($self->in_string()) {
return $text;
}
#return $self->protect_text('<') .$text .$self->protect_text('>');
my $class = $cmdname;
if (!$self->in_code()) {
return $self->_attribute_class('tt', $class).'>'.$text .'';;
} else {
my $open = $self->_attribute_class('span', $class);
if ($open ne '') {
return $open.'>'.$text.'';
} else {
return $text;
}
}
}
$default_commands_conversion{'key'} = \&_convert_key_command;
# argument is formatted as code since indicateurl is in code_style_commands
sub _convert_indicateurl_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $text = $args->[0]->{'normal'};
if (!defined($text)) {
# happens with bogus @-commands without argument, like @strong something
#print STDERR Texinfo::Parser::_print_current($command);
return '';
}
if (!$self->in_string()) {
return $self->get_conf('OPEN_QUOTE_SYMBOL').'' .$text
.''.$self->get_conf('CLOSE_QUOTE_SYMBOL');
} else {
return $self->get_conf('OPEN_QUOTE_SYMBOL').$text.
$self->get_conf('CLOSE_QUOTE_SYMBOL');
}
}
$default_commands_conversion{'indicateurl'} = \&_convert_indicateurl_command;
sub _convert_ctrl_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $text = $args->[0]->{'normal'};
if (!defined($text)) {
# happens with bogus @-commands without argument, like @strong something
#print STDERR Texinfo::Parser::_print_current($command);
return '';
}
return $self->protect_text('^') .$text;
}
$default_commands_conversion{'ctrl'} = \&_convert_ctrl_command;
sub _convert_titlefont_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $text = $args->[0]->{'normal'};
if (!defined($text)) {
# happens with bogus @-commands without argument, like @strong something
#print STDERR Texinfo::Parser::_print_current($command);
return '';
}
return &{$self->{'format_heading_text'}}($self, 'titlefont', $text, 0, $command);
}
$default_commands_conversion{'titlefont'} = \&_convert_titlefont_command;
sub _convert_U_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $arg = $args->[0]->{'normal'};
my $res;
if (defined($arg) && $arg) {
# checks on the value already done in Parser, just output it here.
$res = "$arg;";
} else {
$res = '';
}
return $res;
}
$default_commands_conversion{'U'} = \&_convert_U_command;
sub _default_comment($$) {
my $self = shift;
my $text = shift;
return $self->xml_comment(' '.$text);
}
sub protect_text($$) {
my $self = shift;
my $text = shift;
return &{$self->{'format_protect_text'}}($self, $text);
}
sub _default_protect_text($$) {
my $self = shift;
my $text = shift;
my $result = $self->xml_protect_text($text);
$result =~ s/\f//g;
return $result;
}
sub _default_heading_text($$$$$)
{
my $self = shift;
my $cmdname = shift;
my $text = shift;
my $level = shift;
my $command = shift;
return '' if ($text !~ /\S/);
# This should seldom happen.
if ($self->in_string()) {
$text .= "\n" unless ($cmdname eq 'titlefont');
return $text;
}
my $class;
if ($cmdname eq 'node') {
$class = 'node-heading';
} else {
$class = $cmdname;
}
my $align = '';
$align = ' align="center"' if ($cmdname eq 'centerchap' or $cmdname eq 'settitle');
if ($level < 1) {
$level = 1;
} elsif ($level > $self->get_conf('MAX_HEADER_LEVEL')) {
$level = $self->get_conf('MAX_HEADER_LEVEL');
}
my $result = $self->_attribute_class("h$level", $class) ."$align>$text";
# titlefont appears inline in text, so no end of line is
# added. The end of line should be added by the user if needed.
$result .= "\n" unless ($cmdname eq 'titlefont');
$result .= $self->get_conf('DEFAULT_RULE') . "\n"
if ($cmdname eq 'part'
and defined($self->get_conf('DEFAULT_RULE'))
and $self->get_conf('DEFAULT_RULE') ne '');
return $result;
}
# Associated to a button
sub _default_node_direction($$)
{
my $self = shift;
my $direction = shift;
my $result = undef;
my $href = $self->_element_direction($self->{'current_element'},
$direction, 'href');
my $node = $self->_element_direction($self->{'current_element'},
$direction, 'node');
my $anchor;
if (defined($href) and defined($node) and $node =~ /\S/) {
my $anchor_attributes = $self->_direction_href_attributes($direction);
$anchor = "$node";
#} elsif (defined($node) and $node =~ /\S/) {
# $anchor = $node;
#} else {
}
if (defined($anchor)) {
# i18n
$result = $self->get_conf('BUTTONS_TEXT')->{$direction}.": $anchor";
}
return $result;
}
# how to create IMG tag
# this is only used in html, and only if ICONS is set and the button
# is active.
sub _default_button_icon_img($$$;$)
{
my $self = shift;
my $button = shift;
my $icon = shift;
my $name = shift;
return '' if (!defined($icon));
$button = "" if (!defined ($button));
$name = '' if (!defined($name));
my $alt = '';
if ($name ne '') {
if ($button ne '') {
$alt = "$button: $name";
} else {
$alt = $name;
}
} else {
$alt = $button;
}
return qq{};
}
sub _direction_href_attributes($$)
{
my $self = shift;
my $direction = shift;
my $href_attributes = '';
if ($self->get_conf('USE_ACCESSKEY')
and $self->get_conf('BUTTONS_ACCESSKEY')) {
my $accesskey = $self->get_conf('BUTTONS_ACCESSKEY')->{$direction};
if (defined($accesskey) and ($accesskey ne '')) {
$href_attributes = " accesskey=\"$accesskey\"";
}
}
if ($self->get_conf('USE_REL_REV') and $self->get_conf('BUTTONS_REL')) {
my $button_rel = $self->get_conf('BUTTONS_REL')->{$direction};
if (defined($button_rel) and ($button_rel ne '')) {
$href_attributes .= " rel=\"$button_rel\"";
}
}
return $href_attributes;
}
sub _default_button_formatting($$)
{
my $self = shift;
my $button = shift;
my ($active, $passive);
if (ref($button) eq 'CODE') {
$active = &$button($self);
} elsif (ref($button) eq 'SCALAR') {
$active = "$$button" if defined($$button);
} elsif (ref($button) eq 'ARRAY' and scalar(@$button == 2)) {
my $text = $button->[1];
my $button_href = $button->[0];
# verify that $button_href is simple text and text is a reference
if (defined($button_href) and !ref($button_href)
and defined($text) and (ref($text) eq 'SCALAR') and defined($$text)) {
# use given text
my $href = $self->_element_direction($self->{'current_element'},
$button_href, 'href');
if ($href) {
my $anchor_attributes = $self->_direction_href_attributes($button_href);
$active = "$$text";
} else {
$passive = $$text;
}
# button_href is simple text and text is a reference on code
} elsif (defined($button_href) and !ref($button_href)
and defined($text) and (ref($text) eq 'CODE')) {
$active = &$text($self, $button_href);
# button_href is simple text and text is also a simple text
} elsif (defined($button_href) and !ref($button_href)
and defined($text) and !ref($text)) {
if ($text =~ s/^->\s*//) {
$active = $self->_element_direction($self->{'current_element'},
$button_href, $text);
} else {
my $href = $self->_element_direction($self->{'current_element'},
$button_href, 'href');
my $text_formatted = $self->_element_direction($self->{'current_element'},
$button_href, $text);
if ($href) {
my $anchor_attributes = $self->_direction_href_attributes($button_href);
$active = "$text_formatted";
} else {
$passive = $text_formatted;
}
}
}
} elsif ($button eq ' ') {
# handle space button
if ($self->get_conf('ICONS') and $self->get_conf('ACTIVE_ICONS')
and defined($self->get_conf('ACTIVE_ICONS')->{$button})
and $self->get_conf('ACTIVE_ICONS')->{$button} ne '') {
my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
$active = &{$self->{'format_button_icon_img'}}($self, $button_name,
$self->get_conf('ACTIVE_ICONS')->{' '});
} else {
$active = $self->get_conf('BUTTONS_TEXT')->{$button};
}
} else {
my $href = $self->_element_direction($self->{'current_element'},
$button, 'href');
if ($href) {
# button is active
my $btitle = '';
if ($self->get_conf('BUTTONS_GOTO')
and defined($self->get_conf('BUTTONS_GOTO')->{$button})) {
$btitle = ' title="' . $self->get_conf('BUTTONS_GOTO')->{$button} . '"';
}
if ($self->get_conf('USE_ACCESSKEY') and $self->get_conf('BUTTONS_ACCESSKEY')) {
my $accesskey = $self->get_conf('BUTTONS_ACCESSKEY')->{$button};
if (defined($accesskey) and $accesskey ne '') {
$btitle .= " accesskey=\"$accesskey\"";
}
}
if ($self->get_conf('USE_REL_REV') and ($self->get_conf('BUTTONS_REL'))) {
my $button_rel = $self->get_conf('BUTTONS_REL')->{$button};
if (defined($button_rel) and $button_rel ne '') {
$btitle .= " rel=\"$button_rel\"";
}
}
my $use_icon;
if ($self->get_conf('ICONS') and $self->get_conf('ACTIVE_ICONS')
and $self->get_conf('BUTTONS_NAME')) {
my $active_icon = $self->get_conf('ACTIVE_ICONS')->{$button};
my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
if (defined($active_icon) and $active_icon ne ''
and defined($button_name)) {
# use icon
$active = "".
&{$self->{'format_button_icon_img'}}($self, $button_name, $active_icon,
$self->_element_direction($self->{'current_element'},
$button, 'string')) ."";
$use_icon = 1;
}
}
if (!$use_icon) {
# use text
$active = '[' . "".
$self->get_conf('BUTTONS_TEXT')->{$button}."" . ']';
}
} else {
# button is passive
my $use_icon;
if ($self->get_conf('ICONS') and $self->get_conf('PASSIVE_ICONS')
and $self->get_conf('BUTTONS_NAME')) {
my $passive_icon = $self->get_conf('PASSIVE_ICONS')->{$button};
my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
if ($passive_icon and $passive_icon ne '') {
$passive = &{$self->{'format_button_icon_img'}}($self, $button_name,
$passive_icon,
$self->_element_direction($self->{'current_element'},
$button, 'string'));
$use_icon = 1;
}
}
if (!$use_icon) {
$passive = '[' . $self->get_conf('BUTTONS_TEXT')->{$button} . ']';
}
}
}
return ($active, $passive);
}
my %html_default_node_directions;
foreach my $node_directions ('NodeNext', 'NodePrev', 'NodeUp') {
$html_default_node_directions{$node_directions} = 1;
}
sub _default_navigation_header_panel($$$$;$)
{
my $self = shift;
my $buttons = shift;
my $cmdname = shift;
my $command = shift;
my $vertical = shift;
# if VERTICAL_HEAD_NAVIGATION, the buttons are in a vertical table which
# is itself in the first column of a table opened in header_navigation
#my $vertical = $self->get_conf('VERTICAL_HEAD_NAVIGATION');
my $first_button = 1;
my $result = '';
if ($self->get_conf('HEADER_IN_TABLE')) {
$result .= $self->_attribute_class('table', 'header')
.' cellpadding="1" cellspacing="1" border="0">'."\n";
$result .= "
\n";
}
foreach my $button (@$buttons) {
if ($self->get_conf('HEADER_IN_TABLE')) {
$result .= qq{
\n} if $vertical;
$result .= qq{
};
}
my $direction;
if (ref($button) eq 'ARRAY'
and defined($button->[0]) and !ref($button->[0])) {
$direction = $button->[0];
} elsif (defined($button) and !ref($button)) {
$direction = $button;
}
my ($active, $passive) = &{$self->{'format_button'}}($self, $button);
if ($self->get_conf('HEADER_IN_TABLE')) {
if (defined($active)) {
$first_button = 0 if ($first_button);
$result .= $active;
} elsif (defined($passive)) {
$first_button = 0 if ($first_button);
$result .= $passive;
}
$result .= "
\n";
$result .= "
\n" if $vertical;
} elsif (defined($active)) {
# only active buttons are print out when not in table
if (defined($direction)
and $html_default_node_directions{$direction} and !$first_button) {
$active = ', ' .$active;
}
$result .= $active;
$first_button = 0 if ($first_button);
}
}
if ($self->get_conf('HEADER_IN_TABLE')) {
$result .= "" unless $vertical;
$result .= "\n";
} else {
$result .= "
\n\n";
}
return $result;
}
sub _default_navigation_header($$$$)
{
my $self = shift;
my $buttons = shift;
my $cmdname = shift;
my $command = shift;
my $result = '';
if ($self->get_conf('VERTICAL_HEAD_NAVIGATION')) {
$result .= '
';
} elsif ($self->get_conf('SPLIT') eq 'node') {
$result .= $self->get_conf('DEFAULT_RULE')."\n";
}
return $result;
}
sub _default_element_header($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $element = shift;
my $result = '';
print STDERR "Element $element (@{$element->{'contents'}}) ".
Texinfo::Structuring::_print_element_command_texi($element) ."\n"
if ($self->get_conf('DEBUG'));
# Do the heading if the command is the first command in the element
if (($element->{'contents'}->[0] eq $command
or (!$element->{'contents'}->[0]->{'cmdname'}
and $element->{'contents'}->[1] eq $command))
# and there is more than one element
and ($element->{'element_next'} or $element->{'element_prev'})) {
my $is_top = $self->element_is_top($element);
my $first_in_page = (defined($element->{'filename'})
and $self->{'counter_in_file'}->{$element->{'filename'}} == 1);
my $previous_is_top = ($element->{'element_prev'}
and $self->element_is_top($element->{'element_prev'}));
print STDERR "Header ($previous_is_top, $is_top, $first_in_page): "
.Texinfo::Structuring::_print_root_command_texi($command)."\n"
if ($self->get_conf('DEBUG'));
if ($is_top) {
# use TOP_BUTTONS for top.
$result .= &{$self->{'format_navigation_header'}}($self,
$self->get_conf('TOP_BUTTONS'), $cmdname, $command)
if ($self->get_conf('SPLIT') or $self->get_conf('HEADERS'));
} else {
if ($first_in_page and !$self->get_conf('HEADERS')) {
if ($self->get_conf('SPLIT') eq 'chapter') {
$result .= &{$self->{'format_navigation_header'}}($self,
$self->get_conf('CHAPTER_BUTTONS'), $cmdname, $command);
$result .= $self->get_conf('DEFAULT_RULE') ."\n"
if (defined($self->get_conf('DEFAULT_RULE'))
and !$self->get_conf('VERTICAL_HEAD_NAVIGATION'));
} elsif ($self->get_conf('SPLIT') eq 'section') {
$result .= &{$self->{'format_navigation_header'}}($self,
$self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
}
}
if (($first_in_page or $previous_is_top)
and $self->get_conf('HEADERS')) {
$result .= &{$self->{'format_navigation_header'}}($self,
$self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
} elsif($self->get_conf('HEADERS') or $self->get_conf('SPLIT') eq 'node') {
# got to do this here, as it isn't done otherwise since
# navigation_header is not called
$result .= &{$self->{'format_navigation_header_panel'}}($self,
$self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
}
}
}
return $result;
}
sub _convert_heading_command($$$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $content = shift;
my $result = '';
# not clear that it may really happen
if ($self->in_string) {
$result .= $self->command_string($command) ."\n" if ($cmdname ne 'node');
$result .= $content if (defined($content));
return $result;
}
my $element_id = $self->command_id($command);
$result .= "\n"
if (defined($element_id) and $element_id ne '');
print STDERR "Process $command "
.Texinfo::Structuring::_print_root_command_texi($command)."\n"
if ($self->get_conf('DEBUG'));
my $element;
if ($Texinfo::Common::root_commands{$command->{'cmdname'}}
and $command->{'parent'}
and $command->{'parent'}->{'type'}
and $command->{'parent'}->{'type'} eq 'element') {
$element = $command->{'parent'};
}
if ($element) {
$result .= &{$self->{'format_element_header'}}($self, $cmdname,
$command, $element);
}
my $heading_level;
# node is used as heading if there is nothing else.
if ($cmdname eq 'node') {
if (!$element or (!$element->{'extra'}->{'section'}
and $element->{'extra'}->{'node'}
and $element->{'extra'}->{'node'} eq $command
# bogus node may not have been normalized
and defined($command->{'extra'}->{'normalized'}))) {
if ($command->{'extra'}->{'normalized'} eq 'Top') {
$heading_level = 0;
} else {
$heading_level = 3;
}
}
} else {
$heading_level = $command->{'level'};
}
my $heading = $self->command_text($command);
# $heading not defined may happen if the command is a @node, for example
# if there is an error in the node.
if (defined($heading) and $heading ne '' and defined($heading_level)) {
if ($self->get_conf('TOC_LINKS')
and $Texinfo::Common::root_commands{$cmdname}
and $Texinfo::Common::sectioning_commands{$cmdname}) {
my $content_href = $self->command_contents_href($command, 'contents',
$self->{'current_filename'});
if ($content_href) {
$heading = "$heading";
}
}
if ($self->in_preformatted()) {
$result .= ''.$heading.''."\n";
} else {
# if the level was changed, set the command name right
if ($cmdname ne 'node'
and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
$cmdname
= $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
}
$result .= &{$self->{'format_heading_text'}}($self, $cmdname, $heading,
$heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1, $command);
}
}
$result .= $content if (defined($content));
return $result;
}
foreach my $command (keys(%sectioning_commands), 'node') {
$default_commands_conversion{$command} = \&_convert_heading_command;
}
sub _convert_raw_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
if ($cmdname eq $self->{'output_format'}) {
chomp ($content);
return $content;
}
$self->line_warn(sprintf($self->__("raw format %s is not converted"),
$cmdname), $command->{'line_nr'});
return $self->protect_text($content);
}
foreach my $command (keys(%format_raw_commands)) {
$default_commands_conversion{$command} = \&_convert_raw_command;
}
sub _convert_inline_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $format_arg = shift @$args;
my $format;
if (defined($format_arg)) {
$format = $format_arg->{'monospacetext'};
}
return '' if (!defined($format) or $format eq '');
my $arg_index = undef;
if ($inline_format_commands{$cmdname}) {
if ($cmdname eq 'inlinefmtifelse'
and ! $self->{'expanded_formats_hash'}->{$format}) {
$arg_index = 1;
} elsif ($self->{'expanded_formats_hash'}->{$format}) {
$arg_index = 0;
}
} elsif (defined($command->{'extra'}->{'expand_index'})) {
$arg_index = 0;
}
if (defined($arg_index) and $arg_index < scalar(@$args)) {
my $text_arg = $args->[$arg_index];
if ($text_arg) {
if ($text_arg->{'normal'}) {
return $text_arg->{'normal'};
} elsif ($text_arg->{'raw'}) {
return $text_arg->{'raw'};
}
}
}
return '';
}
foreach my $command (keys(%inline_commands)) {
$default_commands_conversion{$command} = \&_convert_inline_command;
}
sub _indent_with_table ($)
{
my $content = shift;
return '
'.$content."
\n";
}
my $html_menu_entry_index = 0;
sub _convert_preformatted_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
if ($cmdname eq 'menu') {
$html_menu_entry_index = 0;
}
if ($content ne '' and !$self->in_string()) {
if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) {
if ($indented_preformatted_commands{$cmdname}) {
return _indent_with_table ($content);
} else {
return $content."\n";
}
} else {
return $self->_attribute_class('div', $cmdname).">\n".$content.''."\n";
}
} else {
return $content;
}
}
foreach my $preformatted_command (keys(%preformatted_commands)) {
$default_commands_conversion{$preformatted_command}
= \&_convert_preformatted_command;
}
sub _convert_indented_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
if ($content ne '' and !$self->in_string()) {
if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) {
return _indent_with_table ($content);
} else {
return $self->_attribute_class('blockquote', $cmdname).">\n"
.$content.''."\n";
}
} else {
return $content;
}
}
$default_commands_conversion{'indentedblock'} = \&_convert_indented_command;
$default_commands_conversion{'smallindentedblock'}
= \&_convert_indented_command;
sub _convert_verbatim_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
if (!$self->in_string) {
return $self->_attribute_class('pre', $cmdname).'>'
.$content . '';
} else {
return $content;
}
}
$default_commands_conversion{'verbatim'} = \&_convert_verbatim_command;
sub _convert_verbatiminclude_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
my $verbatim_include_verbatim
= $self->Texinfo::Common::expand_verbatiminclude($command);
if (defined($verbatim_include_verbatim)) {
return $self->convert_tree($verbatim_include_verbatim);
} else {
return '';
}
}
$default_commands_conversion{'verbatiminclude'}
= \&_convert_verbatiminclude_command;
sub _convert_command_noop($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
return $content;
}
$default_commands_conversion{'raggedright'} = \&_convert_command_noop;
$default_commands_conversion{'flushleft'} = \&_convert_command_noop;
$default_commands_conversion{'flushright'} = \&_convert_command_noop;
$default_commands_conversion{'group'} = \&_convert_command_noop;
sub _convert_sp_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
if (defined($command->{'extra'}->{'misc_args'}->[0])) {
my $sp_nr = $command->{'extra'}->{'misc_args'}->[0];
if ($self->in_preformatted() or $self->in_string()) {
return "\n" x $sp_nr;
} else {
return " \n" x $sp_nr;
}
}
}
$default_commands_conversion{'sp'} = \&_convert_sp_command;
sub _convert_exdent_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
# FIXME do something better with css and span?
my $preformatted = $self->in_preformatted();
if ($self->in_preformatted() or $self->in_string()) {
return $self->_convert_preformatted_type($cmdname, $command,
$args->[0]->{'normal'} ."\n");
} else {
# ignore alignment information
return "
".$args->[0]->{'normal'} ."\n
";
}
}
$default_commands_conversion{'exdent'} = \&_convert_exdent_command;
sub _convert_center_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
if ($self->in_string()) {
return $self->_convert_preformatted_type($cmdname, $command,
$args->[0]->{'normal'}."\n");
} else {
return "
".$args->[0]->{'normal'}."\n
";
}
}
$default_commands_conversion{'center'} = \&_convert_center_command;
sub _convert_author_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
return '' if (!$args->[0] or !$command->{'extra'}->{'titlepage'});
if (!$self->in_string()) {
return "$args->[0]->{'normal'} \n";
} else {
return $args->[0]->{'normal'}."\n";
}
}
$default_commands_conversion{'author'} = \&_convert_author_command;
sub _convert_title_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'};
}
}
$default_commands_conversion{'title'} = \&_convert_title_command;
sub _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'};
}
}
$default_commands_conversion{'subtitle'} = \&_convert_subtitle_command;
sub _convert_insertcopying_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
if ($self->{'extra'} and $self->{'extra'}->{'copying'}) {
return $self->convert_tree({'contents'
=> $self->{'extra'}->{'copying'}->{'contents'}});
}
return '';
}
$default_commands_conversion{'insertcopying'}
= \&_convert_insertcopying_command;
sub _convert_listoffloats_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $args = shift;
if (!$self->in_string()
and $command->{'extra'} and $command->{'extra'}->{'type'}
and defined($command->{'extra'}->{'type'}->{'normalized'})
and $self->{'floats'}
and $self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}}
and @{$self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}}}) {
my $listoffloats_name = $command->{'extra'}->{'type'}->{'normalized'};
my $result = $self->_attribute_class('dl', 'listoffloats').">\n" ;
foreach my $float (@{$self->{'floats'}->{$listoffloats_name}}) {
my $float_href = $self->command_href($float);
next if (!$float_href);
$result .= '
';
my $float_text = $self->command_text($float);
if (defined($float_text) and $float_text ne '') {
if ($float_href) {
$result .= "$float_text";
} else {
$result .= $float_text;
}
}
$result .= '
';
my $caption;
if ($float->{'extra'}->{'shortcaption'}) {
$caption = $float->{'extra'}->{'shortcaption'};
} elsif ($float->{'extra'}->{'caption'}) {
$caption = $float->{'extra'}->{'caption'};
}
my $caption_text;
if ($caption) {
$caption_text = $self->convert_tree_new_formatting_context(
$caption->{'args'}->[0], $cmdname, 'listoffloats');
} else {
$caption_text = '';
}
$result .= '
'.$caption_text.'
'."\n";
}
return $result . "\n";
} else {
return '';
}
}
$default_commands_conversion{'listoffloats'} = \&_convert_listoffloats_command;
sub _in_preformatted_in_menu($)
{
my $self = shift;
return 1 if ($self->get_conf('SIMPLE_MENU'));
my @pre_classes = $self->preformatted_classes_stack();
foreach my $pre_class (@pre_classes) {
return 1 if ($preformatted_commands{$pre_class});
}
return 0;
}
sub _convert_menu_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
return $content if ($cmdname eq 'detailmenu');
$html_menu_entry_index = 0;
if ($content !~ /\S/) {
return '';
}
if ($self->in_string()) {
return $content;
}
my $begin_row = '';
my $end_row = '';
if ($self->_in_preformatted_in_menu()) {
$begin_row = '
\n";
foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) {
my $letter = $letter_entry->{'letter'};
my $entries_text = '';
foreach my $index_entry_ref (@{$letter_entry->{'entries'}}) {
# to avoid double error messages set ignore_notice if an entry was
# already formatted once, for example if there are multiple printindex.
my $already_formatted;
if (!$formatted_index_entries{$index_entry_ref}) {
$formatted_index_entries{$index_entry_ref} = 1;
} else {
$already_formatted = 1;
$self->{'ignore_notice'}++;
}
my $entry;
if ($index_entry_ref->{'in_code'}) {
$entry = $self->convert_tree({'type' => '_code',
'contents' => $index_entry_ref->{'content'}});
} else {
$entry = $self->convert_tree({'contents' => $index_entry_ref->{'content'}});
}
if ($already_formatted) {
$self->{'ignore_notice'}--;
}
next if ($entry !~ /\S/);
$entry = '' .$entry .'' if ($index_entry_ref->{'in_code'});
my $entry_href = $self->command_href($index_entry_ref->{'command'});
my $associated_command;
if ($self->get_conf('NODE_NAME_IN_INDEX')) {
$associated_command = $index_entry_ref->{'node'};
if (!defined($associated_command)) {
$associated_command
= $self->command_node($index_entry_ref->{'command'});
}
}
if (!$associated_command) {
$associated_command
= $self->command_element_command($index_entry_ref->{'command'});
if (!$associated_command) {
# Use Top if not associated command found
$associated_command
= $self->element_command($self->global_element('Top'));
}
}
my ($associated_command_href, $associated_command_text);
if ($associated_command) {
$associated_command_href = $self->command_href($associated_command);
$associated_command_text = $self->command_text($associated_command);
}
$entries_text .= '
\n";
}
$result .= "\n";
pop @{$self->{'document_context'}};
return $result .$summary;
}
$default_commands_conversion{'printindex'} = \&_convert_printindex_command;
sub _contents_inline_element($$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = &{$self->{'format_contents'}}($self, $cmdname, $command);
if ($content) {
my $result = '';
my $element_name = $contents_command_element_name{$cmdname};
my $special_element
= $self->special_element($element_name);
my $heading;
if ($special_element) {
my $id = $self->command_id($special_element);
if ($id ne '') {
$result .= "\n";
}
$heading = $self->command_text($special_element);
} else {
# happens when called as convert() and not output()
#cluck "$cmdname special element not defined";
$heading
= $self->convert_tree ($self->get_conf('SPECIAL_ELEMENTS_NAME')->{$element_name});
}
my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{$element_name};
$result .= &{$self->{'format_heading_text'}}($self, $class.'-heading',
$heading, $self->get_conf('CHAPTER_HEADER_LEVEL'))."\n";
$result .= $content . "\n";
return $result;
}
return '';
}
sub _convert_informative_command($$$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
return '' if ($self->in_string());
$cmdname = 'shortcontents' if ($cmdname eq 'summarycontents');
$self->_informative_command($command);
if ($self->get_conf('INLINE_CONTENTS')
and ($cmdname eq 'contents' or $cmdname eq 'shortcontents')
and $self->get_conf($cmdname)
and $self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1
and ! $self->get_conf('set'.$cmdname.'aftertitlepage')) {
return $self->_contents_inline_element($cmdname, $command);
}
if ($cmdname eq 'documentlanguage') {
$self->_translate_names();
}
return '';
}
foreach my $informative_command (@informative_global_commands) {
$default_commands_conversion{$informative_command}
= \&_convert_informative_command;
}
my %default_types_conversion;
sub default_types_conversion($$)
{
my $self = shift;
my $type = shift;
return $default_types_conversion{$type};
}
# Ignored commands
#my %ignored_types;
foreach my $type ('empty_line_after_command', 'preamble',
'preamble_before_setfilename',
'empty_spaces_after_command', 'spaces_at_end',
'empty_spaces_before_argument', 'empty_spaces_before_paragraph',
'empty_spaces_after_close_brace',
'empty_space_at_end_def_bracketed') {
#$ignored_types{$type} = 1;
$default_types_conversion{$type} = undef;
}
my %paragraph_style = (
'center' => 'center',
'flushleft' => 'left',
'flushright' => 'right',
);
sub _quotation_arg_to_prepend($$)
{
my $self = shift;
my $command = shift;
if ($command->{'parent'} and $command->{'parent'}->{'cmdname'}
and ($command->{'parent'}->{'cmdname'} eq 'quotation'
or $command->{'parent'}->{'cmdname'} eq 'smallquotation')
and $command->{'parent'}->{'extra'}
and $command->{'parent'}->{'extra'}->{'block_command_line_contents'}) {
return $self->convert_tree($self->gdt('@b{{quotation_arg}:} ',
{'quotation_arg' =>
$command->{'parent'}->{'extra'}->{'block_command_line_contents'}->[0]}));
}
return undef;
}
sub _convert_paragraph_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
if ($self->paragraph_number() == 1) {
my $in_format = $self->top_format();
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;
} else {
my $prepended = $self->_quotation_arg_to_prepend($command);
$content = $prepended.$content if (defined($prepended));
}
}
}
return $content if ($self->in_string());
if ($content =~ /\S/) {
my $align = $self->in_align();
if ($align and $paragraph_style{$align}) {
return "
".$content."
";
} else {
return "
".$content."
";
}
} else {
return '';
}
}
$default_types_conversion{'paragraph'} = \&_convert_paragraph_type;
sub _preformatted_class()
{
my $self = shift;
my $pre_class;
my @pre_classes = $self->preformatted_classes_stack();
foreach my $class (@pre_classes) {
# FIXME maybe add or $pre_class eq 'menu-preformatted' to override
# 'menu-preformatted' with 'menu-comment'?
$pre_class = $class unless ($pre_class
and $preformatted_code_commands{$pre_class}
and !($preformatted_code_commands{$class}
or $class eq 'menu-preformatted'));
}
return $pre_class;
}
sub _convert_preformatted_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
if (!defined($content)) {
cluck "content undef in _convert_preformatted_type "
.Texinfo::Parser::_print_current($command);
}
my $current = $command;
# !defined preformatted_number may happen if there is something before the
# first preformatted. For example an @exdent.
if ($self->preformatted_number() and $self->preformatted_number() == 1) {
my $prepended = $self->_quotation_arg_to_prepend($command);
$content = $prepended.$content if (defined($prepended));
}
return '' if ($content eq '');
return $content if ($type eq 'rawpreformatted');
my $pre_class = $self->_preformatted_class();
if ($self->top_format() eq 'multitable') {
$content =~ s/^\s*//;
$content =~ s/\s*$//;
}
# menu_entry_description is always in a preformatted container
# in the tree, as the whole menu is meant to be an
# environment where spaces and newlines are preserved.
#
# However, if not in preformatted block command (nor in SIMPLE_MENU),
# we don't preserve spaces and newlines in menu_entry_description,
# instead the whole menu_entry is in a table, so here, not
if ($command->{'parent'}->{'type'}
and $command->{'parent'}->{'type'} eq 'menu_entry_description'
and !$self->_in_preformatted_in_menu()) {
return $content;
}
if ($self->in_string()) {
return $content;
}
my $result = $self->_attribute_class('pre', $pre_class).">".$content."
";
# this may happen with lines without textual content
# between a def* and def*x.
if ($command->{'parent'}->{'cmdname'}
and $command->{'parent'}->{'cmdname'} =~ /^def/) {
$result = '
'.$result.'
';
}
return $result;
}
$default_types_conversion{'preformatted'} = \&_convert_preformatted_type;
$default_types_conversion{'rawpreformatted'} = \&_convert_preformatted_type;
sub _convert_bracketed_type($$$$) {
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
#print STDERR "$self $type $command $content\n";
return '{'.$content.'}';
}
$default_types_conversion{'bracketed'} = \&_convert_bracketed_type;
sub _convert_definfoenclose_type($$$$) {
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
return $self->protect_text($command->{'extra'}->{'begin'}) . $content
.$self->protect_text($command->{'extra'}->{'end'});
}
$default_types_conversion{'definfoenclose_command'}
= \&_convert_definfoenclose_type;
sub _convert_text($$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $text = shift;
if ($self->in_verbatim()) {
return $self->protect_text($text);
}
return $text if ($self->in_raw());
$text = uc($text) if ($self->in_upper_case());
$text = $self->protect_text($text);
if ($self->get_conf('ENABLE_ENCODING') and
!$self->get_conf('ENABLE_ENCODING_USE_ENTITY')
and $self->get_conf('OUTPUT_ENCODING_NAME')
and $self->get_conf('OUTPUT_ENCODING_NAME') eq 'utf-8') {
$text = Texinfo::Convert::Unicode::unicode_text($text,
($self->in_code() or $self->in_math()));
} elsif (!$self->in_code() and !$self->in_math()) {
if ($self->get_conf('USE_ISO')) {
$text =~ s/---/\&mdash\;/g;
$text =~ s/--/\&ndash\;/g;
$text =~ s/``/\&ldquo\;/g;
$text =~ s/''/\&rdquo\;/g;
$text =~ s/'/\&rsquo\;/g;
$text =~ s/`/\&lsquo\;/g;
} else {
$text =~ s/``/"/g;
$text =~ s/''/"/g;
$text =~ s/---/\x{1F}/g;
$text =~ s/--/-/g;
$text =~ s/\x{1F}/--/g;
}
}
$text = $self->_protect_space_codebreak($text);
return $text;
}
$default_types_conversion{'text'} = \&_convert_text;
sub _simplify_text_for_comparison($)
{
my $text = shift;
$text =~ s/[^\w]//g;
return $text;
}
sub _convert_row_type($$$$) {
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
return $content if ($self->in_string());
if ($content =~ /\S/) {
my $row_cmdname = $command->{'contents'}->[0]->{'cmdname'};
if ($row_cmdname eq 'headitem') {
return '
' . $content . '
' . "\n";
} else {
return '
' . $content . '
' . "\n";
}
} else {
return '';
}
}
$default_types_conversion{'row'} = \&_convert_row_type;
sub _convert_menu_entry_type($$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $href;
my $node;
my $section;
my $node_entry = $command->{'extra'}->{'menu_entry_node'};
# external node
my $external_node;
if ($node_entry->{'manual_content'}) {
$href = $self->command_href($node_entry, undef, $command);
$external_node = 1;
} else {
$node = $self->label_command($node_entry->{'normalized'});
# if !NODE_NAME_IN_MENU, we pick the associated section, except if
# the node is the element command
if ($node->{'extra'}->{'associated_section'}
and !$self->get_conf('NODE_NAME_IN_MENU')
and !($self->command_element_command($node) eq $node)) {
$section = $node->{'extra'}->{'associated_section'};
$href = $self->command_href($section, undef, $command);
} else {
$href = $self->command_href($node, undef, $command);
}
}
$html_menu_entry_index++;
my $accesskey = '';
$accesskey = " accesskey=\"$html_menu_entry_index\""
if ($self->get_conf('USE_ACCESSKEY') and $html_menu_entry_index < 10);
my $MENU_SYMBOL = $self->get_conf('MENU_SYMBOL');
my $MENU_ENTRY_COLON = $self->get_conf('MENU_ENTRY_COLON');
if ($self->_in_preformatted_in_menu() or $self->in_string()) {
my $result = '';
my $i = 0;
my @args = @{$command->{'args'}};
while (@args) {
last if ($args[0]->{'type'}
and $args[0]->{'type'} eq 'menu_entry_description');
my $arg = shift @args;
if ($arg->{'type'} and $arg->{'type'} eq 'menu_entry_node') {
my $name = $self->convert_tree(
{'type' => '_code', 'contents' => $arg->{'contents'}});
if ($href ne '' and !$self->in_string()) {
$result .= "".$name."";
} else {
$result .= $name;
}
} elsif ($arg->{'type'} and $arg->{'type'} eq 'menu_entry_leading_text') {
my $text = $arg->{'text'};
$text =~ s/\*/$MENU_SYMBOL/;
$result .= $text;
} else {
$result .= $self->convert_tree($arg, "menu_arg preformatted [$i]");
}
$i++;
}
my $description = '';
foreach my $arg (@args) {
$description .= $self->convert_tree($arg, "menu_arg preformatted [$i]");
$i++;
}
if (!$self->get_conf('SIMPLE_MENU')) {
$description =~ s/^
";
}
return $result;
}
my $name;
my $name_no_number;
if ($section) {
#my $section_name = $self->command_text($section);
$name = $self->command_text($section);
$name_no_number = $self->command_text($section, 'text_nonumber');
if ($href ne '' and $name ne '') {
#$name = "".$section_name."";
$name = "".$name."";
}# else {
# $name = $section_name;
#}
#$name = "$MENU_SYMBOL ".$name if ($section_name eq $name_no_number);
}
if (!defined($name) or $name eq '') {
if ($command->{'extra'}->{'menu_entry_name'}) {
$name = $self->convert_tree($command->{'extra'}->{'menu_entry_name'});
}
if (!defined($name) or $name eq '') {
if ($node_entry->{'manual_content'}) {
$name = $self->command_text($node_entry);
} else {
$name = $self->convert_tree({'type' => '_code',
'contents' => $node_entry->{'node_content'}},
"menu_arg name");
}
}
$name =~ s/^\s*//;
$name_no_number = $name;
if ($href ne '') {
$name = "".$name."";
}
$name = "$MENU_SYMBOL ".$name;
}
my $description = '';
if ($command->{'extra'}->{'menu_entry_description'}) {
$description = $self->convert_tree ($command->{'extra'}->{'menu_entry_description'},
"menu_arg description");
if ($self->get_conf('AVOID_MENU_REDUNDANCY')) {
$description = '' if (_simplify_text_for_comparison($name_no_number)
eq _simplify_text_for_comparison($description));
}
}
return "
$name$MENU_ENTRY_COLON
$description
\n";
}
$default_types_conversion{'menu_entry'} = \&_convert_menu_entry_type;
sub _convert_menu_comment_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
if ($self->_in_preformatted_in_menu() or $self->in_string()) {
return $content;
} else {
return "
".$content
."
";
}
}
$default_types_conversion{'menu_comment'} = \&_convert_menu_comment_type;
sub _convert_before_item_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
return '' if ($content !~ /\S/);
return $content if ($self->in_string());
my $top_format = $self->top_format();
if ($top_format eq 'itemize' or $top_format eq 'enumerate') {
return '
'. $content .'
';
} elsif ($top_format eq 'table' or $top_format eq 'vtable'
or $top_format eq 'ftable') {
return '
\n";
} else {
my $category_prepared = '';
if ($command->{'extra'} and $command->{'extra'}->{'def_args'}
and @{$command->{'extra'}->{'def_args'}}) {
my $parsed_definition_category
= Texinfo::Common::definition_category ($self, $command);
if ($parsed_definition_category) {
$category_prepared = $self->convert_tree({'type' => '_code',
'contents' => [$parsed_definition_category]});
}
}
my $arguments_text = '';
if ($arguments) {
$arguments_text = $self->convert_tree({'type' => '_code',
'contents' => $arguments});
$arguments_text = ' ' . $arguments_text . ''
if ($arguments_text =~ /\S/);
}
my $def_type = '';
my $type_name = '';
if ($command->{'extra'}->{'def_parsed_hash'}->{'type'}) {
$def_type = $self->convert_tree({'type' => '_code',
'contents' => [$command->{'extra'}->{'def_parsed_hash'}->{'type'}]});
}
$type_name = " $def_type" if ($def_type ne '');
my $name = '';
if ($command->{'extra'}->{'def_parsed_hash'}->{'name'}) {
$name = $self->convert_tree({'type' => '_code',
'contents' => [$command->{'extra'}->{'def_parsed_hash'}->{'name'}]});
}
$type_name .= ' ' . $name . '' if ($name ne '');
$type_name .= $arguments_text;
return "
" . $type_name .
"
" . $category_prepared .
$index_label . "
\n";
}
}
$default_types_conversion{'def_line'} = \&_convert_def_line_type;
sub _convert_def_item_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
return $content if ($self->in_string());
if ($content =~ /\S/) {
if (! $self->get_conf('DEF_TABLE')) {
return '
' . $content . '
';
} else {
return '
' . $content . '
';
}
}
}
$default_types_conversion{'def_item'} = \&_convert_def_item_type;
$default_types_conversion{'inter_def_item'} = \&_convert_def_item_type;
sub _convert_def_command($$$$) {
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $content = shift;
return $content if ($self->in_string());
#print STDERR "IIII $self $cmdname command $command args $args content $content\n";
if (!$self->get_conf('DEF_TABLE')) {
return "
\n". $content ."
\n";
} else {
return "
\n" . $content . "
\n";
}
}
foreach my $command (keys(%def_commands)) {
$default_commands_conversion{$command} = \&_convert_def_command;
}
sub _convert_table_item_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
return $content if ($self->in_string());
if ($content =~ /\S/) {
return '
' . $content . '
'."\n";
}
}
$default_types_conversion{'table_item'} = \&_convert_table_item_type;
$default_types_conversion{'inter_item'} = \&_convert_table_item_type;
# This type is the only one present if there are no elements. It is
# therefore used to do the formatting of the element in case there are no
# element.
sub _convert_root_text_type($$$$)
{
my $self = shift;
my $type = shift;
my $command = shift;
my $content = shift;
my $result = $content;
#$result =~ s/^\s*//;
# if there is no element, the parent should not be an element
if (!$command->{'parent'}
or !$command->{'parent'}->{'type'}
or $command->{'parent'}->{'type'} ne 'element') {
$result .= &{$self->{'format_footnotes_text'}}($self);
$result .= $self->get_conf('DEFAULT_RULE') ."\n",
if ($self->get_conf('PROGRAM_NAME_IN_FOOTER')
and defined($self->get_conf('DEFAULT_RULE'))
and !$self->in_string());
}
return $result;
}
$default_types_conversion{'text_root'} = \&_convert_root_text_type;
sub _contents_shortcontents_in_title($)
{
my $self = shift;
my $result = '';
if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
foreach my $command ('contents', 'shortcontents') {
if ($self->get_conf($command)
and $self->get_conf('set'.$command.'aftertitlepage')) {
my $contents_text = $self->_contents_inline_element($command, undef);
if ($contents_text ne '') {
$result .= $contents_text . $self->get_conf('DEFAULT_RULE')."\n";
}
}
}
}
return $result;
}
# Convert @titlepage. Falls back to simpletitle.
sub _default_titlepage($)
{
my $self = shift;
my $titlepage_text;
if ($self->{'extra'}->{'titlepage'}) {
$titlepage_text = $self->convert_tree({'contents'
=> $self->{'extra'}->{'titlepage'}->{'contents'}});
} elsif ($self->{'simpletitle_tree'}) {
my $title_text = $self->convert_tree_new_formatting_context(
$self->{'simpletitle_tree'}, 'simpletitle_string');
$titlepage_text = &{$self->{'format_heading_text'}}($self, 'settitle', $title_text,
0, {'cmdname' => 'settitle',
'contents' => $self->{'simpletitle_tree'}->{'contents'}});
}
my $result = '';
$result .= $titlepage_text.$self->get_conf('DEFAULT_RULE')."\n"
if (defined($titlepage_text));
$result .= $self->_contents_shortcontents_in_title();
return $result;
}
sub _print_title($)
{
my $self = shift;
my $result = '';
if ($self->get_conf('SHOW_TITLE')) {
if ($self->get_conf('USE_TITLEPAGE_FOR_TITLE')) {
$result .= &{$self->{'format_titlepage'}}($self);
} else {
if ($self->{'simpletitle_tree'}) {
my $title_text = $self->convert_tree_new_formatting_context(
$self->{'simpletitle_tree'}, 'simpletitle_string');
$result .= &{$self->{'format_heading_text'}}($self, 'settitle', $title_text,
0, {'cmdname' => 'settitle',
'contents' => $self->{'simpletitle_tree'}->{'contents'}});
}
$result .= $self->_contents_shortcontents_in_title();
}
}
return $result;
}
sub _convert_element_type($$$$)
{
my $self = shift;
my $type = shift;
my $element = shift;
my $content = shift;
#print STDERR "GGGGGGGG $element $element->{'parent'} $element->{'parent'}->{'type'}\n";
#print STDERR "$element->{'extra'}->{'special_element'}\n"
# if ($element->{'extra'}->{'special_element'});
#if (!defined($element->{'parent'})) {
# print STDERR "NO PARENT ".Texinfo::Parser::_print_current($element)."\n";
#}
if ($self->in_string()) {
if (defined($content)) {
return $content;
} else {
return '';
}
}
my $result = '';
my $special_element;
if ($element->{'extra'}->{'special_element'}) {
$special_element = $element->{'extra'}->{'special_element'};
my $id = $self->command_id($element);
if ($id ne '') {
$result .= "\n";
}
if ($self->get_conf('HEADERS')
# first in page
or $self->{'counter_in_file'}->{$element->{'filename'}} == 1) {
$result .= &{$self->{'format_navigation_header'}}($self,
$self->get_conf('MISC_BUTTONS'), undef, $element);
}
my $heading = $self->command_text($element);
my $element_name = $element->{'extra'}->{'special_element'};
my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{$element_name};
my $level = $self->get_conf('CHAPTER_HEADER_LEVEL');
if ($element_name eq 'Footnotes') {
$level = $self->get_conf('FOOTNOTE_SEPARATE_HEADER_LEVEL');
}
$result .= &{$self->{'format_heading_text'}}($self, $class.'-heading',
$heading, $level)."\n";
my $special_element_body .= &{$self->{'format_special_element_body'}}($self,
$special_element, $element);
# This may happen with footnotes in regions that are not expanded,
# like @copying or @titlepage
if ($special_element_body eq '') {
return '';
}
$result .= $special_element_body;
} elsif (!$element->{'element_prev'}) {
$result .= $self->_print_title();
if (!$element->{'element_next'}) {
# only one element
my $foot_text = &{$self->{'format_footnotes_text'}}($self);
return $result.$content.$foot_text.$self->get_conf('DEFAULT_RULE')."\n";
}
}
$result .= $content unless ($special_element);
$result .= &{$self->{'format_element_footer'}}($self, $type,
$element, $content);
return $result;
}
sub _default_element_footer($$$$)
{
my $self = shift;
my $type = shift;
my $element = shift;
my $content = shift;
my $result = '';
my $is_top = $self->element_is_top($element);
my $next_is_top = ($element->{'element_next'}
and $self->element_is_top($element->{'element_next'}));
my $next_is_special = (defined($element->{'element_next'})
and $element->{'element_next'}->{'extra'}->{'special_element'});
# no 'parent' defined happens if there are no pages, and there are elements
# which should only happen when called with $self->{'output_file'}
# set to ''.
#print STDERR "$element $element->{'filename'} $self->{'file_counters'}->{$element->{'filename'}}\n";
#print STDERR "next: $element->{'element_next'}->{'filename'}\n" if ($element->{'element_next'});
my $end_page = (!$element->{'element_next'}
or (defined($element->{'filename'})
and $element->{'filename'} ne $element->{'element_next'}->{'filename'}
and $self->{'file_counters'}->{$element->{'filename'}} == 1));
#my $end_page = (!$element->{'element_next'}
# or (defined($element->{'parent'})
# and $element->{'parent'} ne $element->{'element_next'}->{'parent'}));
my $is_special = $element->{'extra'}->{'special_element'};
if (($end_page or $next_is_top or $next_is_special or $is_top)
and $self->get_conf('VERTICAL_HEAD_NAVIGATION')
and ($self->get_conf('SPLIT') ne 'node'
or $self->get_conf('HEADERS') or $is_special or $is_top)) {
$result .= "
"."\n";
}
my $rule = '';
my $buttons;
my $maybe_in_page;
if (($is_top or $is_special)
and ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC'))
and ($end_page
and ($self->get_conf('HEADERS')
or ($self->get_conf('SPLIT') and $self->get_conf('SPLIT') ne 'node')))) {
if ($is_top) {
$buttons = $self->get_conf('TOP_BUTTONS');
} else {
$buttons = $self->get_conf('MISC_BUTTONS');
}
} elsif ($end_page and $self->get_conf('SPLIT') eq 'section') {
$buttons = $self->get_conf('SECTION_FOOTER_BUTTONS');
} elsif ($end_page and $self->get_conf('SPLIT') eq 'chapter') {
$buttons = $self->get_conf('CHAPTER_BUTTONS');
} elsif ($self->get_conf('SPLIT') eq 'node') {
if ($self->get_conf('HEADERS')) {
my $no_footer_word_count;
if ($self->get_conf('WORDS_IN_PAGE')) {
my @cnt = split(/\W*\s+\W*/, $content);
if (scalar(@cnt) < $self->get_conf('WORDS_IN_PAGE')) {
$no_footer_word_count = 1;
}
}
$buttons = $self->get_conf('NODE_FOOTER_BUTTONS')
unless ($no_footer_word_count);
}
} else {
$maybe_in_page = 1;
}
if ($maybe_in_page or $is_top or $is_special
or ($end_page and ($self->get_conf('SPLIT') eq 'chapter'
or $self->get_conf('SPLIT') eq 'section'))
or ($self->get_conf('SPLIT') eq 'node' and $self->get_conf('HEADERS'))) {
$rule = $self->get_conf('DEFAULT_RULE');
}
if (!$end_page and ($is_top or $next_is_top or ($next_is_special
and !$is_special))) {
$rule = $self->get_conf('BIG_RULE');
}
# FIXME the following condition is almost a duplication of end_page
# except that the file counter needs not be 1
if ((!$element->{'element_next'}
or (defined($element->{'filename'})
and $element->{'filename'} ne $element->{'element_next'}->{'filename'}))
and $self->get_conf('footnotestyle') eq 'end') {
$result .= &{$self->{'format_footnotes_text'}}($self);
}
if (!$self->get_conf('PROGRAM_NAME_IN_FOOTER')
and !$buttons and !$maybe_in_page) {
# no rule in that case
} else {
$result .= "$rule\n" if ($rule);
}
if ($buttons) {
$result .= &{$self->{'format_navigation_header_panel'}}($self, $buttons,
undef, $element);
}
return $result;
}
$default_types_conversion{'element'} = \&_convert_element_type;
sub _new_document_context($$)
{
my $self = shift;
my $cmdname = shift;
push @{$self->{'document_context'}},
{'cmdname' => $cmdname,
'formatting_context' => [{'cmdname' => $cmdname}],
'composition_context' => ['raggedright'],
'formats' => [],
'monospace' => [0],
};
}
my %default_formatting_references = (
'heading_text' => \&_default_heading_text,
'comment' => \&_default_comment,
'protect_text' => \&_default_protect_text,
'css_lines' => \&_default_css_lines,
'begin_file' => \&_default_begin_file,
'node_redirection_page' => \&_default_node_redirection_page,
'end_file' => \&_default_end_file,
'special_element_body' => \&_default_special_element_body,
'footnotes_text' => \&_default_footnotes_text,
'program_string' => \&_default_program_string,
'titlepage' => \&_default_titlepage,
'navigation_header' => \&_default_navigation_header,
'navigation_header_panel' => \&_default_navigation_header_panel,
'element_header' => \&_default_element_header,
'element_footer' => \&_default_element_footer,
'button' => \&_default_button_formatting,
'button_icon_img' => \&_default_button_icon_img,
'external_href' => \&_default_external_href,
'contents' => \&_default_contents,
'frame_files' => \&_default_frame_files,
);
sub _use_entity_is_entity($$)
{
my $self = shift;
my $text = shift;
return 0 if (!$self->get_conf('ENABLE_ENCODING_USE_ENTITY'));
return 1 if ($text =~ /^&/ and $text =~ /;$/);
}
sub _complete_commands_formatting($$)
{
my $self = shift;
my $command = shift;
if (!defined ($self->{'commands_formatting'}->{'normal'}->{$command})) {
$self->{'commands_formatting'}->{'normal'}->{$command} = '';
}
if (!defined ($self->{'commands_formatting'}->{'preformatted'}->{$command})) {
$self->{'commands_formatting'}->{'preformatted'}->{$command} =
$self->{'commands_formatting'}->{'normal'}->{$command};
}
if (!defined ($self->{'commands_formatting'}->{'string'}->{$command})) {
$self->{'commands_formatting'}->{'string'}->{$command} =
$self->{'commands_formatting'}->{'preformatted'}->{$command};
}
}
sub converter_initialize($)
{
my $self = shift;
if ($self->get_conf('SHORTEXTN')) {
$self->set_conf('EXTENSION', 'htm');
}
$foot_num = 0;
$foot_lines = '';
%formatted_index_entries = ();
%footnote_id_numbers = ();
%{$self->{'css_map'}} = %css_map;
$self->{'htmlxref'} = {};
if ($self->{'htmlxref_files'}) {
$self->{'htmlxref'} = Texinfo::Common::parse_htmlxref_files($self,
$self->{'htmlxref_files'});
}
foreach my $type (keys(%default_types_conversion)) {
if (exists($Texinfo::Config::texinfo_types_conversion{$type})) {
$self->{'types_conversion'}->{$type}
= $Texinfo::Config::texinfo_types_conversion{$type};
} else {
$self->{'types_conversion'}->{$type}
= $default_types_conversion{$type};
}
}
# FIXME API with a function call? Used in cvs.init.
foreach my $type (keys(%default_code_types)) {
$self->{'code_types'}->{$type} = $default_code_types{$type};
}
if ($Texinfo::Config::texinfo_code_types) {
foreach my $type (keys(%$Texinfo::Config::texinfo_code_types)) {
$self->{'code_types'}->{$type}
= $Texinfo::Config::texinfo_code_types->{$type};
}
}
# FIXME put value in a category in Texinfo::Common?
foreach my $command (keys(%misc_commands), keys(%brace_commands),
keys (%block_commands), keys(%no_brace_commands), 'value') {
if (exists($Texinfo::Config::texinfo_commands_conversion{$command})) {
$self->{'commands_conversion'}->{$command}
= $Texinfo::Config::texinfo_commands_conversion{$command};
} else {
if (!$self->get_conf('SHOW_MENU')
and ($command eq 'menu' or $command eq 'detailmenu')) {
$self->{'commands_conversion'}->{$command} = undef;
} elsif ($format_raw_commands{$command}
and !$self->{'expanded_formats_hash'}->{$command}) {
} elsif (exists($default_commands_conversion{$command})) {
$self->{'commands_conversion'}->{$command}
= $default_commands_conversion{$command};
if ($command eq 'menu' and $self->get_conf('SIMPLE_MENU')) {
$self->{'commands_conversion'}->{$command}
= $default_commands_conversion{'example'};
}
}
}
}
foreach my $context ('normal', 'preformatted', 'string') {
foreach my $command (keys(%{$default_commands_formatting{'normal'}})) {
if (exists ($Texinfo::Config::commands_formatting{$context}->{$command})) {
$self->{'commands_formatting'}->{$context}->{$command}
= $Texinfo::Config::commands_formatting{$context}->{$command};
} else {
if (defined($default_commands_formatting{$context}->{$command})) {
if ($self->get_conf('ENABLE_ENCODING')
and Texinfo::Convert::Unicode::unicode_for_brace_no_arg_command(
$command, $self->get_conf('OUTPUT_ENCODING_NAME'))
and !$self->_use_entity_is_entity($default_commands_formatting{$context}->{$command})) {
$self->{'commands_formatting'}->{$context}->{$command}
= Texinfo::Convert::Unicode::unicode_for_brace_no_arg_command(
$command, $self->get_conf('OUTPUT_ENCODING_NAME'))
} else {
$self->{'commands_formatting'}->{$context}->{$command}
= $default_commands_formatting{$context}->{$command};
}
}
}
if (exists ($Texinfo::Config::commands_translation{$context}->{$command})) {
$self->{'commands_translation'}->{$context}->{$command}
= $Texinfo::Config::commands_translation{$context}->{$command};
delete $self->{'translated_commands'}->{$command};
} elsif (defined($default_commands_translation{$context}->{$command})) {
$self->{'commands_translation'}->{$context}->{$command}
= $default_commands_translation{$context}->{$command};
delete $self->{'translated_commands'}->{$command};
}
}
}
# set sane defaults in case there is none and the default formatting
# function is used
foreach my $command (keys(%{$default_commands_formatting{'normal'}})) {
if ($self->{'commands_conversion'}->{$command}
and $self->{'commands_conversion'}->{$command}
eq $default_commands_conversion{$command}) {
$self->_complete_commands_formatting($command);
}
}
foreach my $context (keys(%style_commands_formatting)) {
foreach my $command (keys(%{$style_commands_formatting{$context}})) {
if (exists ($Texinfo::Config::style_commands_formatting{$context}->{$command})) {
$self->{'style_commands_formatting'}->{$context}->{$command}
= $Texinfo::Config::style_commands_formatting{$context}->{$command};
} elsif (exists($style_commands_formatting{$context}->{$command})) {
$self->{'style_commands_formatting'}->{$context}->{$command}
= $style_commands_formatting{$context}->{$command};
}
}
}
foreach my $command (keys %{$self->{'commands_conversion'}}) {
if (exists($Texinfo::Config::commands_args{$command})) {
$self->{'commands_args'}->{$command}
= $Texinfo::Config::commands_args{$command};
} elsif (exists($default_commands_args{$command})) {
$self->{'commands_args'}->{$command} = $default_commands_args{$command};
}
}
foreach my $formatting_reference (keys(%default_formatting_references)) {
$self->{'default_formatting_functions'}->{$formatting_reference}
= $default_formatting_references{$formatting_reference};
if (defined($Texinfo::Config::texinfo_formatting_references{$formatting_reference})) {
$self->{"format_".$formatting_reference}
= $Texinfo::Config::texinfo_formatting_references{$formatting_reference};
} else {
$self->{"format_".$formatting_reference}
= $default_formatting_references{$formatting_reference};
}
}
if ($Texinfo::Config::renamed_nodes) {
%{$self->{'renamed_nodes'}} = %{$Texinfo::Config::renamed_nodes};
}
$self->{'document_context'} = [];
$self->{'multiple_pass'} = [];
$self->_new_document_context('_toplevel_context');
if ($self->get_conf('SPLIT') and $self->get_conf('SPLIT') ne 'chapter'
and $self->get_conf('SPLIT') ne 'section'
and $self->get_conf('SPLIT') ne 'node') {
$self->force_conf('SPLIT', 'node');
}
return $self;
}
# the entry point for _convert
sub convert_tree($$;$)
{
my $self = shift;
my $element = shift;
my $explanation = shift;
return $self->_convert($element, $explanation);
}
sub _normalized_to_id($)
{
my $id = shift;
if (!defined($id)) {
cluck "_normalized_to_id id not defined";
return '';
}
$id =~ s/^([0-9_])/g_t$1/;
return $id;
}
sub _default_css_lines ($)
{
my $self = shift;
return if ($self->get_conf('NO_CSS'));
my $css_refs = $self->get_conf('CSS_REFS');
return if (!@{$self->{'css_import_lines'}} and !@{$self->{'css_rule_lines'}}
and !keys(%{$self->{'css_map'}}) and !@$css_refs);
my $css_text = "\n";
foreach my $ref (@$css_refs) {
$css_text .= "\n";
}
$self->set_conf('CSS_LINES', $css_text);
}
sub _process_css_file($$$)
{
my $self = shift;
my $fh =shift;
my $file = shift;
my $in_rules = 0;
my $in_comment = 0;
my $in_import = 0;
my $in_string = 0;
my $rules = [];
my $imports = [];
my $line_nr = 0;
while (my $line = <$fh>) {
$line_nr++;
#print STDERR "Line: $line";
if ($in_rules) {
push @$rules, $line;
next;
}
my $text = '';
while (1) {
#sleep 1;
#print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $line";
if ($in_comment) {
if ($line =~ s/^(.*?\*\/)//) {
$text .= $1;
$in_comment = 0;
} else {
push @$imports, $text . $line;
last;
}
} elsif (!$in_string and $line =~ s/^\///) {
if ($line =~ s/^\*//) {
$text .= '/*';
$in_comment = 1;
} else {
push (@$imports, $text. "\n") if ($text ne '');
push (@$rules, '/' . $line);
$in_rules = 1;
last;
}
} elsif (!$in_string and $in_import and $line =~ s/^([\"\'])//) {
# strings outside of import start rules
$text .= "$1";
$in_string = quotemeta("$1");
} elsif ($in_string and $line =~ s/^(\\$in_string)//) {
$text .= $1;
} elsif ($in_string and $line =~ s/^($in_string)//) {
$text .= $1;
$in_string = 0;
} elsif ((! $in_string and !$in_import)
and ($line =~ s/^([\\]?\@import)$//
or $line =~ s/^([\\]?\@import\s+)//)) {
$text .= $1;
$in_import = 1;
} elsif (!$in_string and $in_import and $line =~ s/^\;//) {
$text .= ';';
$in_import = 0;
} elsif (($in_import or $in_string) and $line =~ s/^(.)//) {
$text .= $1;
} elsif (!$in_import and $line =~ s/^([^\s])//) {
push (@$imports, $text. "\n") if ($text ne '');
push (@$rules, $1 . $line);
$in_rules = 1;
last;
} elsif ($line =~ s/^(\s)//) {
$text .= $1;
} elsif ($line eq '') {
push (@$imports, $text);
last;
}
}
}
#file_line_warn (__("string not closed in css file"), $file) if ($in_string);
#file_line_warn (__("--css-file ended in comment"), $file) if ($in_comment);
#file_line_warn (__("\@import not finished in css file"), $file) if ($in_import and !$in_comment and !$in_string);
$self->file_line_warn(sprintf($self->__("string not closed in css file"),
$file, $line_nr)) if ($in_string);
$self->file_line_warn(sprintf($self->__("--css-include ended in comment"),
$file, $line_nr)) if ($in_comment);
$self->file_line_warn(sprintf($self->__("\@import not finished in css file"),
$file, $line_nr))
if ($in_import and !$in_comment and !$in_string);
return ($imports, $rules);
}
sub _prepare_css($)
{
my $self = shift;
return if ($self->get_conf('NO_CSS'));
my @css_import_lines;
my @css_rule_lines;
my $css_files = $self->get_conf('CSS_FILES');
foreach my $file (@$css_files) {
my $css_file_fh;
my $css_file;
if ($file eq '-') {
$css_file_fh = \*STDIN;
$css_file = '-';
} else {
$css_file = $self->Texinfo::Common::locate_include_file($file);
unless (defined($css_file)) {
$self->document_warn(sprintf(
$self->__("CSS file %s not found"), $file));
next;
}
# FIXME use open_out?
unless (open (CSSFILE, $css_file)) {
$self->document_warn(sprintf($self->__(
"could not open --include-file %s: %s"),
$css_file, $!));
next;
}
$css_file_fh = \*CSSFILE;
}
my ($import_lines, $rules_lines);
($import_lines, $rules_lines)
= $self->_process_css_file ($css_file_fh, $css_file);
if (!close($css_file_fh)) {
$self->document_warn(sprintf($self->__("error on closing CSS file %s: %s"),
$css_file, $!));
}
push @css_import_lines, @$import_lines;
push @css_rule_lines, @$rules_lines;
}
if ($self->get_conf('DEBUG')) {
if (@css_import_lines) {
print STDERR "# css import lines\n";
foreach my $line (@css_import_lines) {
print STDERR "$line";
}
}
if (@css_rule_lines) {
print STDERR "# css rule lines\n";
foreach my $line (@css_rule_lines) {
print STDERR "$line";
}
}
}
$self->{'css_import_lines'} = \@css_import_lines;
$self->{'css_rule_lines'} = \@css_rule_lines;
}
sub _node_id_file($$)
{
my $self = shift;
my $node_info = shift;
my ($target, $id);
my $normalized = $node_info->{'normalized'};
if (defined($normalized)) {
$target = _normalized_to_id($normalized);
} else {
$target = '';
}
if (!$node_info->{'manual_content'}) {
$id = $target;
}
# to find out the Top node, one could check $node_info->{'normalized'}
if (defined($Texinfo::Config::node_target_name)) {
($target, $id) = &$Texinfo::Config::node_target_name($node_info,
$target, $id);
}
my $filename = $self->_node_filename($node_info);
return ($filename, $target, $id);
}
sub _new_sectioning_command_target($$)
{
my $self = shift;
my $command = shift;
my ($normalized_name, $filename)
= $self->_sectioning_command_normalized_filename($command);
my $target_base = _normalized_to_id($normalized_name);
if ($target_base !~ /\S/ and $command->{'cmdname'} eq 'top'
and defined($self->{'misc_elements_targets'}->{'Top'})) {
$target_base = $self->{'misc_elements_targets'}->{'Top'};
}
my $nr=1;
my $target = $target_base;
if ($target ne '') {
while ($self->{'ids'}->{$target}) {
$target = $target_base.'-'.$nr;
$nr++;
# Avoid integer overflow
die if ($nr == 0);
}
}
my $id = $target;
if ($command->{'extra'}->{'associated_node'}
and $self->get_conf('USE_NODE_TARGET')) {
$target
= $self->{'targets'}->{$command->{'extra'}->{'associated_node'}}->{'id'};
}
# These are undefined if the $id is set to ''.
my $target_contents;
my $id_contents;
my $target_shortcontents;
my $id_shortcontents;
if ($Texinfo::Common::sectioning_commands{$command->{'cmdname'}}) {
# NOTE id is used as base for both id and target. In comment an example
# showing how target could have been used.
#my $target_base_contents;
#if ($command->{'extra'}->{'associated_node'}
# and $self->get_conf('USE_NODE_TARGET') {
# $target_base_contents = $target;
#} else {
# $target_base_contents = $target_base;
#}
# $target_content =~ s/^g_t//;
#$target_contents = 'toc-'.$target_base_contents;
if ($id ne '') {
my $id_base_contents = $id;
$id_base_contents =~ s/^g_t//;
$target_contents = 'toc-'.$id_base_contents;
my $target_base_contents = $target_base;
$target_base_contents =~ s/^g_t//;
my $toc_nr = $nr -1;
while ($self->{'ids'}->{$target_contents}) {
$target_contents = 'toc-'.$target_base_contents.'-'.$toc_nr;
$toc_nr++;
# Avoid integer overflow
die if ($toc_nr == 0);
}
$id_contents = $target_contents;
# NOTE id is used as a base for id and target. target could also
# have been used, see above for an example.
$target_shortcontents = 'stoc-'.$id_base_contents;
my $target_base_shortcontents = $target_base;
$target_base_shortcontents =~ s/^g_t//;
my $stoc_nr = $nr -1;
while ($self->{'ids'}->{$target_shortcontents}) {
$target_shortcontents = 'stoc-'.$target_base_shortcontents
.'-'.$stoc_nr;
$stoc_nr++;
# Avoid integer overflow
die if ($stoc_nr == 0);
}
}
$id_shortcontents = $target_shortcontents;
}
if (defined($Texinfo::Config::sectioning_command_target_name)) {
($target, $id, $target_contents, $id_contents,
$target_shortcontents, $id_shortcontents, $filename)
= &$Texinfo::Config::sectioning_command_target_name($self,
$command, $target, $id,
$target_contents, $id_contents,
$target_shortcontents, $id_shortcontents,
$filename);
}
if ($self->get_conf('DEBUG')) {
print STDERR "Register $command->{'cmdname'} $target, $id\n";
}
$self->{'targets'}->{$command} = {
'target' => $target,
'id' => $id,
'section_filename' => $filename,
};
$self->{'ids'}->{$id} = $command;
if (defined($id_contents)) {
$self->{'targets'}->{$command}->{'contents_id'} = $id_contents;
$self->{'ids'}->{$id_contents} = $command;
} else {
$self->{'targets'}->{$command}->{'contents_id'} = '';
}
if (defined($target_contents)) {
$self->{'targets'}->{$command}->{'contents_target'} = $target_contents;
} else {
$self->{'targets'}->{$command}->{'contents_target'} = '';
}
if (defined($id_shortcontents)) {
$self->{'targets'}->{$command}->{'shortcontents_id'} = $id_shortcontents;
$self->{'ids'}->{$id_shortcontents} = $command;
} else {
$self->{'targets'}->{$command}->{'shortcontents_id'} = '';
}
if (defined($target_shortcontents)) {
$self->{'targets'}->{$command}->{'shortcontents_target'}
= $target_shortcontents;
} else {
$self->{'targets'}->{$command}->{'shortcontents_target'} = '';
}
return $self->{'targets'}->{$command};
}
# This set 2 unrelated things.
# * The targets and id of sectioning elements
# * the target, id and normalized filename of 'labels', ie everything that
# may be the target of a ref, like @node, @float, @anchor...
# conversion to HTML is done on-demand, upon call to command_text.
sub _set_root_commands_targets_node_files($$)
{
my $self = shift;
my $elements = shift;
my $no_unidecode;
$no_unidecode = 1 if (defined($self->get_conf('USE_UNIDECODE'))
and !$self->get_conf('USE_UNIDECODE'));
if ($self->{'labels'}) {
foreach my $root_command (values(%{$self->{'labels'}})) {
my ($filename, $target, $id) = $self->_node_id_file($root_command->{'extra'});
$filename .= '.'.$self->get_conf('NODE_FILE_EXTENSION')
if (defined($self->get_conf('NODE_FILE_EXTENSION'))
and $self->get_conf('NODE_FILE_EXTENSION') ne '');
if (defined($Texinfo::Config::node_file_name)) {
$filename = &$Texinfo::Config::node_file_name($self, $root_command,
$filename);
}
if ($self->get_conf('DEBUG')) {
print STDERR "Register label($root_command) $target, $filename\n";
}
$self->{'targets'}->{$root_command} = {'target' => $target,
'id' => $id,
'node_filename' => $filename};
$self->{'ids'}->{$id} = $root_command;
}
}
if ($elements) {
foreach my $element (@$elements) {
foreach my $root_command(@{$element->{'contents'}}) {
# this happens for type 'text_root' which precedes the
# root commands. The target may also already be set for top node.
next if (!defined($root_command->{'cmdname'})
or $self->{'targets'}->{$root_command});
if ($Texinfo::Common::sectioning_commands{$root_command->{'cmdname'}}) {
$self->_new_sectioning_command_target($root_command);
}
}
}
}
}
sub _get_element($$;$);
# If $find_container is set, the element that holds the command is found,
# otherwise the element that holds the command content is found. This is
# mostly relevant for footnote only.
sub _get_element($$;$)
{
my $self = shift;
my $command = shift;
my $find_container = shift;
my $current = $command;
my ($element, $root_command);
while (1) {
if ($current->{'type'}) {
if ($current->{'type'} eq 'element') {
return ($current, $root_command);
}
}
if ($current->{'cmdname'}) {
if ($root_commands{$current->{'cmdname'}}) {
$root_command = $current;
return ($element, $root_command) if defined($element);
} elsif ($region_commands{$current->{'cmdname'}}) {
if ($current->{'cmdname'} eq 'copying'
and $self->{'extra'} and $self->{'extra'}->{'insertcopying'}) {
foreach my $insertcopying(@{$self->{'extra'}->{'insertcopying'}}) {
my ($element, $root_command)
= $self->_get_element($insertcopying, $find_container);
return ($element, $root_command)
if (defined($element) or defined($root_command));
}
} elsif ($current->{'cmdname'} eq 'titlepage'
and $self->get_conf('USE_TITLEPAGE_FOR_TITLE')
and $self->get_conf('SHOW_TITLE')
and $self->{'elements'}->[0]) {
return ($self->{'elements'}->[0],
$self->{'elements'}->[0]->{'extra'}->{'element_command'});
}
die "Problem $element, $root_command" if (defined($element)
or defined($root_command));
return (undef, undef);
} elsif ($current->{'cmdname'} eq 'footnote'
and $self->{'special_elements_types'}->{'Footnotes'}
and $find_container) {
# in that case there is no root_command
$element = $self->{'special_elements_types'}->{'Footnotes'};
return ($element);
}
}
if ($current->{'parent'}) {
$current = $current->{'parent'};
} else {
return ($element, $root_command);
}
}
}
sub _set_pages_files($$)
{
my $self = shift;
my $elements = shift;
my $special_elements = shift;
# Ensure that the document has pages
return undef if (!defined($elements) or !@$elements);
my $extension = '';
$extension = '.'.$self->get_conf('EXTENSION')
if (defined($self->get_conf('EXTENSION'))
and $self->get_conf('EXTENSION') ne '');
if (!$self->get_conf('SPLIT')) {
foreach my $element (@$elements) {
if (!defined($element->{'filename'})) {
$element->{'filename'} = $self->{'output_filename'};
$element->{'out_filename'} = $self->{'output_file'};
}
}
} else {
my $node_top;
#my $section_top;
$node_top = $self->{'labels'}->{'Top'} if ($self->{'labels'});
#$section_top = $self->{'extra'}->{'top'} if ($self->{'extra'});
my $top_node_filename = $self->_top_node_filename();
# first determine the top node file name.
if ($self->get_conf('NODE_FILENAMES') and $node_top
and defined($top_node_filename)) {
my ($node_top_element) = $self->_get_element($node_top);
die "BUG: No element for top node" if (!defined($node_top));
$self->_set_element_file($node_top_element, $top_node_filename);
}
my $file_nr = 0;
my $previous_page;
foreach my $element(@$elements) {
# For Top node.
next if (defined($element->{'filename'}));
if (!$element->{'extra'}->{'first_in_page'}) {
cluck ("No first_in_page for $element\n");
}
if (!defined($element->{'extra'}->{'first_in_page'}->{'filename'})) {
my $file_element = $element->{'extra'}->{'first_in_page'};
if ($self->get_conf('NODE_FILENAMES')) {
foreach my $root_command (@{$file_element->{'contents'}}) {
if ($root_command->{'cmdname'}
and $root_command->{'cmdname'} eq 'node') {
my $node_filename;
# double node are not normalized, they are handled here
if (!defined($root_command->{'extra'}->{'normalized'})
or !defined($self->{'labels'}->{$root_command->{'extra'}->{'normalized'}})) {
$node_filename = 'unknown_node';
$node_filename .= '.'.$self->get_conf('NODE_FILE_EXTENSION')
if (defined($self->get_conf('NODE_FILE_EXTENSION'))
and $self->get_conf('NODE_FILE_EXTENSION') ne '');
} else {
if (!defined($self->{'targets'}->{$root_command})
or !defined($self->{'targets'}->{$root_command}->{'node_filename'})) {
# Could have been a double node, thus use equivalent node.
# However since double nodes are not normalized, in fact it
# never happens.
$root_command
= $self->{'labels'}->{$root_command->{'extra'}->{'normalized'}};
}
$node_filename
= $self->{'targets'}->{$root_command}->{'node_filename'};
}
$self->_set_element_file($file_element, $node_filename);
last;
}
}
if (!defined($file_element->{'filename'})) {
# use section to do the file name if there is no node
my $command = $self->element_command($file_element);
if ($command) {
if ($command->{'cmdname'} eq 'top' and !$node_top
and defined($top_node_filename)) {
$self->_set_element_file($file_element, $top_node_filename);
} else {
$self->_set_element_file($file_element,
$self->{'targets'}->{$command}->{'section_filename'});
}
} else {
# when everything else has failed
if ($file_nr == 0 and !$node_top
and defined($top_node_filename)) {
$self->_set_element_file($file_element, $top_node_filename);
} else {
my $filename = $self->{'document_name'} . "_$file_nr";
$filename .= $extension;
$self->_set_element_file($element, $filename);
}
$file_nr++;
}
}
} else {
my $filename = $self->{'document_name'} . "_$file_nr";
$filename .= '.'.$self->get_conf('EXTENSION')
if (defined($self->get_conf('EXTENSION'))
and $self->get_conf('EXTENSION') ne '');
$self->_set_element_file($file_element, $filename);
$file_nr++;
}
}
$element->{'filename'}
= $element->{'extra'}->{'first_in_page'}->{'filename'};
$element->{'out_filename'}
= $element->{'extra'}->{'first_in_page'}->{'out_filename'};
}
}
foreach my $element (@$elements) {
if (defined($Texinfo::Config::element_file_name)) {
# NOTE the information that it is associated with @top or @node Top
# may be determined with $self->element_is_top($element);
my $filename = &$Texinfo::Config::element_file_name($self, $element,
$element->{'filename'});
$self->_set_element_file($element, $filename) if (defined($filename));
}
$self->{'file_counters'}->{$element->{'filename'}}++;
print STDERR "Page $element ".Texinfo::Structuring::_print_element_command_texi($element).": $element->{'filename'}($self->{'file_counters'}->{$element->{'filename'}})\n"
if ($self->get_conf('DEBUG'));
}
if ($special_elements) {
my $previous_element = $elements->[-1];
foreach my $element (@$special_elements) {
my $filename
= $self->{'targets'}->{$element}->{'misc_filename'};
if (defined($filename)) {
$self->_set_element_file($element, $filename);
$self->{'file_counters'}->{$element->{'filename'}}++;
print STDERR "Special page $element: $element->{'filename'}($self->{'file_counters'}->{$element->{'filename'}})\n"
if ($self->get_conf('DEBUG'));
}
$element->{'element_prev'} = $previous_element;
$previous_element->{'element_next'} = $element;
$previous_element = $element;
}
}
}
sub _prepare_elements($$)
{
my $self = shift;
my $root = shift;
my $elements;
# do that now to have it available for formatting
# NOTE this calls Convert::Converter::_informative_command on all the
# @informative_global commands.
# Thus sets among others language and encodings.
$self->_set_global_multiple_commands(-1);
$self->_translate_names();
if ($self->get_conf('USE_NODES')) {
$elements = Texinfo::Structuring::split_by_node($root);
} else {
$elements = Texinfo::Structuring::split_by_section($root);
}
$self->{'elements'} = $elements
if (defined($elements));
# This may be done as soon as elements are available.
$self->_prepare_global_targets($elements);
# Do that before the other elements, to be sure that special page ids
# are registered before elements id are.
my $special_elements
= $self->_prepare_special_elements($elements);
$self->{'special_elements'} = $special_elements
if (defined($special_elements));
#if ($elements) {
# foreach my $element(@{$elements}) {
# print STDERR "ELEMENT $element->{'type'}: $element\n";
# }
#}
$self->_set_root_commands_targets_node_files($elements);
return ($elements, $special_elements);
}
sub _prepare_special_elements($$)
{
my $self = shift;
my $elements = shift;
my %do_special;
# FIXME let the user decide how @*contents are treated?
if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
foreach my $cmdname ('contents', 'shortcontents') {
my $type = $contents_command_element_name{$cmdname};
if ($self->get_conf($cmdname)) {
if ($self->get_conf('INLINE_CONTENTS')
or ($self->get_conf('set'.$cmdname.'aftertitlepage'))) {
} else {
$do_special{$type} = 1;
}
}
}
}
if ($self->{'extra'}->{'footnote'}
and $self->get_conf('footnotestyle') eq 'separate'
and $elements and scalar(@$elements) > 1) {
$do_special{'Footnotes'} = 1;
}
if ((!defined($self->get_conf('DO_ABOUT'))
and $elements and scalar(@$elements) > 1
and ($self->get_conf('SPLIT') or $self->get_conf('HEADERS')))
or ($self->get_conf('DO_ABOUT'))) {
$do_special{'About'} = 1;
}
my $extension = '';
$extension = $self->get_conf('EXTENSION')
if (defined($self->get_conf('EXTENSION')));
my $special_elements = [];
foreach my $type (@{$self->{'misc_elements_order'}}) {
next unless ($do_special{$type});
my $element = {'type' => 'element',
'extra' => {'special_element' => $type,
}};
$element->{'extra'}->{'directions'}->{'This'} = $element;
$self->{'special_elements_types'}->{$type} = $element;
push @$special_elements, $element;
my $id = $self->{'misc_elements_targets'}->{$type};
my $target = $id;
my $default_filename;
if ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC')) {
$default_filename = $self->{'document_name'}.
$self->{'misc_pages_file_string'}->{$type};
$default_filename .= '.'.$extension if (defined($extension));
} else {
$default_filename = undef;
}
my $filename;
if (defined($Texinfo::Config::special_element_target_file_name)) {
($target, $id, $filename)
= &$Texinfo::Config::special_element_target_file_name(
$self,
$element,
$target, $id,
$default_filename);
}
$filename = $default_filename if (!defined($filename));
if ($self->get_conf('DEBUG')) {
my $fileout = $filename;
$fileout = 'UNDEF' if (!defined($fileout));
print STDERR "Add special $element $type: target $target, id $id,\n".
" filename $fileout\n"
}
if ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC')
or (defined($filename) ne defined($default_filename))
or (defined($filename) and $filename ne $default_filename)) {
$self->_set_element_file($element, $filename);
print STDERR "NEW page for $type ($filename)\n" if ($self->get_conf('DEBUG'));
}
$self->{'targets'}->{$element} = {'id' => $id,
'target' => $target,
'misc_filename' => $filename,
};
$self->{'ids'}->{$id} = $element;
}
if ($self->get_conf('FRAMES')) {
foreach my $type (keys(%{$self->{'frame_pages_file_string'}})) {
my $default_filename;
$default_filename = $self->{'document_name'}.
$self->{'frame_pages_file_string'}->{$type};
$default_filename .= '.'.$extension if (defined($extension));
my $element = {'type' => 'element',
'extra' => {'special_element' => $type,
}};
# only the filename is used
my ($target, $id, $filename);
if (defined($Texinfo::Config::special_element_target_file_name)) {
($target, $id, $filename)
= &$Texinfo::Config::special_element_target_file_name(
$self,
$element,
$target, $id,
$default_filename);
}
$filename = $default_filename if (!defined($filename));
$self->{'frame_pages_filenames'}->{$type} = $filename;
}
}
return $special_elements;
}
sub _prepare_contents_elements($)
{
my $self = shift;
if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
foreach my $cmdname ('contents', 'shortcontents') {
my $type = $contents_command_element_name{$cmdname};
if ($self->get_conf($cmdname)) {
my $default_filename;
if ($self->get_conf('set'.$cmdname.'aftertitlepage')) {
if ($self->{'elements'}) {
$default_filename = $self->{'elements'}->[0]->{'filename'};
}
} elsif ($self->get_conf('INLINE_CONTENTS')) {
if ($self->{'extra'} and $self->{'extra'}->{$cmdname}) {
foreach my $command(@{$self->{'extra'}->{$cmdname}}) {
my ($element, $root_command)
= $self->_get_element($command);
if (defined($element)) {
$default_filename = $element->{'filename'};
last;
}
}
} else {
next;
}
} else { # in this case, there should already be a special element
# if needed, done together with the other special elements.
next;
}
my $element = {'type' => 'element',
'extra' => {'special_element' => $type}};
$self->{'special_elements_types'}->{$type} = $element;
my $id = $self->{'misc_elements_targets'}->{$type};
my $target = $id;
my $filename;
if (defined($Texinfo::Config::special_element_target_file_name)) {
($target, $id, $filename)
= &$Texinfo::Config::special_element_target_file_name(
$self,
$element,
$target, $id,
$default_filename);
}
$filename = $default_filename if (!defined($filename));
print STDERR "Add content $element $type: target $target, id $id,\n".
" filename $filename\n" if ($self->get_conf('DEBUG'));
$self->{'targets'}->{$element} = {'id' => $id,
'target' => $target,
'misc_filename' => $filename,
'filename' => $filename,
};
}
}
}
}
# Associate elements with the global targets, First, Last, Top, Index.
sub _prepare_global_targets($$)
{
my $self = shift;
my $elements = shift;
$self->{'global_target_elements'}->{'First'} = $elements->[0];
$self->{'global_target_elements'}->{'Last'} = $elements->[-1];
# It is always the first printindex, even if it is not output (for example
# it is in @copying and @titlepage, which are certainly wrong constructs).
if ($self->{'extra'} and $self->{'extra'}->{'printindex'}) {
my ($element, $root_command)
= $self->_get_element($self->{'extra'}->{'printindex'}->[0]);
if (defined($element)) {
if ($root_command and $root_command->{'cmdname'} eq 'node'
and $element->{'extra'}->{'section'}) {
$root_command = $element->{'extra'}->{'section'};
}
if ($root_command and $root_command->{'cmdname'} ne 'node') {
while ($root_command->{'level'} > 1
and $root_command->{'section_up'}
and $root_command->{'section_up'}->{'parent'}) {
$root_command = $root_command->{'section_up'};
$element = $root_command->{'parent'};
}
}
$self->{'global_target_elements'}->{'Index'} = $element;
}
}
my $node_top;
$node_top = $self->{'labels'}->{'Top'} if ($self->{'labels'});
my $section_top;
$section_top = $self->{'extra'}->{'top'} if ($self->{'extra'});
if ($section_top) {
$self->{'global_target_elements'}->{'Top'} = $section_top->{'parent'};
} elsif ($node_top) {
my $element_top = $node_top->{'parent'};
if (!$element_top) {
die "No parent for node_top: ".Texinfo::Parser::_print_current($node_top);
}
$self->{'global_target_elements'}->{'Top'} = $element_top;
} else {
$self->{'global_target_elements'}->{'Top'} = $elements->[0];
}
if ($self->get_conf('DEBUG')) {
print STDERR "GLOBAL DIRECTIONS:\n";
foreach my $global_direction ('First', 'Last', 'Index', 'Top') {
if (defined($self->{'global_target_elements'}->{$global_direction})) {
print STDERR "$global_direction($self->{'global_target_elements'}->{$global_direction}): ".
Texinfo::Structuring::_print_element_command_texi(
$self->{'global_target_elements'}->{$global_direction})."\n";
}
}
}
}
sub _prepare_index_entries($)
{
my $self = shift;
if ($self->{'parser'}) {
my $no_unidecode;
$no_unidecode = 1 if (defined($self->get_conf('USE_UNIDECODE'))
and !$self->get_conf('USE_UNIDECODE'));
my ($index_names, $merged_indices)
= $self->{'parser'}->indices_information();
$self->{'index_names'} = $index_names;
#print STDERR "IIII ($index_names, $merged_indices, $index_entries)\n";
my $merged_index_entries
= Texinfo::Structuring::merge_indices($index_names);
$self->{'index_entries_by_letter'}
= $self->Texinfo::Structuring::sort_indices_by_letter($merged_index_entries,
$index_names);
$self->{'index_entries'} = $merged_index_entries;
foreach my $index_name (sort(keys(%$index_names))) {
foreach my $index_entry (@{$index_names->{$index_name}->{'index_entries'}}) {
my $region = '';
$region = "$index_entry->{'region'}->{'cmdname'}-"
if (defined($index_entry->{'region'}));
my @contents = @{$index_entry->{'content_normalized'}};
my $trimmed_contents
= Texinfo::Common::trim_spaces_comment_from_content(\@contents);
my $normalized_index =
Texinfo::Convert::NodeNameNormalization::transliterate_texinfo(
{'contents' => \@contents}, $no_unidecode);
my $target_base = "index-" . $region .$normalized_index;
my $nr=1;
my $target = $target_base;
while ($self->{'ids'}->{$target}) {
$target = $target_base.'-'.$nr;
$nr++;
# Avoid integer overflow
die if ($nr == 0);
}
my $id = $target;
$self->{'ids'}->{$target} = $index_entry->{'command'};
$self->{'targets'}->{$index_entry->{'command'}} = { 'id' => $id,
'target' => $target,
};
#print STDERR "Enter $index_entry $index_entry->{'command'}: $id\n";
}
}
}
}
my $footid_base = 'FOOT';
my $docid_base = 'DOCF';
sub _prepare_footnotes($)
{
my $self = shift;
if ($self->{'extra'}->{'footnote'}) {
my $footnote_nr = 0;
foreach my $footnote (@{$self->{'extra'}->{'footnote'}}) {
$footnote_nr++;
my $nr = $footnote_nr;
my $footid = $footid_base.$nr;
my $docid = $docid_base.$nr;
while ($self->{'ids'}->{$docid} or $self->{'ids'}->{$footid}) {
$nr++;
$footid = $footid_base.$nr;
$docid = $docid_base.$nr;
# Avoid integer overflow
die if ($nr == 0);
}
$self->{'ids'}->{$footid} = $footnote;
$self->{'ids'}->{$docid} = $footnote;
$self->{'targets'}->{$footnote} = { 'id' => $docid,
'target' => $footid,
};
print STDERR "Enter footnote $footnote: id $docid, target $footid, nr $footnote_nr\n"
.Texinfo::Convert::Texinfo::convert($footnote)."\n"
if ($self->get_conf('DEBUG'));
}
}
}
# TODO this encapsulates some information.
# The encapsulation and API should be more consistent for
# the overall module.
sub _htmlxref($$)
{
my $self = shift;
my $file = shift;
return $self->{'htmlxref'}->{$file};
}
my %htmlxref_entries = %Texinfo::Common::htmlxref_entries;
sub _external_node_href($$$$)
{
my $self = shift;
my $external_node = shift;
my $filename = shift;
my $link_command = shift;
# This only overrides an implicit pointer to (dir) as the Top node's Up.
# It has no effect if a pointer is explicitly specified,
# or if implicit pointers aren't being created (e.g., just a Top node).
if ($external_node->{'top_node_up'}
and defined($self->get_conf('TOP_NODE_UP_URL'))) {
return $self->get_conf('TOP_NODE_UP_URL');
}
# In addition to that implicit (dir) as the Top node's Up, replace all
# other references to external file "dir" with the same TOP_NODE_UP_URL.
if (defined($self->get_conf('TOP_NODE_UP_URL'))
and $external_node->{'manual_content'}[0]->{'text'} eq "dir") {
return $self->get_conf('TOP_NODE_UP_URL');
}
#print STDERR "external_node: ".join('|', keys(%$external_node))."\n";
my ($target_filebase, $target, $id) = $self->_node_id_file($external_node);
my $xml_target = _normalized_to_id($target);
my $default_target_split = $self->get_conf('EXTERNAL_CROSSREF_SPLIT');
my $extension = '';
$extension = "." . $self->get_conf('NODE_FILE_EXTENSION')
if (defined($self->get_conf('NODE_FILE_EXTENSION'))
and $self->get_conf('NODE_FILE_EXTENSION') ne '');
my $target_split;
my $file;
if ($external_node->{'manual_content'}) {
my $manual_name = Texinfo::Convert::Text::convert(
{'contents' => $external_node->{'manual_content'}},
{ 'code' => 1,
Texinfo::Common::_convert_text_options($self)});
my $manual_base = $manual_name;
$manual_base =~ s/\.[^\.]*$//;
$manual_base =~ s/^.*\///;
my $document_split = $self->get_conf('SPLIT');
$document_split = 'mono' if (!$document_split);
my $split_found;
my $href;
my $htmlxref_info = $self->_htmlxref($manual_base);
if ($htmlxref_info) {
foreach my $split_ordered (@{$htmlxref_entries{$document_split}}) {
if (defined($htmlxref_info->{$split_ordered})) {
$split_found = $split_ordered;
$href = $htmlxref_info->{$split_ordered};
last;
}
}
}
if (defined($split_found)) {
$target_split = 1 unless ($split_found eq 'mono');
} else { # nothing specified for that manual, use default
$target_split = $default_target_split;
if ($self->get_conf('CHECK_HTMLXREF')
and !$external_node->{'top_node_up'}) {
if (defined($link_command) and $link_command->{'line_nr'}) {
$self->line_warn(sprintf($self->__(
"no htmlxref.cnf entry found for `%s'"), $manual_name),
$link_command->{'line_nr'});
} elsif (!$self->{'check_htmlxref_already_warned'}->{$manual_name}) {
$self->document_warn(sprintf($self->__(
"no htmlxref.cnf entry found for `%s'"), $manual_name),
);
}
$self->{'check_htmlxref_already_warned'}->{$manual_name} = 1;
}
}
if ($target_split) {
if (defined($href)) {
$file = $href;
} elsif (defined($self->get_conf('EXTERNAL_DIR'))) {
$file = $self->get_conf('EXTERNAL_DIR')."/$manual_base";
} elsif ($self->get_conf('SPLIT')) {
$file = "../$manual_base";
}
$file .= "/";
} else {# target not split
if (defined($href)) {
$file = $href;
} else {
if (defined($self->get_conf('EXTERNAL_DIR'))) {
$file = $self->get_conf('EXTERNAL_DIR')."/$manual_base";
} elsif ($self->get_conf('SPLIT')) {
$file = "../$manual_base";
} else {
$file = $manual_base;
}
$file .= $extension;
}
}
} else {
$file = '';
$target_split = $default_target_split;
}
if ($target eq '') {
if ($target_split) {
if (defined($self->get_conf('TOP_NODE_FILE_TARGET'))) {
return $file . $self->get_conf('TOP_NODE_FILE_TARGET')
. $extension;# . '#Top';
} else {
return $file;# . '#Top';
}
} else {
return $file . '#Top';
}
}
if (! $target_split) {
return $file . '#' . $xml_target;
} else {
my $file_basename;
if ($target eq 'Top' and defined($self->get_conf('TOP_NODE_FILE_TARGET'))) {
$file_basename = $self->get_conf('TOP_NODE_FILE_TARGET');
} else {
$file_basename = $target_filebase;
}
return $file . $file_basename . $extension . '#' . $xml_target;
}
}
my %valid_types = (
'href' => 1,
'string' => 1,
'text' => 1,
'tree' => 1,
'target' => 1,
'id' => 1,
'node' => 1,
);
foreach my $no_number_type ('text', 'tree', 'string') {
$valid_types{$no_number_type .'_nonumber'} = 1;
}
sub _element_direction($$$$;$)
{
my $self = shift;
my $element = shift;
my $direction = shift;
my $type = shift;
my $filename = shift;
my $element_target;
my $command;
my $target;
$filename = $self->{'current_filename'} if (!defined($filename));
if (!$valid_types{$type}) {
print STDERR "Incorrect type $type in _element_direction call\n";
return undef;
}
if ($self->{'global_target_elements'}->{$direction}) {
$element_target = $self->{'global_target_elements'}->{$direction};
} elsif ($element and $element->{'extra'}
and $element->{'extra'}->{'directions'}
and $element->{'extra'}->{'directions'}->{$direction}) {
$element_target
= $element->{'extra'}->{'directions'}->{$direction};
}
if ($element_target) {
######## debug
if (!$element_target->{'type'}) {
die "No type for element_target $direction $element_target: "
. Texinfo::Parser::_print_current_keys($element_target)
. "directions :". Texinfo::Structuring::_print_directions($element);
}
########
if ($element_target->{'type'} eq 'external_node'
or $element_target->{'type'} eq 'top_node_up') {
my $external_node = $element_target->{'extra'};
if ($type eq 'href') {
return $self->command_href($external_node, $filename);
} elsif ($type eq 'text' or $type eq 'node') {
return $self->command_text($external_node);
} elsif ($type eq 'string') {
return $self->command_text($external_node, $type);
}
} elsif ($type eq 'node') {
$command = $element_target->{'extra'}->{'node'};
$target = $self->{'targets'}->{$command} if ($command);
$type = 'text';
} else {
if ($element_target->{'extra'}->{'special_element'}) {
$command = $element_target;
} else {
$command = $element_target->{'extra'}->{'element_command'};
}
if ($type eq 'href') {
if (defined($command)) {
return $self->command_href($command, $filename);
} else {
return '';
}
}
$target = $self->{'targets'}->{$command} if ($command);
}
} elsif ($self->special_element($direction)) {
$element_target = $self->special_element($direction);
$command = $element_target;
if ($type eq 'href') {
return $self->command_href($element_target, $filename);
}
$target = $self->{'targets'}->{$element_target};
} else {
return undef;
}
if (exists($target->{$type})) {
return $target->{$type};
} elsif ($type eq 'id' or $type eq 'target') {
return undef;
} elsif ($command) {
return $self->command_text($command, $type);
}
}
sub _default_contents($$;$$)
{
my $self = shift;
my $cmdname = shift;
my $command = shift;
my $filename = shift;
$filename = $self->{'current_filename'} if (!defined($filename));
return ''
if (!$self->{'structuring'} or !$self->{'structuring'}->{'sectioning_root'});
my $section_root = $self->{'structuring'}->{'sectioning_root'};
my $contents;
$contents = 1 if ($cmdname eq 'contents');
my $min_root_level = $section_root->{'section_childs'}->[0]->{'level'};
my $max_root_level = $section_root->{'section_childs'}->[0]->{'level'};
foreach my $top_section(@{$section_root->{'section_childs'}}) {
$min_root_level = $top_section->{'level'}
if ($top_section->{'level'} < $min_root_level);
$max_root_level = $top_section->{'level'}
if ($top_section->{'level'} > $max_root_level);
}
# chapter level elements are considered top-level here.
$max_root_level = 1 if ($max_root_level < 1);
#print STDERR "ROOT_LEVEL Max: $max_root_level, Min: $min_root_level\n";
my $ul_class = '';
$ul_class = $NO_BULLET_LIST_CLASS if ($self->get_conf('NUMBER_SECTIONS'));
my $result = '';
if ($contents and !defined($self->get_conf('BEFORE_TOC_LINES'))
or (!$contents and !defined($self->get_conf('BEFORE_OVERVIEW')))) {
$result .= $self->_attribute_class('div', $cmdname).">\n";
} elsif($contents) {
$result .= $self->get_conf('BEFORE_TOC_LINES');
} else {
$result .= $self->get_conf('BEFORE_OVERVIEW');
}
my $toplevel_contents;
if (@{$section_root->{'section_childs'}} > 1) {
# or $section_root->{'section_childs'}->[0]->{'cmdname'} ne 'top') {
$result .= $self->_attribute_class('ul', $ul_class) .">\n";
$toplevel_contents = 1;
}
foreach my $top_section (@{$section_root->{'section_childs'}}) {
my $section = $top_section;
SECTION:
while ($section) {
if ($section->{'cmdname'} ne 'top') {
my $text = $self->command_text($section);
my $href;
if (!$contents and $self->get_conf('OVERVIEW_LINK_TO_TOC')) {
$href = $self->command_contents_href($section, 'contents', $filename);
} else {
$href = $self->command_href($section, $filename);
}
my $toc_id = $self->command_contents_id($section, $cmdname);
if ($text ne '') {
# no indenting for shortcontents
$result .= (' ' x (2*($section->{'level'} - $min_root_level)))
if ($contents);
if ($toc_id ne '' or $href ne '') {
my $toc_name_attribute = '';
if ($toc_id ne '') {
$toc_name_attribute = "name=\"$toc_id\" ";
}
my $href_attribute = '';
if ($href ne '') {
$href_attribute = "href=\"$href\"";
}
$result .= "
$text";
}
}
} elsif ($section->{'section_childs'} and @{$section->{'section_childs'}}
and $toplevel_contents) {
$result .= "
";
}
# for shortcontents don't do child if child is not toplevel
if ($section->{'section_childs'}
and ($contents or $section->{'level'} < $max_root_level)) {
# no indenting for shortcontents
$result .= "\n". ' ' x (2*($section->{'level'} - $min_root_level))
if ($contents);
$result .= $self->_attribute_class('ul', $ul_class) .">\n";
$section = $section->{'section_childs'}->[0];
} elsif ($section->{'section_next'} and $section->{'cmdname'} ne 'top') {
$result .= "
\n";
last if ($section eq $top_section);
$section = $section->{'section_next'};
} else {
#last if ($section eq $top_section);
if ($section eq $top_section) {
$result .= "\n" unless ($section->{'cmdname'} eq 'top');
last;
}
while ($section->{'section_up'}) {
$section = $section->{'section_up'};
$result .= "\n". ' ' x (2*($section->{'level'} - $min_root_level))
. "";
if ($section eq $top_section) {
$result .= "\n" if ($toplevel_contents);
last SECTION;
}
if ($section->{'section_next'}) {
$result .= "\n";
$section = $section->{'section_next'};
last;
}
}
}
}
}
if (@{$section_root->{'section_childs'}} > 1) {
# or $section_root->{'section_childs'}->[0]->{'cmdname'} ne 'top') {
$result .= "\n";
}
if ($contents and !defined($self->get_conf('AFTER_TOC_LINES'))
or (!$contents and !defined($self->get_conf('AFTER_OVERVIEW')))) {
$result .= "\n\n";
} elsif($contents) {
$result .= $self->get_conf('AFTER_TOC_LINES');
} else {
$result .= $self->get_conf('AFTER_OVERVIEW');
}
return $result;
}
sub _default_program_string($)
{
my $self = shift;
if (defined($self->get_conf('PROGRAM'))
and $self->get_conf('PROGRAM') ne ''
and defined($self->get_conf('PACKAGE_URL'))) {
return $self->convert_tree(
$self->gdt('This document was generated on @emph{@today{}} using @uref{{program_homepage}, @emph{{program}}}.',
{ 'program_homepage' => $self->get_conf('PACKAGE_URL'),
'program' => $self->get_conf('PROGRAM') }));
} else {
return $self->convert_tree(
$self->gdt('This document was generated on @emph{@today{}}.'));
}
}
sub _default_end_file($)
{
my $self = shift;
my $program_text = '';
if ($self->get_conf('PROGRAM_NAME_IN_FOOTER')) {
my $program_string = &{$self->{'format_program_string'}}($self);
$program_text = "
$program_string
";
}
my $pre_body_close = $self->get_conf('PRE_BODY_CLOSE');
$pre_body_close = '' if (!defined($pre_body_close));
return "$program_text
$pre_body_close