1# Parser.pm: parse texinfo code into a tree. 2# 3# Copyright 2010-2020 Free Software Foundation, Inc. 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, 8# or (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17# 18# Original author: Patrice Dumas <pertusus@free.fr> 19# Parts (also from Patrice Dumas) come from texi2html.pl or texi2html.init. 20 21# The organization of the file is the following: 22# module definitions. 23# default parser state. With explanation of the internal structures. 24# initializations, determination of command types. 25# user visible subroutines. 26# internal subroutines, doing the parsing. 27 28package Texinfo::Parser; 29 30# We need the unicode stuff. 31use 5.006; 32use strict; 33 34# debug 35use Carp qw(cluck); 36 37use Data::Dumper; 38 39# to detect if an encoding may be used to open the files 40use Encode; 41 42# for fileparse 43use File::Basename; 44 45# Clone could be faster for small structures, which should be the case 46# here, but Clone is not in perl core modules, so we use Storable::dclone. 47use Storable qw(dclone); # standard in 5.007003 48 49# commands definitions 50use Texinfo::Common; 51# Error reporting and counting, translation of strings. 52use Texinfo::Report; 53# encoding_alias 54use Texinfo::Encoding; 55 56# to normalize node name, anchor, float arg, and first *ref argument. 57use Texinfo::Convert::NodeNameNormalization; 58# in error messages, and for macro body expansion 59use Texinfo::Convert::Texinfo; 60 61require Exporter; 62use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 63@ISA = qw(Exporter Texinfo::Report); 64 65our $module_loaded = 0; 66sub import { 67 if (!$module_loaded) { 68 Texinfo::XSLoader::override ("Texinfo::Parser::_merge_text", 69 "Texinfo::MiscXS::merge_text"); 70 Texinfo::XSLoader::override ("Texinfo::Parser::_abort_empty_line", 71 "Texinfo::MiscXS::abort_empty_line"); 72 Texinfo::XSLoader::override ("Texinfo::Parser::_parse_texi_regex", 73 "Texinfo::MiscXS::parse_texi_regex"); 74 $module_loaded = 1; 75 } 76 # The usual import method 77 goto &Exporter::import; 78} 79 80 81%EXPORT_TAGS = ( 'all' => [ qw( 82 parser 83 parse_texi_text 84 parse_texi_line 85 parse_texi_file 86 indices_information 87 floats_information 88 internal_references_information 89 labels_information 90 global_commands_information 91 global_informations 92) ] ); 93 94@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 95 96@EXPORT = qw( 97); 98 99$VERSION = '6.8'; 100 101sub N__($) 102{ 103 return $_[0]; 104} 105 106my %parser_default_configuration = ( 107 %Texinfo::Common::default_parser_state_configuration, 108 %Texinfo::Common::default_parser_customization_values, 109 %Texinfo::Common::default_structure_customization_values, 110 'clickstyle' => 'arrow', 111 'kbdinputstyle' => 'distinct', 112 # this is not really used, but this allows to have an 113 # output more similar to the XS parser output. 114 'floats' => {}, 115); 116 117# the other possible keys for the parser state are: 118# 119# expanded_formats_hash each key comes from expanded_formats value is 1 120# index_names a structure holding the link between index 121# names, merged indices, 122# initial value is %index_names in Texinfo::Common. 123# context_stack stack of the contexts, more recent on top. 124# 'line' is added when on a line or 125# block @-command line, 126# 'def' is added instead if on a definition line. 127# 'preformatted' is added in block commands 128# where there is no paragraphs and spaces are kept 129# (format, example, display...) 130# 'math' is added in math block commands (displaymath) 131# 'rawpreformatted' is added in raw block commands 132# (html, xml, docbook...) 133# 'menu' is added in menu commands 134# 'math', 'footnote', 'caption', 'shortcaption', 135# 'inlineraw' are also added when in those commands 136# conditionals_stack a stack of conditional commands that are expanded. 137# macro_stack stack of macros being expanded (more recent first) 138# definfoenclose an hash, key is the command name, value is an array 139# reference with 2 values, beginning and ending. 140# input a stack, with last at bottom. Holds the opened files 141# or text. Pending macro expansion or text expansion 142# is also in that structure. 143# line_commands the same as %line_commands in Texinfo::Common, 144# but with index entry commands dynamically added 145# close_paragraph_commands same as %close_paragraph_commands 146# close_preformatted_commands same as %close_preformatted_commands 147# no_paragraph_commands the same as %default_no_paragraph_commands 148# below, with index 149# entry commands dynamically added 150# simple_text_commands the same as %simple_text_commands below, but 151# with index entry commands dynamically added 152# current_node last seen node. 153# current_section last seen section. 154# nodes list of nodes. 155# command_index associate a command name with an index name 156# floats key is the normalized float type, value is an array 157# reference holding all the floats. 158# internal_references an array holding all the internal references. 159 160# set points to the value set when initializing, for 161# configuration items that are not to be overriden 162# by @-commands. For example documentlanguage. 163 164# A line information is an hash reference with the keys: 165# line_nr the line number 166# file_name the file name 167# macro if in a macro expansion, the name of the macro 168# 169# A text fragment information is a 2 element array reference, the first is the 170# text fragment, the second is the line information. 171 172# The input structure is an array, the first is the most recently included 173# file. The last element may be a file if the parsing is done on a file, 174# with parse_texi_file, or simply pending text, if called as parse_texi_text. 175# each element of the array is a hash reference. The key are: 176# pending an array reference containing pending text fragments, either the 177# text given as parse_texi_text or macro expansion text. 178# name file name 179# line_nr current line number in the file 180# fh filehandle for the file 181 182# The commands in initialization_overrides are not set in the document if 183# set at the parser initialization. 184my %initialization_overrides = ( 185 'documentlanguage' => 1, 186); 187 188my %no_brace_commands = %Texinfo::Common::no_brace_commands; 189my %line_commands = %Texinfo::Common::line_commands; 190my %other_commands = %Texinfo::Common::other_commands; 191my %brace_commands = %Texinfo::Common::brace_commands; 192my %accent_commands = %Texinfo::Common::accent_commands; 193my %context_brace_commands = %Texinfo::Common::context_brace_commands; 194my %block_commands = %Texinfo::Common::block_commands; 195my %block_item_commands = %Texinfo::Common::block_item_commands; 196my %close_paragraph_commands = %Texinfo::Common::close_paragraph_commands; 197my %def_map = %Texinfo::Common::def_map; 198my %def_commands = %Texinfo::Common::def_commands; 199my %def_aliases = %Texinfo::Common::def_aliases; 200my %menu_commands = %Texinfo::Common::menu_commands; 201my %preformatted_commands = %Texinfo::Common::preformatted_commands; 202my %math_commands = %Texinfo::Common::math_commands; 203my %format_raw_commands = %Texinfo::Common::format_raw_commands; 204my %item_container_commands = %Texinfo::Common::item_container_commands; 205my %item_line_commands = %Texinfo::Common::item_line_commands; 206my %deprecated_commands = %Texinfo::Common::deprecated_commands; 207my %root_commands = %Texinfo::Common::root_commands; 208my %sectioning_commands = %Texinfo::Common::sectioning_commands; 209my %command_index = %Texinfo::Common::command_index; 210my %ref_commands = %Texinfo::Common::ref_commands; 211my %region_commands = %Texinfo::Common::region_commands; 212my %code_style_commands = %Texinfo::Common::code_style_commands; 213my %in_heading_commands = %Texinfo::Common::in_heading_commands; 214my %in_index_commands = %Texinfo::Common::in_index_commands; 215my %explained_commands = %Texinfo::Common::explained_commands; 216my %inline_format_commands = %Texinfo::Common::inline_format_commands; 217my %inline_commands = %Texinfo::Common::inline_commands; 218my %all_commands = %Texinfo::Common::all_commands; 219 220# equivalence between a @set flag and an @@-command 221my %set_flag_command_equivalent = ( 222 'txicodequoteundirected' => 'codequoteundirected', 223 'txicodequotebacktick' => 'codequotebacktick', 224# 'txideftypefnnl' => 'deftypefnnewline', 225); 226 227 228# keep line information for those commands. 229my %keep_line_nr_brace_commands = %context_brace_commands; 230foreach my $keep_line_nr_brace_command ('titlefont', 'anchor') { 231 $keep_line_nr_brace_commands{$keep_line_nr_brace_command} = 1; 232} 233foreach my $brace_command (keys (%brace_commands)) { 234 $keep_line_nr_brace_commands{$brace_command} = 1; 235} 236 237my %type_with_paragraph; 238foreach my $type ('before_item', 'text_root', 'document_root', 239 'brace_command_context') { 240 $type_with_paragraph{$type} = 1; 241} 242 243my %command_ignore_space_after; 244foreach my $command ('anchor', 'hyphenation', 'caption', 'shortcaption', 245 'sortas', 'seeentry', 'seealso') { 246 $command_ignore_space_after{$command} = 1; 247} 248 249my %global_multiple_commands; 250foreach my $global_multiple_command ( 251 'footnote', 'hyphenation', 'insertcopying', 'printindex', 252 'subtitle','titlefont', 'listoffloats', 'detailmenu', 'part', 253 keys(%Texinfo::Common::document_settable_at_commands), ) { 254 $global_multiple_commands{$global_multiple_command} = 1; 255} 256 257my %global_unique_commands; 258foreach my $global_unique_command ( 259 'copying', 'settitle', 260 'shorttitlepage', 'title', 'titlepage', 'top', 261 keys(%Texinfo::Common::document_settable_unique_at_commands), ) { 262 $global_unique_commands{$global_unique_command} = 1; 263} 264 265my %index_names = %Texinfo::Common::index_names; 266 267# index names that cannot be set by the user. 268my %forbidden_index_name = (); 269 270foreach my $name (keys(%index_names)) { 271 $forbidden_index_name{$name} = 1; 272 if ($name =~ /^(.).$/) { 273 $forbidden_index_name{$1} = 1; 274 } 275} 276 277foreach my $other_forbidden_index_name ('info','ps','pdf','htm', 278 'html', 'log','aux','dvi','texi','txi','texinfo','tex','bib') { 279 $forbidden_index_name{$other_forbidden_index_name} = 1; 280} 281 282# @-commands that do not start a paragraph 283my %default_no_paragraph_commands; 284# @-commands that should be at the beginning of a line 285my %begin_line_commands; 286 287foreach my $command ('node', 'end') { 288 $begin_line_commands{$command} = $command; 289} 290 291foreach my $no_paragraph_command ('titlefont', 'caption', 'shortcaption', 292 'image', '*', 'hyphenation', 'anchor', 'errormsg') { 293 $default_no_paragraph_commands{$no_paragraph_command} = 1; 294} 295 296foreach my $no_paragraph_command (keys(%line_commands), 297 keys(%other_commands)) { 298 $default_no_paragraph_commands{$no_paragraph_command} = 1; 299} 300 301foreach my $no_paragraph_command (keys(%line_commands)) { 302 $begin_line_commands{$no_paragraph_command} = 1; 303} 304 305# verbatiminclude is not said to begin at the beginning of the line 306# in the manual 307foreach my $not_begin_line_command ('comment', 'c', 'sp', 'columnfractions', 308 'item', 'verbatiminclude', 309 'set', 'clear', 'vskip', 'subentry') { 310 delete $begin_line_commands{$not_begin_line_command}; 311} 312 313my %block_arg_commands; 314foreach my $block_command (keys(%block_commands)) { 315 $begin_line_commands{$block_command} = 1; 316 $default_no_paragraph_commands{$block_command} = 1; 317 $block_arg_commands{$block_command} = 1 318 if ($block_commands{$block_command} ne 'raw'); 319# and ! $format_raw_commands{$block_command}); 320} 321 322my %close_preformatted_commands = %close_paragraph_commands; 323foreach my $no_close_preformatted('sp') { 324 delete $close_preformatted_commands{$no_close_preformatted}; 325} 326# FIXME to close preformated or not to close? 327#foreach my $format_raw_command(keys(%format_raw_commands)) { 328# $close_preformatted_commands{$format_raw_command} = 1; 329#} 330 331# commands that may appear in accents 332my %in_accent_commands = %accent_commands; 333foreach my $brace_command(keys(%brace_commands)) { 334 $in_accent_commands{$brace_command} = 1 if (!$brace_commands{$brace_command}); 335} 336foreach my $no_brace_command (keys(%no_brace_commands)) { 337 $in_accent_commands{$no_brace_command} = 1; 338} 339$in_accent_commands{'c'} = 1; 340$in_accent_commands{'comment'} = 1; 341 342# commands that may appear in text arguments 343my %in_full_text_commands; 344foreach my $command (keys(%brace_commands), keys(%no_brace_commands)) { 345 $in_full_text_commands{$command} = 1; 346} 347foreach my $in_full_text_command ('c', 'comment', 'refill', 'subentry', 348 'columnfractions', 'set', 'clear', 'end') { 349 $in_full_text_commands{$in_full_text_command} = 1; 350} 351 352foreach my $out_format (keys(%format_raw_commands)) { 353 $in_full_text_commands{$out_format} = 1; 354} 355delete $in_full_text_commands{'caption'}; 356delete $in_full_text_commands{'shortcaption'}; 357foreach my $block_command (keys(%block_commands)) { 358 $in_full_text_commands{$block_command} = 1 359 if ($block_commands{$block_command} eq 'conditional'); 360} 361 362 363# commands that may appear inside sectioning commands 364my %in_full_line_commands_no_refs = %in_full_text_commands; 365foreach my $not_in_full_line_commands_no_refs ('titlefont', 366 'anchor', 'footnote', 'verb') { 367 delete $in_full_line_commands_no_refs{$not_in_full_line_commands_no_refs}; 368} 369 370# commands that may happen in simple text arguments 371my %in_simple_text_commands = %in_full_line_commands_no_refs; 372foreach my $not_in_simple_text_command('xref', 'ref', 'pxref', 'inforef') { 373 delete $in_simple_text_commands{$not_in_simple_text_command}; 374} 375 376# commands that only accept simple text as argument in any context. 377my %simple_text_commands; 378foreach my $line_command(keys(%line_commands)) { 379 if ($line_commands{$line_command} =~ /^\d+$/ 380 or ($line_commands{$line_command} eq 'line' 381 and !($sectioning_commands{$line_command} 382 or $def_commands{$line_command})) 383 or $line_commands{$line_command} eq 'text') { 384 $simple_text_commands{$line_command} = 1; 385 } 386} 387 388my %full_line_commands_no_refs = (%sectioning_commands, 389 %def_commands); 390 391delete $simple_text_commands{'center'}; 392delete $simple_text_commands{'exdent'}; 393 394foreach my $command (keys (%brace_commands)) { 395 if ($brace_commands{$command} =~ /\d/ 396 and $brace_commands{$command} > 0 397 and !$inline_commands{$command}) { 398 $simple_text_commands{$command} = 1; 399 } 400} 401 402foreach my $command ('shortcaption', 'math') { 403 $simple_text_commands{$command} = 1; 404} 405 406# commands that accept full text, but no block or top-level commands 407my %full_text_commands; 408foreach my $brace_command (keys (%brace_commands)) { 409 if ($brace_commands{$brace_command} eq 'style') { 410 $full_text_commands{$brace_command} = 1; 411 } 412} 413 414# commands that accept almost the same as in full text, except 415# what does not make sense on a line. 416my %full_line_commands; 417$full_line_commands{'center'} = 1; 418$full_line_commands{'exdent'} = 1; 419$full_line_commands{'item'} = 1; 420$full_line_commands{'itemx'} = 1; 421 422# Fill the valid nestings hash. The keys are the containing commands and 423# the values arrays of commands that are allowed to occur inside those 424# commands. All commands not in this hash are considered to accept anything. 425# There are additional context tests, to make sure, for instance that we are 426# testing @-commands on the block, line or node @-command line and not 427# in the content. 428# Index entry commands are dynamically set as %in_simple_text_commands 429my %default_valid_nestings; 430 431foreach my $command (keys(%accent_commands)) { 432 $default_valid_nestings{$command} = \%in_accent_commands; 433} 434foreach my $command (keys(%simple_text_commands)) { 435 $default_valid_nestings{$command} = \%in_simple_text_commands; 436} 437foreach my $command (keys(%full_text_commands), keys(%full_line_commands)) { 438 $default_valid_nestings{$command} = \%in_full_text_commands; 439} 440foreach my $command (keys(%full_line_commands_no_refs)) { 441 $default_valid_nestings{$command} = \%in_full_line_commands_no_refs; 442} 443 444# Only for block commands with line arguments 445foreach my $command (keys(%block_commands)) { 446 if ($block_commands{$command} and $block_commands{$command} ne 'raw' 447 and $block_commands{$command} ne 'conditional' 448 and !$def_commands{$command}) { 449 $default_valid_nestings{$command} = \%in_simple_text_commands; 450 } 451} 452 453 454my @preformatted_contexts = ('preformatted', 'rawpreformatted'); 455my %preformatted_contexts; 456foreach my $preformatted_context (@preformatted_contexts) { 457 $preformatted_contexts{$preformatted_context} = 1; 458} 459 460# contexts on the context_stack stack where empty line doesn't trigger 461# a paragraph 462my %no_paragraph_contexts; 463foreach my $no_paragraph_context ('math', 'menu', @preformatted_contexts, 464 'def', 'inlineraw') { 465 $no_paragraph_contexts{$no_paragraph_context} = 1; 466}; 467 468 469 470# Format a bug message 471sub _bug_message($$;$$) 472{ 473 my ($self, $message, $line_number, $current) = @_; 474 475 my $line_message = ''; 476 if ($line_number) { 477 my $file = $line_number->{'file_name'}; 478 $line_message 479 = "last location: $line_number->{'file_name'}:$line_number->{'line_nr'}"; 480 if ($line_number->{'macro'} ne '') { 481 $line_message .= " (possibly involving $line_number->{'macro'})"; 482 } 483 $line_message .= "\n"; 484 } 485 my $message_context_stack = "context_stack: (@{$self->{'context_stack'}})\n"; 486 my $current_element_message = ''; 487 if ($current) { 488 $current_element_message = "current: ". _print_current($current); 489 } 490 warn "You found a bug: $message\n\n". 491 "Additional informations:\n". 492 $line_message.$message_context_stack.$current_element_message; 493} 494 495# simple deep copy of a structure 496# NOTE: currently not used, dclone is used instead. But in case dclone 497# happens not to be enough in the future, _deep_copy could be reused. 498sub _deep_copy($) 499{ 500 my $struct = shift; 501 my $string = Data::Dumper->Dump([$struct], ['struct']); 502 eval $string; 503 return $struct; 504} 505 506sub _setup_conf($$$) 507{ 508 my ($parser, $conf, $module_name) = @_; 509 510 if (defined($conf)) { 511 foreach my $key (keys(%$conf)) { 512 if (exists($parser_default_configuration{$key})) { 513 if ($key eq 'info') { 514 # merge hashes prefering values from $conf 515 $parser->{'info'} = { %{$parser->{'info'}}, %{$conf->{'info'}} }; 516 } elsif ($key ne 'values' and ref($conf->{$key})) { 517 $parser->{$key} = dclone($conf->{$key}); 518 } else { 519 $parser->{$key} = $conf->{$key}; 520 } 521 if ($initialization_overrides{$key}) { 522 $parser->{'set'}->{$key} = $parser->{$key}; 523 } 524 } else { 525 warn "$key not a possible customization in $module_name\n"; 526 } 527 } 528 } 529} 530 531# initialization entry point. Set up a parser. 532# The last argument, optional, is a hash provided by the user to change 533# the default values for what is present in %parser_default_configuration. 534sub parser(;$$) 535{ 536 my $conf = shift; 537 538 my $parser = dclone(\%parser_default_configuration); 539 bless $parser; 540 541 return _setup_parser($parser, $conf); 542} 543 544sub _setup_parser { 545 my ($parser, $conf) = @_; 546 547 _setup_conf($parser, $conf, "Texinfo::Parser::parser"); 548 549 # Now initialize command hash that are dynamically modified, notably 550 # those for index commands, and lists, based on defaults and user provided. 551 $parser->{'line_commands'} = dclone(\%line_commands); 552 $parser->{'valid_nestings'} = dclone(\%default_valid_nestings); 553 $parser->{'no_paragraph_commands'} = { %default_no_paragraph_commands }; 554 $parser->{'index_names'} = dclone(\%index_names); 555 $parser->{'command_index'} = {%command_index}; 556 $parser->{'close_paragraph_commands'} = {%close_paragraph_commands}; 557 $parser->{'close_preformatted_commands'} = {%close_preformatted_commands}; 558 # a hash is simply concatenated. It should be like %index_names. 559 if (ref($parser->{'indices'}) eq 'HASH') { 560 %{$parser->{'index_names'}} = (%{$parser->{'index_names'}}, 561 %{$parser->{'indices'}}); 562 } else { # an array holds index names defined with @defindex 563 foreach my $name (@{$parser->{'indices'}}) { 564 $parser->{'index_names'}->{$name} = {'in_code' => 0}; 565 } 566 } 567 foreach my $index (keys (%{$parser->{'index_names'}})) { 568 if (!exists($parser->{'index_names'}->{$index}->{'name'})) { 569 $parser->{'index_names'}->{$index}->{'name'} = $index; 570 } 571 if (!exists($parser->{'index_names'}->{$index}->{'contained_indices'})) { 572 $parser->{'index_names'}->{$index}->{'contained_indices'}->{$index} = 1; 573 } 574 foreach my $prefix ($index, substr($index, 0, 1)) { 575 $parser->{'line_commands'}->{$prefix.'index'} = 'line'; 576 $parser->{'no_paragraph_commands'}->{$prefix.'index'} = 1; 577 $parser->{'valid_nestings'}->{$prefix.'index'} = \%in_simple_text_commands; 578 $parser->{'command_index'}->{$prefix.'index'} = $index; 579 } 580 } 581 if ($parser->{'merged_indices'}) { 582 foreach my $index_from (keys (%{$parser->{'merged_indices'}})) { 583 my $index_to = $parser->{'merged_indices'}->{$index_from}; 584 if (defined($parser->{'index_names'}->{$index_from}) 585 and defined($parser->{'index_names'}->{$index_to})) { 586 $parser->{'index_names'}->{$index_from}->{'merged_in'} = $index_to; 587 $parser->{'index_names'}->{$index_to}->{'contained_indices'}->{$index_from} = 1; 588 } 589 } 590 } 591 foreach my $explained_command(keys(%explained_commands)) { 592 if (!defined($parser->{'explained_commands'}->{$explained_command})) { 593 $parser->{'explained_commands'}->{$explained_command} = {}; 594 } 595 } 596 $parser->{'context_stack'} = [ '_root' ]; 597 $parser->{'regions_stack'} = []; 598 $parser->{'macro_stack'} = []; 599 $parser->{'conditionals_stack'} = []; 600 601 # turn the array to a hash for speed. Not sure it really matters for such 602 # a small array. 603 foreach my $expanded_format(@{$parser->{'expanded_formats'}}) { 604 $parser->{'expanded_formats_hash'}->{$expanded_format} = 1; 605 } 606 607 %{$parser->{'global_commands'}} = %global_multiple_commands; 608 609 $parser->Texinfo::Report::new; 610 611 return $parser; 612} 613 614# simple parser initialization, fit for strings of Texinfo, not whole 615# documents, targetting speed. 616# all the simple_parsers share the dynamic informations 617my $simple_parser_line_commands = dclone(\%line_commands); 618my $simple_parser_valid_nestings = dclone(\%default_valid_nestings); 619my $simple_parser_no_paragraph_commands = { %default_no_paragraph_commands }; 620my $simple_parser_index_names = dclone(\%index_names); 621my $simple_parser_command_index = {%command_index}; 622my $simple_parser_close_paragraph_commands = {%close_paragraph_commands}; 623my $simple_parser_close_preformatted_commands = {%close_preformatted_commands}; 624sub simple_parser(;$) 625{ 626 my $conf = shift; 627 628 my $parser = dclone(\%parser_default_configuration); 629 bless $parser; 630 631 _setup_conf($parser, $conf, "Texinfo::Parser::simple_parser"); 632 633 $parser->{'line_commands'} = $simple_parser_line_commands; 634 $parser->{'valid_nestings'} = $simple_parser_valid_nestings; 635 $parser->{'no_paragraph_commands'} = $simple_parser_no_paragraph_commands; 636 $parser->{'index_names'} = $simple_parser_index_names; 637 $parser->{'command_index'} = $simple_parser_command_index; 638 $parser->{'close_paragraph_commands'} = $simple_parser_close_paragraph_commands; 639 $parser->{'close_preformatted_commands'} = $simple_parser_close_preformatted_commands; 640 641 foreach my $explained_command(keys(%explained_commands)) { 642 if (!defined($parser->{'explained_commands'}->{$explained_command})) { 643 $parser->{'explained_commands'}->{$explained_command} = {}; 644 } 645 } 646 $parser->{'context_stack'} = [ '_root' ]; 647 $parser->{'regions_stack'} = []; 648 $parser->{'macro_stack'} = []; 649 $parser->{'conditionals_stack'} = []; 650 651 # turn the array to a hash for speed. Not sure it really matters for such 652 # a small array. 653 foreach my $expanded_format(@{$parser->{'expanded_formats'}}) { 654 $parser->{'expanded_formats_hash'}->{$expanded_format} = 1; 655 } 656 657 %{$parser->{'global_commands'}} = (); 658 659 $parser->Texinfo::Report::new; 660 661 return $parser; 662} 663 664sub get_conf($$) 665{ 666 my ($self, $var) = @_; 667 return $self->{$var}; 668} 669 670# split a scalar text in an array lines. 671sub _text_to_lines($) 672{ 673 my $text = shift; 674 die if (!defined($text)); 675 my $had_final_end_line = chomp($text); 676 my $lines = [ map {$_."\n"} split (/\n/, $text, -1) ]; 677 chomp($lines->[-1]) unless (!@$lines or $had_final_end_line); 678 return $lines; 679} 680 681# construct a text fragments array matching a lines array, based on information 682# supplied. 683# If $fixed_line_number is set the line number is not increased, otherwise 684# it is increased, beginning at $first_line. 685sub _complete_line_nr($$;$$$) 686{ 687 my ($lines, $first_line, $file, $macro, $fixed_line_number) = @_; 688 689 $macro = '' if (!defined($macro)); 690 $file = '' if (!defined($file)); 691 my $new_lines = []; 692 693 if (defined($first_line)) { 694 my $line_index = $first_line; 695 foreach my $index(0..scalar(@$lines)-1) { 696 $line_index = $index+$first_line if (!$fixed_line_number); 697 $new_lines->[$index] = [ $lines->[$index], 698 { 'line_nr' => $line_index, 699 'file_name' => $file, 'macro' => $macro } ]; 700 } 701 } else { 702 foreach my $line (@$lines) { 703 push @$new_lines, [ $line ]; 704 } 705 } 706 return $new_lines; 707} 708 709# entry point for text fragments. 710# Used in tests. 711# It has no specific root type, the default set in _parse_texi is used 712sub parse_texi_text($$;$$$$) 713{ 714 my ($self, $text, $lines_nr, $file, $macro, $fixed_line_number) = @_; 715 716 return undef if (!defined($text)); 717 718 my $lines_array = []; 719 if (!ref($text)) { 720 $text = _text_to_lines($text); 721 } 722 $lines_nr = [] if (!defined($lines_nr)); 723 if (!ref($lines_nr)) { 724 $lines_array = _complete_line_nr($text, $lines_nr, $file, 725 $macro, $fixed_line_number); 726 } else { 727 while (@$text) { 728 my $line_nr = shift @$lines_nr; 729 my $line = shift @$text; 730 push @$lines_array, [$line, $line_nr]; 731 } 732 } 733 734 $self = parser() if (!defined($self)); 735 $self->{'input'} = [{'pending' => $lines_array}]; 736 my $tree = $self->_parse_texi(); 737 return $tree; 738} 739 740sub _open_in { 741 my ($self, $filehandle, $file_name) = @_; 742 743 if (open($filehandle, $file_name)) { 744 if (defined($self->{'info'}->{'input_perl_encoding'})) { 745 if ($self->{'info'}->{'input_perl_encoding'} eq 'utf-8') { 746 binmode($filehandle, ":utf8"); 747 # Use :utf8 instead of :encoding(utf-8), as the latter does 748 # error checking and has (unreliably) led to fatal errors 749 # when reading the first few lines of e.g. Latin-1 or Shift-JIS 750 # files, even though @documentencoding is given early on in the file. 751 # Evidently Perl is checking ahead in the file. 752 } else { 753 binmode($filehandle, ":encoding($self->{'info'}->{'input_perl_encoding'})"); 754 } 755 } 756 return 1; 757 } else { 758 return 0; 759 } 760} 761 762# parse a texi file 763sub parse_texi_file($$) 764{ 765 my ($self, $file_name) = @_; 766 767 my $filehandle = do { local *FH }; 768 if (!_open_in($self, $filehandle, $file_name)) { 769 $self->document_error(sprintf(__("could not open %s: %s"), 770 $file_name, $!)); 771 return undef; 772 } 773 my $line_nr = 0; 774 my $line; 775 my @first_lines; 776 777 my $pending_first_texi_line; 778 # the first line not empty and not with \input is kept in 779 # $pending_first_texi_line and put in the pending lines just below 780 while ($line = <$filehandle>) { 781 $line_nr++; 782 if ($line =~ /^ *\\input/ or $line =~ /^\s*$/) { 783 $line =~ s/\x{7F}.*\s*//; 784 push @first_lines, $line; 785 } else { 786 $pending_first_texi_line = $line; 787 last; 788 } 789 } 790 my $root = { 'contents' => [], 'type' => 'text_root' }; 791 if (@first_lines) { 792 push @{$root->{'contents'}}, { 'type' => 'preamble', 'contents' => [], 793 'parent' => $root }; 794 foreach my $line (@first_lines) { 795 push @{$root->{'contents'}->[-1]->{'contents'}}, 796 { 'text' => $line, 797 'type' => 'preamble_text', 798 'parent' => $root->{'contents'}->[-1] 799 }; 800 } 801 } 802 my ($directories, $suffix); 803 ($file_name, $directories, $suffix) = fileparse($file_name); 804 $self = parser() if (!defined($self)); 805 $self->{'input'} = [{ 806 'pending' => [[$pending_first_texi_line, {'line_nr' => $line_nr, 807 'macro' => '', 'file_name' => $file_name}]], 808 'name' => $file_name, 809 'line_nr' => $line_nr, 810 'fh' => $filehandle 811 }]; 812 $self->{'info'}->{'input_file_name'} = $file_name; 813 $self->{'info'}->{'input_directory'} = $directories; 814 815 my $tree = $self->_parse_texi($root); 816 817 # Find 'text_root', which contains everything before first node/section. 818 # if there are elements, 'text_root' is the first content, otherwise it 819 # is the root. 820 my $text_root; 821 if ($tree->{'type'} eq 'text_root') { 822 $text_root = $tree; 823 } elsif ($tree->{'contents'} and $tree->{'contents'}->[0] 824 and $tree->{'contents'}->[0]->{'type'} eq 'text_root') { 825 $text_root = $tree->{'contents'}->[0]; 826 } 827 828 # Put everything before @setfilename in a special type. This allows to 829 # ignore everything before @setfilename. 830 if ($self->{'IGNORE_BEFORE_SETFILENAME'} and $text_root and 831 $self->{'extra'} and $self->{'extra'}->{'setfilename'} 832 and $self->{'extra'}->{'setfilename'}->{'parent'} eq $text_root) { 833 my $before_setfilename = {'type' => 'preamble_before_setfilename', 834 'parent' => $text_root, 835 'contents' => []}; 836 while ($text_root->{'contents'}->[0] ne $self->{'extra'}->{'setfilename'}) { 837 my $content = shift @{$text_root->{'contents'}}; 838 $content->{'parent'} = $before_setfilename; 839 push @{$before_setfilename->{'contents'}}, $content; 840 } 841 unshift (@{$text_root->{'contents'}}, $before_setfilename) 842 if (@{$before_setfilename->{'contents'}}); 843 } 844 #$self->_check_contents_location($tree); 845 846 return $tree; 847} 848 849sub parse_texi_line($$;$$$$) 850{ 851 my ($self, $text, $lines_nr, $file, $macro, $fixed_line_number) = @_; 852 853 return undef if (!defined($text)); 854 855 if (!ref($text)) { 856 $text = _text_to_lines($text); 857 } 858 my $lines_array = _complete_line_nr($text, $lines_nr, $file, 859 $macro, $fixed_line_number); 860 861 $self = parser() if (!defined($self)); 862 $self->{'input'} = [{'pending' => $lines_array}]; 863 my $tree = $self->_parse_texi({'contents' => [], 'type' => 'root_line'}); 864 return $tree; 865} 866 867# return indices informations 868sub indices_information($) 869{ 870 my $self = shift; 871 return $self->{'index_names'}; 872} 873 874sub floats_information($) 875{ 876 my $self = shift; 877 return $self->{'floats'}; 878} 879 880sub internal_references_information($) 881{ 882 my $self = shift; 883 return $self->{'internal_references'}; 884} 885 886sub global_commands_information($) 887{ 888 my $self = shift; 889 return $self->{'extra'}; 890} 891 892# @ dircategory_direntry 893# perl_encoding 894# input_encoding_name 895# input_file_name 896sub global_informations($) 897{ 898 my $self = shift; 899 return $self->{'info'}; 900} 901 902# Setup labels and nodes info and return labels 903sub labels_information 904{ 905 goto &Texinfo::Common::labels_information; 906} 907 908# Following are the internal subroutines. The most important are 909# _parse_texi: the main parser loop. 910# _end_line: called at an end of line. Handling of @include lines is 911# done here. 912# _next_text: present the next text fragment, from pending text or line, 913# as described above. 914 915# for debugging 916sub _print_current($) 917{ 918 my $current = shift; 919 return Texinfo::Common::_print_current($current); 920} 921 922# for debugging 923sub _print_command_args_texi($) 924{ 925 my $current = shift; 926 return '' if (!$current->{'cmdname'}); 927 my $args = ''; 928 my $with_brace; 929 if ($current->{'args'} and @{$current->{'args'}}) { 930 $with_brace 931 = ($current->{'args'}->[0]->{'type'} eq 'brace_command_arg' 932 or $current->{'args'}->[0]->{'type'} eq 'brace_command_context'); 933 $args .= '{' if ($with_brace); 934 foreach my $arg (@{$current->{'args'}}) { 935 $args .= Texinfo::Convert::Texinfo::convert($arg).', '; 936 } 937 $args =~ s/, $//; 938 } 939 chomp($args); 940 if ($with_brace) { 941 $args .= '}'; 942 } 943 return '@'.$current->{'cmdname'} .$args."\n"; 944} 945 946sub _print_current_keys($) 947{ 948 my $current = shift; 949 my $string = _print_current($current); 950 foreach my $key (keys (%$current)) { 951 $string .= " $key: $current->{$key}\n"; 952 } 953 if ($current->{'extra'}) { 954 $string .= " EXTRA\n"; 955 foreach my $key (keys (%{$current->{'extra'}})) { 956 $string .= " $key: $current->{'extra'}->{$key}\n"; 957 } 958 } 959 return $string; 960} 961 962# For debugging 963sub _print_tree($) 964{ 965 my $tree = shift; 966 967 return Texinfo::Common::print_tree($tree); 968} 969 970sub _register_global_command { 971 my ($self, $current, $line_nr) = @_; 972 973 my $command = $current->{'cmdname'}; 974 975 if ($command eq 'summarycontents' and !$self->{'global_commands'}->{$command}) { 976 $command = 'shortcontents'; 977 } 978 if ($self->{'global_commands'}->{$command}) { 979 push @{$self->{'extra'}->{$command}}, $current; 980 $current->{'line_nr'} = $line_nr if (!$current->{'line_nr'}); 981 return 1; 982 } elsif ($global_unique_commands{$command}) { 983 # setfilename ignored in an included file 984 $current->{'line_nr'} = $line_nr if (!$current->{'line_nr'}); 985 if ($command eq 'setfilename' 986 and scalar(@{$self->{'input'}}) > 1) { 987 } elsif (exists ($self->{'extra'}->{$current->{'cmdname'}})) { 988 $self->line_warn(sprintf(__('multiple @%s'), 989 $current->{'cmdname'}), $line_nr); 990 } else { 991 $self->{'extra'}->{$current->{'cmdname'}} = $current; 992 } 993 return 1; 994 } 995 return 0; 996} 997 998# parse a @macro line 999sub _parse_macro_command_line($$$$$;$) 1000{ 1001 my ($self, $command, $line, $parent, $line_nr) = @_; 1002 1003 my $macro = { 'cmdname' => $command, 'parent' => $parent, 'contents' => [], 1004 'extra' => {'arg_line' => $line}, 'line_nr' => $line_nr }; 1005 # REMACRO 1006 if ($line =~ /^\s+([[:alnum:]][[:alnum:]_-]*)\s*(.*)/) { 1007 my $macro_name = $1; 1008 my $args_def = $2; 1009 my @args; 1010 1011 if ($args_def =~ s/^\s*{\s*(.*?)\s*}\s*//) { 1012 @args = split(/\s*,\s*/, $1); 1013 } 1014 1015 print STDERR "MACRO \@$command $macro_name\n" if ($self->{'DEBUG'}); 1016 1017 $macro->{'args'} = [ 1018 { 'type' => 'macro_name', 'text' => $macro_name, 1019 'parent' => $macro } ]; 1020 my $index = 0; 1021 foreach my $formal_arg (@args) { 1022 push @{$macro->{'args'}}, 1023 { 'type' => 'macro_arg', 'text' => $formal_arg, 1024 'parent' => $macro}; 1025 if ($formal_arg !~ /^[\w\-]+$/) { 1026 $self->line_error(sprintf(__("bad or empty \@%s formal argument: %s"), 1027 $command, $formal_arg), $line_nr); 1028 $macro->{'extra'}->{'invalid_syntax'} = 1; 1029 } 1030 $macro->{'extra'}->{'args_index'}->{$formal_arg} = $index; 1031 $index++; 1032 } 1033 # accept an @-command after the arguments in case there is a @c or 1034 # @comment 1035 if ($args_def =~ /^\s*[^\@]/) { 1036 $self->line_error(sprintf(__("bad syntax for \@%s argument: %s"), 1037 $command, $args_def), 1038 $line_nr); 1039 $macro->{'extra'}->{'invalid_syntax'} = 1; 1040 } 1041 } elsif ($line !~ /\S/) { 1042 $self->line_error(sprintf( 1043 __("%c%s requires a name"), ord('@'), $command), $line_nr); 1044 $macro->{'extra'}->{'invalid_syntax'} = 1; 1045 } else { 1046 $self->line_error(sprintf( 1047 __("bad name for \@%s"), $command), $line_nr); 1048 $macro->{'extra'}->{'invalid_syntax'} = 1; 1049 } 1050 return $macro; 1051} 1052 1053# start a paragraph if in a context where paragraphs are to be started. 1054sub _begin_paragraph($$;$) 1055{ 1056 my ($self, $current, $line_nr) = @_; 1057 1058 # !$current->{'type'} is true for @-commands. In fact it is unclear 1059 # that there may be cases of !$current->{'type'} and !$current->{'cmdname'} 1060 if ((!$current->{'type'} or $type_with_paragraph{$current->{'type'}}) 1061 and !$no_paragraph_contexts{$self->{'context_stack'}->[-1]}) { 1062 if (!defined($current->{'contents'})) { 1063 $self->_bug_message("contents undef", $line_nr, $current); 1064 die; 1065 } 1066 1067 # find whether an @indent precedes the paragraph 1068 my $indent; 1069 if (scalar(@{$current->{'contents'}})) { 1070 my $index = scalar(@{$current->{'contents'}}) -1; 1071 while ($index >= 0 1072 and !($current->{'contents'}->[$index]->{'type'} 1073 and ($current->{'contents'}->[$index]->{'type'} eq 'empty_line' 1074 or $current->{'contents'}->[$index]->{'type'} eq 'paragraph')) 1075 and !($current->{'contents'}->[$index]->{'cmdname'} 1076 and $self->{'close_paragraph_commands'}->{$current->{'contents'}->[$index]->{'cmdname'}})) { 1077 if ($current->{'contents'}->[$index]->{'cmdname'} 1078 and ($current->{'contents'}->[$index]->{'cmdname'} eq 'indent' 1079 or $current->{'contents'}->[$index]->{'cmdname'} eq 'noindent')) { 1080 $indent = $current->{'contents'}->[$index]->{'cmdname'}; 1081 last; 1082 } 1083 $index--; 1084 } 1085 } 1086 push @{$current->{'contents'}}, 1087 { 'type' => 'paragraph', 'parent' => $current, 'contents' => [] }; 1088 $current->{'contents'}->[-1]->{'extra'}->{$indent} = 1 if ($indent); 1089 $current = $current->{'contents'}->[-1]; 1090 print STDERR "PARAGRAPH\n" if ($self->{'DEBUG'}); 1091 return $current; 1092 } 1093 return 0; 1094} 1095 1096sub _begin_preformatted($$) 1097{ 1098 my ($self, $current) = @_; 1099 1100 if ($preformatted_contexts{$self->{'context_stack'}->[-1]}) { 1101 push @{$current->{'contents'}}, 1102 { 'type' => $self->{'context_stack'}->[-1], 1103 'parent' => $current, 'contents' => [] }; 1104 $current = $current->{'contents'}->[-1]; 1105 print STDERR "PREFORMATTED $self->{'context_stack'}->[-1]\n" if ($self->{'DEBUG'}); 1106 } 1107 return $current; 1108} 1109 1110# wrapper around line_warn. Set line_nr to be the line_nr of the command, 1111# corresponding to the opening of the command. Call line_warn with 1112# sprintf if needed. 1113sub _command_warn($$$$;@) 1114{ 1115 my $self = shift; 1116 my $current = shift; 1117 my $line_nr = shift; 1118 my $message = shift; 1119 1120 if ($current->{'line_nr'}) { 1121 $line_nr = $current->{'line_nr'}; 1122 } 1123 if (@_) { 1124 $self->line_warn(sprintf($message, @_), $line_nr); 1125 } else { 1126 $self->line_warn($message, $line_nr); 1127 } 1128} 1129 1130sub _command_error($$$$;@) 1131{ 1132 my $self = shift; 1133 my $current = shift; 1134 my $line_nr = shift; 1135 my $message = shift; 1136 1137 # use the beginning of the @-command for the error message 1138 # line number if available. 1139 # FIXME line_nr currently not registered for regular brace commands 1140 if ($current->{'line_nr'}) { 1141 $line_nr = $current->{'line_nr'}; 1142 } 1143 if (@_) { 1144 $self->line_error(sprintf($message, @_), $line_nr); 1145 } else { 1146 $self->line_error($message, $line_nr); 1147 } 1148} 1149 1150# currently doesn't do much more than 1151# return $_[1]->{'parent'} 1152sub _close_brace_command($$$;$$) 1153{ 1154 my ($self, $current, $line_nr, $closed_command, 1155 $interrupting_command) = @_; 1156 1157 if ($current->{'cmdname'} ne 'verb' 1158 or $current->{'extra'}->{'delimiter'} eq '') { 1159 if (defined($closed_command)) { 1160 $self->_command_error($current, $line_nr, 1161 __("\@end %s seen before \@%s closing brace"), 1162 $closed_command, $current->{'cmdname'}); 1163 } elsif (defined($interrupting_command)) { 1164 $self->_command_error($current, $line_nr, 1165 __("\@%s seen before \@%s closing brace"), 1166 $interrupting_command, $current->{'cmdname'}); 1167 1168 } else { 1169 $self->_command_error($current, $line_nr, 1170 __("%c%s missing closing brace"), ord('@'), $current->{'cmdname'}); 1171 } 1172 } else { 1173 $self->_command_error($current, $line_nr, 1174 __("\@%s missing closing delimiter sequence: %s}"), 1175 $current->{'cmdname'}, $current->{'extra'}->{'delimiter'}); 1176 } 1177 $current = $current->{'parent'}; 1178 return $current; 1179} 1180 1181sub _in_code($$) 1182{ 1183 my ($self, $current) = @_; 1184 1185 while ($current->{'parent'} and $current->{'parent'}->{'cmdname'} 1186 and exists $brace_commands{$current->{'parent'}->{'cmdname'}} 1187 and !exists $context_brace_commands{$current->{'parent'}->{'cmdname'}}) { 1188 return 1 if ($code_style_commands{$current->{'parent'}->{'cmdname'}}); 1189 $current = $current->{'parent'}->{'parent'}; 1190 } 1191 return 0; 1192} 1193 1194# close brace commands, that don't set a new context (ie @caption, @footnote) 1195sub _close_all_style_commands($$$;$$) 1196{ 1197 my ($self, $current, $line_nr, $closed_command, 1198 $interrupting_command) = @_; 1199 1200 while ($current->{'parent'} and $current->{'parent'}->{'cmdname'} 1201 and exists $brace_commands{$current->{'parent'}->{'cmdname'}} 1202 and !exists $context_brace_commands{$current->{'parent'}->{'cmdname'}}) { 1203 $current = _close_brace_command($self, $current->{'parent'}, $line_nr, 1204 $closed_command, $interrupting_command); 1205 } 1206 return $current; 1207} 1208 1209# close brace commands except for @caption, @footnote then the paragraph 1210sub _end_paragraph($$$;$$) 1211{ 1212 my ($self, $current, $line_nr, $closed_command, 1213 $interrupting_command) = @_; 1214 1215 $current = _close_all_style_commands($self, $current, $line_nr, 1216 $closed_command, $interrupting_command); 1217 if ($current->{'type'} and $current->{'type'} eq 'paragraph') { 1218 print STDERR "CLOSE PARA\n" if ($self->{'DEBUG'}); 1219 $current = $current->{'parent'}; 1220 } 1221 return $current; 1222} 1223 1224# close brace commands except for @caption, @footnote then the preformatted 1225sub _end_preformatted($$$;$$) 1226{ 1227 my ($self, $current, $line_nr, $closed_command, 1228 $interrupting_command) = @_; 1229 1230 $current = _close_all_style_commands($self, $current, $line_nr, 1231 $closed_command, $interrupting_command); 1232 if ($current->{'type'} and $preformatted_contexts{$current->{'type'}}) { 1233 print STDERR "CLOSE PREFORMATTED $current->{'type'}\n" if ($self->{'DEBUG'}); 1234 # completly remove void preformatted contexts 1235 if (!@{$current->{'contents'}}) { 1236 my $removed = pop @{$current->{'parent'}->{'contents'}}; 1237 print STDERR "popping $removed->{'type'}\n" if ($self->{'DEBUG'}); 1238 } 1239 $current = $current->{'parent'}; 1240 } 1241 return $current; 1242} 1243 1244# check that there are no text holding environment (currently 1245# checking only paragraphs and preformatted) in contents 1246sub _check_no_text($) 1247{ 1248 my $current = shift; 1249 my $after_paragraph = 0; 1250 foreach my $content (@{$current->{'contents'}}) { 1251 if ($content->{'type'} and $content->{'type'} eq 'paragraph') { 1252 $after_paragraph = 1; 1253 last; 1254 } elsif ($content->{'type'} and $preformatted_contexts{$content->{'type'}}) { 1255 foreach my $preformatted_content (@{$content->{'contents'}}) { 1256 if ((defined($preformatted_content->{'text'}) 1257 and $preformatted_content->{'text'} =~ /\S/) 1258 or ($preformatted_content->{'cmdname'} 1259 and ($preformatted_content->{'cmdname'} ne 'c' 1260 and $preformatted_content->{'cmdname'} ne 'comment') 1261 and !($preformatted_content->{'type'} 1262 and $preformatted_content->{'type'} eq 'index_entry_command'))) { 1263 $after_paragraph = 1; 1264 last; 1265 } 1266 } 1267 last if ($after_paragraph); 1268 } 1269 } 1270 return $after_paragraph; 1271} 1272 1273# put everything after the last @item/@itemx in an item_table type container 1274# and distinguish table_term and table_entry. 1275sub _gather_previous_item($$;$$) 1276{ 1277 my ($self, $current, $next_command, $line_nr) = @_; 1278 1279 # nothing to do in that case. 1280 if ($current->{'contents'}->[-1]->{'type'} 1281 and $current->{'contents'}->[-1]->{'type'} eq 'before_item') { 1282 if ($next_command and $next_command eq 'itemx') { 1283 $self->line_warn(sprintf(__("\@itemx should not begin \@%s"), 1284 $current->{'cmdname'}), $line_nr); 1285 } 1286 return; 1287 } 1288 my $type; 1289 # if before an itemx, the type is different since there should not be 1290 # real content, so it may be treated differently 1291 if ($next_command and $next_command eq 'itemx') { 1292 $type = 'inter_item'; 1293 } else { 1294 $type = 'table_item'; 1295 } 1296 my $table_gathered = {'type' => $type, 1297 'contents' => []}; 1298 # remove everything that is not an @item/@items or before_item to 1299 # put it in the table_item, starting from the end. 1300 my $contents_count = scalar(@{$current->{'contents'}}); 1301 for (my $i = 0; $i < $contents_count; $i++) { 1302 if ($current->{'contents'}->[-1]->{'cmdname'} 1303 and ($current->{'contents'}->[-1]->{'cmdname'} eq 'item' 1304 or ($current->{'contents'}->[-1]->{'cmdname'} eq 'itemx'))) { 1305 last; 1306 } else { 1307 my $item_content = pop @{$current->{'contents'}}; 1308 $item_content->{'parent'} = $table_gathered; 1309 unshift @{$table_gathered->{'contents'}}, $item_content; 1310 } 1311 } 1312 if ($type eq 'table_item') { 1313 my $table_entry = {'type' => 'table_entry', 1314 'parent' => $current, 1315 'contents' => []}; 1316 my $table_term = {'type' => 'table_term', 1317 'parent' => $table_entry, 1318 'contents' => []}; 1319 push @{$table_entry->{'contents'}}, $table_term; 1320 my $contents_count = scalar(@{$current->{'contents'}}); 1321 for (my $i = 0; $i < $contents_count; $i++) { 1322 if ($current->{'contents'}->[-1]->{'type'} 1323 and ($current->{'contents'}->[-1]->{'type'} eq 'before_item' 1324 or $current->{'contents'}->[-1]->{'type'} eq 'table_entry')) { 1325 last; 1326 } else { 1327 my $item_content = pop @{$current->{'contents'}}; 1328 $item_content->{'parent'} = $table_term; 1329 unshift @{$table_term->{'contents'}}, $item_content; 1330 # debug 1331 if (! (($item_content->{'cmdname'} 1332 and ($item_content->{'cmdname'} eq 'itemx' 1333 or $item_content->{'cmdname'} eq 'item')) 1334 or ($item_content->{'type'} 1335 and $item_content->{'type'} eq 'inter_item'))) { 1336 $self->_bug_message("wrong element in table term", $line_nr, 1337 $item_content); 1338 } 1339 } 1340 } 1341 push @{$current->{'contents'}}, $table_entry; 1342 if (scalar(@{$table_gathered->{'contents'}})) { 1343 push @{$table_entry->{'contents'}}, $table_gathered; 1344 $table_gathered->{'parent'} = $table_entry; 1345 } 1346 } else { 1347 my $after_paragraph = _check_no_text($table_gathered); 1348 if ($after_paragraph) { 1349 $self->line_error(__("\@itemx must follow \@item"), $line_nr); 1350 } 1351 if (scalar(@{$table_gathered->{'contents'}})) { 1352 push @{$current->{'contents'}}, $table_gathered; 1353 $table_gathered->{'parent'} = $current; 1354 } 1355 } 1356} 1357 1358# Starting from the end, gather everything util the def_line to put in 1359# a def_item 1360sub _gather_def_item($;$) 1361{ 1362 my ($current, $next_command) = @_; 1363 1364 my $type; 1365 # means that we are between a @def*x and a @def 1366 if ($next_command) { 1367 $type = 'inter_def_item'; 1368 } else { 1369 $type = 'def_item'; 1370 } 1371 1372 # This may happen for a construct like 1373 # @deffnx a b @section 1374 # but otherwise the end of line will lead to the command closing 1375 return if (!$current->{'cmdname'} or $current->{'cmdname'} =~ /x$/); 1376 my $def_item = {'type' => $type, 1377 'parent' => $current, 1378 'contents' => []}; 1379 # remove everything that is not a def_line to put it in the def_item, 1380 # starting from the end. 1381 my $contents_count = scalar(@{$current->{'contents'}}); 1382 for (my $i = 0; $i < $contents_count; $i++) { 1383 if ($current->{'contents'}->[-1]->{'type'} 1384 and $current->{'contents'}->[-1]->{'type'} eq 'def_line') { 1385 # and !$current->{'contents'}->[-1]->{'extra'}->{'not_after_command'}) { 1386 last; 1387 } else { 1388 my $item_content = pop @{$current->{'contents'}}; 1389 $item_content->{'parent'} = $def_item; 1390 unshift @{$def_item->{'contents'}}, $item_content; 1391 } 1392 } 1393 if (scalar(@{$def_item->{'contents'}})) { 1394 push @{$current->{'contents'}}, $def_item; 1395 } 1396} 1397 1398# close formats 1399sub _close_command_cleanup($$) { 1400 my ($self, $current) = @_; 1401 1402 return unless ($current->{'cmdname'}); 1403 # remove the dynamic counters in multitable, they are not of use in the final 1404 # tree. Also determine the multitable_body and multitable_head with 1405 # @item or @headitem rows. 1406 if ($current->{'cmdname'} eq 'multitable') { 1407 my $in_head_or_rows; 1408 my @contents = @{$current->{'contents'}}; 1409 $current->{'contents'} = []; 1410 foreach my $row (@contents) { 1411 if ($row->{'type'} and $row->{'type'} eq 'row') { 1412 delete $row->{'cells_count'}; 1413 if ($row->{'contents'}->[0]->{'cmdname'} eq 'headitem') { 1414 if (!$in_head_or_rows) { 1415 push @{$current->{'contents'}}, {'type' => 'multitable_head', 1416 'parent' => $current}; 1417 $in_head_or_rows = 1; 1418 } 1419 } elsif ($row->{'contents'}->[0]->{'cmdname'} eq 'item') { 1420 if (!defined($in_head_or_rows) or $in_head_or_rows) { 1421 push @{$current->{'contents'}}, {'type' => 'multitable_body', 1422 'parent' => $current}; 1423 $in_head_or_rows = 0; 1424 } 1425 } 1426 push @{$current->{'contents'}->[-1]->{'contents'}}, $row; 1427 $row->{'parent'} = $current->{'contents'}->[-1]; 1428 } else { 1429 push @{$current->{'contents'}}, $row; 1430 $in_head_or_rows = undef; 1431 } 1432 } 1433 delete $current->{'rows_count'}; 1434 } elsif ($item_container_commands{$current->{'cmdname'}}) { 1435 delete $current->{'items_count'}; 1436 } 1437 1438 # put everything after the last @def*x command in a def_item type container. 1439 if ($def_commands{$current->{'cmdname'}}) { 1440 # At this point the end command hasn't been added to the command contents. 1441 # so checks cannot be done at this point. 1442 _gather_def_item($current); 1443 } 1444 1445 if ($item_line_commands{$current->{'cmdname'}}) { 1446 # At this point the end command hasn't been added to the command contents. 1447 # so checks cannot be done at this point. 1448 if (@{$current->{'contents'}}) { 1449 _gather_previous_item($self, $current); 1450 } 1451 } 1452 1453 # put end out of before_item, and replace it at the end of the parent. 1454 # remove empty before_item. 1455 # warn if not empty before_item, but format is empty 1456 if ($block_item_commands{$current->{'cmdname'}}) { 1457 if (@{$current->{'contents'}}) { 1458 my $leading_spaces = 0; 1459 my $before_item; 1460 if ($current->{'contents'}->[0]->{'type'} 1461 and $current->{'contents'}->[0]->{'type'} eq 'empty_line_after_command' 1462 and $current->{'contents'}->[1] 1463 and $current->{'contents'}->[1]->{'type'} 1464 and $current->{'contents'}->[1]->{'type'} eq 'before_item') { 1465 $leading_spaces = 1; 1466 $before_item = $current->{'contents'}->[1]; 1467 } elsif ($current->{'contents'}->[0]->{'type'} 1468 and $current->{'contents'}->[0]->{'type'} eq 'before_item') { 1469 $before_item = $current->{'contents'}->[0]; 1470 } 1471 if ($before_item) { 1472 if ($current->{'extra'}->{'end_command'} 1473 and @{$before_item->{'contents'}} 1474 and $before_item->{'contents'}->[-1] eq $current->{'extra'}->{'end_command'}) { 1475 my $end = pop @{$before_item->{'contents'}}; 1476 $end->{'parent'} = $current; 1477 push @{$current->{'contents'}}, $end; 1478 } 1479 # remove empty before_items 1480 if (!@{$before_item->{'contents'}}) { 1481 if ($leading_spaces) { 1482 my $space = shift @{$current->{'contents'}}; 1483 shift @{$current->{'contents'}}; 1484 unshift @{$current->{'contents'}}, $space; 1485 } else { 1486 shift @{$current->{'contents'}}; 1487 } 1488 } else { 1489 # warn if not empty before_item, but format is empty 1490 my $empty_before_item = 1; 1491 foreach my $before_item_content (@{$before_item->{'contents'}}) { 1492 if (!$before_item_content->{'cmdname'} or 1493 ($before_item_content->{'cmdname'} ne 'c' 1494 and $before_item_content->{'cmdname'} ne 'comment')) { 1495 $empty_before_item = 0; 1496 last; 1497 } 1498 } 1499 if (!$empty_before_item) { 1500 my $empty_format = 1; 1501 foreach my $format_content (@{$current->{'contents'}}) { 1502 next if ($format_content eq $before_item); 1503 if (($format_content->{'cmdname'} and 1504 ($format_content->{'cmdname'} ne 'c' 1505 and $format_content->{'cmdname'} ne 'comment' 1506 and $format_content->{'cmdname'} ne 'end')) 1507 or ($format_content->{'type'} and 1508 ($format_content->{'type'} ne 'empty_line_after_command'))) { 1509 $empty_format = 0; 1510 last; 1511 } 1512 } 1513 if ($empty_format) { 1514 $self->line_warn(sprintf(__("\@%s has text but no \@item"), 1515 $current->{'cmdname'}), $current->{'line_nr'}); 1516 } 1517 } 1518 } 1519 } 1520 } 1521 } 1522} 1523 1524# close the current command, with error messages and give the parent. 1525# If the last argument is given it is the command being closed if 1526# hadn't there be an error, currently only block command, used for a 1527# better error message. 1528sub _close_current($$$;$$) 1529{ 1530 my ($self, $current, $line_nr, $closed_command, 1531 $interrupting_command) = @_; 1532 1533 if ($current->{'cmdname'}) { 1534 print STDERR "CLOSING(_close_current) \@$current->{'cmdname'}\n" if ($self->{'DEBUG'}); 1535 if (exists($brace_commands{$current->{'cmdname'}})) { 1536 pop @{$self->{'context_stack'}} 1537 if (exists $context_brace_commands{$current->{'cmdname'}}); 1538 $current = _close_brace_command($self, $current, $line_nr, 1539 $closed_command, $interrupting_command); 1540 } elsif (exists($block_commands{$current->{'cmdname'}})) { 1541 if (defined($closed_command)) { 1542 $self->line_error(sprintf(__("`\@end' expected `%s', but saw `%s'"), 1543 $current->{'cmdname'}, $closed_command), $line_nr); 1544 } elsif ($interrupting_command) { 1545 $self->line_error(sprintf(__("\@%s seen before \@end %s"), 1546 $interrupting_command, $current->{'cmdname'}), 1547 $line_nr); 1548 } else { 1549 $self->line_error(sprintf(__("no matching `%cend %s'"), 1550 ord('@'), $current->{'cmdname'}), $line_nr); 1551 if ($block_commands{$current->{'cmdname'}} eq 'conditional') { 1552 # in this case we are within an ignored conditional 1553 my $conditional = pop @{$current->{'parent'}->{'contents'}}; 1554 } 1555 } 1556 if ($preformatted_commands{$current->{'cmdname'}} 1557 or $menu_commands{$current->{'cmdname'}} 1558 or $format_raw_commands{$current->{'cmdname'}} 1559 or $math_commands{$current->{'cmdname'}}) { 1560 my $context = pop @{$self->{'context_stack'}}; 1561 } 1562 pop @{$self->{'regions_stack'}} 1563 if ($region_commands{$current->{'cmdname'}}); 1564 $current = $current->{'parent'}; 1565 } else { 1566 # There @item and @tab commands are closed, and also line commands 1567 # with invalid content 1568 $current = $current->{'parent'}; 1569 } 1570 } elsif ($current->{'type'}) { 1571 print STDERR "CLOSING type $current->{'type'}\n" if ($self->{'DEBUG'}); 1572 if ($current->{'type'} eq 'bracketed') { 1573 $self->_command_error($current, $line_nr, 1574 __("misplaced %c"), ord('{')); 1575 if ($current->{'contents'} 1576 and @{$current->{'contents'}} 1577 and $current->{'contents'}->[0]->{'type'} 1578 and $current->{'contents'}->[0]->{'type'} 1579 eq 'empty_spaces_before_argument') { 1580 # remove spaces element from tree and update extra values 1581 _abort_empty_line($self, $current) 1582 } 1583 1584 } elsif ($current->{'type'} eq 'menu_comment' 1585 or $current->{'type'} eq 'menu_entry_description') { 1586 my $context = pop @{$self->{'context_stack'}}; 1587 if ($context ne 'preformatted') { 1588 $self->_bug_message("context $context instead of preformatted", 1589 $line_nr, $current); 1590 } 1591 # close empty menu_comment 1592 if ($current->{'type'} eq 'menu_comment' 1593 and !@{$current->{'contents'}}) { 1594 pop @{$current->{'parent'}->{'contents'}}; 1595 } 1596 } elsif ($current->{'type'} eq 'line_arg' 1597 or $current->{'type'} eq 'block_line_arg') { 1598 my $context = pop @{$self->{'context_stack'}}; 1599 if ($context ne 'line' and $context ne 'def') { 1600 $self->_bug_message("context $context instead of line or def", 1601 $line_nr, $current); 1602 die; 1603 } 1604 } 1605 $current = $current->{'parent'}; 1606 } else { # Should never go here. 1607 $current = $current->{'parent'} if ($current->{'parent'}); 1608 $self->_bug_message("No type nor cmdname when closing", 1609 $line_nr, $current); 1610 } 1611 return $current; 1612} 1613 1614# a closed_command arg means closing until that command is found. 1615# no command arg means closing until the root or a root_command 1616# is found. 1617sub _close_commands($$$;$$) 1618{ 1619 my ($self, $current, $line_nr, $closed_command, 1620 $interrupting_command) = @_; 1621 1622 $current = _end_paragraph($self, $current, $line_nr, $closed_command, 1623 $interrupting_command); 1624 $current = _end_preformatted($self, $current, $line_nr, $closed_command, 1625 $interrupting_command); 1626 1627 # stop if the command is found 1628 while (!($closed_command and $current->{'cmdname'} 1629 and $current->{'cmdname'} eq $closed_command) 1630 # stop if at the root 1631 and $current->{'parent'} 1632 # stop if in a root command 1633 # or in a context_brace_commands and searching for a specific 1634 # end block command (with $closed_command set). 1635 # This second condition means that a footnote is not closed when 1636 # looking for the end of a block command, but is closed when 1637 # completly closing the stack. 1638 and !($current->{'cmdname'} 1639 and ($root_commands{$current->{'cmdname'}} 1640 or ($closed_command and $current->{'parent'}->{'cmdname'} 1641 and $context_brace_commands{$current->{'parent'}->{'cmdname'}})))){ 1642 _close_command_cleanup($self, $current); 1643 $current = _close_current($self, $current, $line_nr, $closed_command, 1644 $interrupting_command); 1645 } 1646 1647 my $closed_element; 1648 if ($closed_command and $current->{'cmdname'} 1649 and $current->{'cmdname'} eq $closed_command) { 1650 if ($preformatted_commands{$current->{'cmdname'}}) { 1651 my $context = pop @{$self->{'context_stack'}}; 1652 if ($context ne 'preformatted') { 1653 $self->_bug_message("context $context instead of preformatted for $closed_command", 1654 $line_nr, $current); 1655 } 1656 } elsif ($format_raw_commands{$current->{'cmdname'}}) { 1657 my $context = pop @{$self->{'context_stack'}}; 1658 if ($context ne 'rawpreformatted') { 1659 $self->_bug_message("context $context instead of rawpreformatted for $closed_command", 1660 $line_nr, $current); 1661 } 1662 } elsif ($menu_commands{$current->{'cmdname'}}) { 1663 my $context = pop @{$self->{'context_stack'}}; 1664 # may be in menu, but context is preformatted if in a preformatted too. 1665 if ($context ne 'menu' and $context ne 'preformatted') { 1666 $self->_bug_message("context $context instead of preformatted or menu for $closed_command", 1667 $line_nr, $current); 1668 } 1669 } elsif ($math_commands{$current->{'cmdname'}}) { 1670 my $context = pop @{$self->{'context_stack'}}; 1671 if ($context ne 'math') { 1672 $self->_bug_message("context $context instead of math for $closed_command", 1673 $line_nr, $current); 1674 } 1675 } 1676 pop @{$self->{'regions_stack'}} 1677 if ($region_commands{$current->{'cmdname'}}); 1678 $closed_element = $current; 1679 #$self->_close_command_cleanup($current); 1680 $current = $current->{'parent'}; 1681 } elsif ($closed_command) { 1682 $self->line_error(sprintf(__("unmatched `%c%s'"), 1683 ord('@'), "end $closed_command"), $line_nr); 1684 } 1685 return ($closed_element, $current); 1686} 1687 1688# begin paragraph if needed. If not try to merge with the previous 1689# content if it is also some text. 1690# NOTE - this sub has an XS override 1691sub _merge_text { 1692 my ($self, $current, $text) = @_; 1693 1694 my $paragraph; 1695 1696 my $no_merge_with_following_text = 0; 1697 if ($text =~ /\S/) { 1698 my $leading_spaces; 1699 if ($text =~ /^(\s+)/) { 1700 $leading_spaces = $1; 1701 } 1702 if ($current->{'contents'} and @{$current->{'contents'}} 1703 and $current->{'contents'}->[-1]->{'type'} 1704 and ($current->{'contents'}->[-1]->{'type'} eq 'empty_line_after_command' 1705 or $current->{'contents'}->[-1]->{'type'} eq 'empty_spaces_after_command' 1706 or $current->{'contents'}->[-1]->{'type'} eq 'empty_spaces_before_argument' 1707 or $current->{'contents'}->[-1]->{'type'} eq 'empty_spaces_after_close_brace')) { 1708 $no_merge_with_following_text = 1; 1709 } 1710 if (_abort_empty_line($self, $current, $leading_spaces)) { 1711 $text =~ s/^(\s+)//; 1712 } 1713 1714 $paragraph = _begin_paragraph($self, $current); 1715 $current = $paragraph if ($paragraph); 1716 } 1717 1718 if (!defined($current->{'contents'})) { 1719 $self->_bug_message("No contents in _merge_text", 1720 undef, $current); 1721 die; 1722 } 1723 1724 if (!$no_merge_with_following_text 1725 and @{$current->{'contents'}} 1726 and exists($current->{'contents'}->[-1]->{'text'}) 1727 and $current->{'contents'}->[-1]->{'text'} !~ /\n/) { 1728 $current->{'contents'}->[-1]->{'text'} .= $text; 1729 print STDERR "MERGED TEXT: $text|||\n" if ($self->{'DEBUG'}); 1730 } else { 1731 push @{$current->{'contents'}}, { 'text' => $text, 'parent' => $current }; 1732 print STDERR "NEW TEXT: $text|||\n" if ($self->{'DEBUG'}); 1733 } 1734 return $current; 1735} 1736 1737# return the parent if in a item_container command, itemize or enumerate 1738sub _item_container_parent($) 1739{ 1740 my $current = shift; 1741 if ((($current->{'cmdname'} and $current->{'cmdname'} eq 'item') 1742 or ($current->{'type'} and $current->{'type'} eq 'before_item')) 1743 and ($current->{'parent'} and $current->{'parent'}->{'cmdname'} 1744 and $item_container_commands{$current->{'parent'}->{'cmdname'}})) { 1745 return ($current->{'parent'}); 1746 } 1747 return undef; 1748} 1749 1750# return the parent if in a item_line command, @*table 1751sub _item_line_parent($) 1752{ 1753 my $current = shift; 1754 if ($current->{'type'} and $current->{'type'} eq 'before_item' 1755 and $current->{'parent'}) { 1756 $current = $current->{'parent'}; 1757 } 1758 return $current if ($current->{'cmdname'} 1759 and $item_line_commands{$current->{'cmdname'}}); 1760 return undef; 1761} 1762 1763# return the parent if in a multitable 1764sub _item_multitable_parent($) 1765{ 1766 my $current = shift; 1767 if (($current->{'cmdname'} and ($current->{'cmdname'} eq 'headitem' 1768 or $current->{'cmdname'} eq 'item' or $current->{'cmdname'} eq 'tab')) 1769 and $current->{'parent'} and $current->{'parent'}->{'parent'}) { 1770 $current = $current->{'parent'}->{'parent'}; 1771 } elsif ($current->{'type'} and $current->{'type'} eq 'before_item' 1772 and $current->{'parent'}) { 1773 $current = $current->{'parent'}; 1774 } 1775 return $current if ($current->{'cmdname'} 1776 and $current->{'cmdname'} eq 'multitable'); 1777 return undef; 1778} 1779 1780sub _save_line_directive 1781{ 1782 my ($self, $line_nr, $file_name) = @_; 1783 1784 my $input = $self->{'input'}->[0]; 1785 return if !$input; 1786 $input->{'line_nr'} = $line_nr if $line_nr; 1787 $input->{'name'} = $file_name if $file_name; 1788} 1789 1790# returns next text fragment, be it pending from a macro expansion or 1791# text or file 1792sub _next_text($$) 1793{ 1794 my ($self, $line_nr) = @_; 1795 1796 while (@{$self->{'input'}}) { 1797 my $input = $self->{'input'}->[0]; 1798 if (@{$input->{'pending'}}) { 1799 my $new_text = shift @{$input->{'pending'}}; 1800 if ($new_text->[1] and $new_text->[1]->{'end_macro'}) { 1801 delete $new_text->[1]->{'end_macro'}; 1802 my $top_macro = shift @{$self->{'macro_stack'}}; 1803 print STDERR "SHIFT MACRO_STACK(@{$self->{'macro_stack'}}): $top_macro->{'args'}->[0]->{'text'}\n" 1804 if ($self->{'DEBUG'}); 1805 } 1806 return ($new_text->[0], $new_text->[1]); 1807 } elsif ($input->{'fh'}) { 1808 my $input_error = 0; 1809 local $SIG{__WARN__} = sub { 1810 my $message = shift; 1811 print STDERR "$input->{'name'}" . ":" 1812 . ($input->{'line_nr'} + 1) . ": input error: $message"; 1813 $input_error = 1; 1814 }; 1815 my $fh = $input->{'fh'}; 1816 my $line = <$fh>; 1817 if (defined($line)) { 1818 if ($input_error) { 1819 # possible encoding error. attempt to recover by stripping out 1820 # non-ASCII bytes. there may not be that many in the file. 1821 Encode::_utf8_off($line); 1822 $line =~ s/[\x80-\xFF]//g; 1823 } 1824 # add an end of line if there is none at the end of file 1825 if (eof($fh) and $line !~ /\n/) { 1826 $line .= "\n"; 1827 } 1828 $line =~ s/\x{7F}.*\s*//; 1829 $input->{'line_nr'}++; 1830 return ($line, {'line_nr' => $input->{'line_nr'}, 1831 'file_name' => $input->{'name'}, 1832 'macro' => ''}); 1833 } 1834 } 1835 my $previous_input = shift(@{$self->{'input'}}); 1836 # Don't close STDIN 1837 if ($previous_input->{'fh'} and $previous_input->{'name'} ne '-') { 1838 if (!close($previous_input->{'fh'})) { 1839 $self->document_warn(sprintf(__("error on closing %s: %s"), 1840 $previous_input->{'name'}, $!)); 1841 1842 } 1843 } 1844 } 1845 1846 return (undef, $line_nr); 1847} 1848 1849# collect text and line numbers until an end of line is found. 1850sub _new_line($$) 1851{ 1852 my ($self, $line_nr) = @_; 1853 1854 my $new_line = ''; 1855 1856 while (1) { 1857 my $new_text; 1858 ($new_text, $line_nr) = _next_text($self, $line_nr); 1859 if (!defined($new_text)) { 1860 $new_line = undef if ($new_line eq ''); 1861 last; 1862 } 1863 1864 $new_line .= $new_text; 1865 1866 my $chomped_text = $new_text; 1867 last if chomp($chomped_text); 1868 } 1869 return ($new_line, $line_nr); 1870} 1871 1872# $MACRO is the element in the tree defining the macro. 1873sub _expand_macro_arguments($$$$) 1874{ 1875 my ($self, $macro, $line, $line_nr) = @_; 1876 1877 my $braces_level = 1; 1878 my $arguments = [ '' ]; 1879 my $arg_nr = 0; 1880 my $args_total = scalar(@{$macro->{'args'}}) -1; 1881 my $name = $macro->{'args'}->[0]->{'text'}; 1882 1883 my $line_nr_orig = $line_nr; 1884 1885 while (1) { 1886 if ($line =~ s/([^\\{},]*)([\\{},])//) { 1887 my $separator = $2; 1888 $arguments->[-1] .= $1; 1889 if ($separator eq '\\') { 1890 if ($line =~ s/^(.)//) { 1891 my $protected_char = $1; 1892 if ($protected_char !~ /[\\{},]/) { 1893 $arguments->[-1] .= '\\'; 1894 } 1895 $arguments->[-1] .= $protected_char; 1896 1897 print STDERR "MACRO ARG: $separator: $protected_char\n" if ($self->{'DEBUG'}); 1898 } else { 1899 $arguments->[-1] .= '\\'; 1900 print STDERR "MACRO ARG: $separator\n" if ($self->{'DEBUG'}); 1901 } 1902 } elsif ($separator eq ',') { 1903 if ($braces_level == 1) { 1904 if (scalar(@$arguments) < $args_total) { 1905 push @$arguments, ''; 1906 $line =~ s/^\s*//; 1907 print STDERR "MACRO NEW ARG\n" if ($self->{'DEBUG'}); 1908 } else { 1909 # implicit quoting when there is one argument. 1910 if ($args_total != 1) { 1911 $self->line_error(sprintf(__( 1912 "macro `%s' called with too many args"), 1913 $name), $line_nr); 1914 } 1915 $arguments->[-1] .= ','; 1916 } 1917 } else { 1918 $arguments->[-1] .= ','; 1919 } 1920 } elsif ($separator eq '}') { 1921 $braces_level--; 1922 last if ($braces_level == 0); 1923 $arguments->[-1] .= $separator; 1924 } elsif ($separator eq '{') { 1925 $braces_level++; 1926 $arguments->[-1] .= $separator; 1927 } 1928 } else { 1929 print STDERR "MACRO ARG end of line\n" if ($self->{'DEBUG'}); 1930 $arguments->[-1] .= $line; 1931 1932 ($line, $line_nr) = _new_line($self, $line_nr); 1933 if (!defined($line)) { 1934 $self->line_error(sprintf(__("\@%s missing closing brace"), 1935 $name), $line_nr_orig); 1936 return ($arguments, "\n", $line_nr); 1937 } 1938 } 1939 } 1940 if ($args_total == 0 and $arguments->[0] ne '') { 1941 $self->line_error(sprintf(__( 1942 "macro `%s' declared without argument called with an argument"), 1943 $name), $line_nr); 1944 } 1945 print STDERR "END MACRO ARGS EXPANSION(".scalar(@$arguments)."): ". 1946 join("|\n", @$arguments) ."|\n" if ($self->{'DEBUG'}); 1947 return ($arguments, $line, $line_nr); 1948} 1949 1950# $MACRO is a member of $self->{'macros'}. 1951sub _expand_macro_body($$$$) { 1952 my ($self, $macro, $args, $line_nr) = @_; 1953 1954 my $macrobody = $macro->{'macrobody'}; 1955 my $args_total = scalar(@{$macro->{'element'}->{'args'}}) -1; 1956 my $args_index = $macro->{'args_index'}; 1957 1958 my $i; 1959 for ($i=0; $i<=$args_total; $i++) { 1960 $args->[$i] = "" unless (defined($args->[$i])); 1961 } 1962 1963 my $result = ''; 1964 while ($macrobody ne '') { 1965 if ($macrobody =~ s/^([^\\]*)\\//o) { 1966 $result .= $1; 1967 if ($macrobody =~ s/^\\//) { 1968 $result .= '\\'; 1969 } elsif ($macrobody =~ s/^([^\\]*)\\//) { 1970 my $arg = $1; 1971 if (defined($args_index->{$arg})) { 1972 $result .= $args->[$args_index->{$arg}]; 1973 } else { 1974 $self->line_error(sprintf(__( 1975 "\\ in \@%s expansion followed `%s' instead of parameter name or \\"), 1976 $macro->{'element'}->{'args'}->[0]->{'text'}, $arg), $line_nr); 1977 $result .= '\\' . $arg; 1978 } 1979 } 1980 next; 1981 } 1982 $result .= $macrobody; 1983 last; 1984 } 1985 return $result; 1986} 1987 1988# each time a new line appeared, a container is opened to hold the text 1989# consisting only of spaces. This container is removed here, typically 1990# this is called when non-space happens on a line. 1991# NOTE - this sub has an XS override 1992sub _abort_empty_line { 1993 my ($self, $current, $additional_spaces) = @_; 1994 1995 $additional_spaces = '' if (!defined($additional_spaces)); 1996 if ($current->{'contents'} and @{$current->{'contents'}} 1997 and $current->{'contents'}->[-1]->{'type'} 1998 and ($current->{'contents'}->[-1]->{'type'} eq 'empty_line' 1999 or $current->{'contents'}->[-1]->{'type'} eq 'empty_line_after_command' 2000 or $current->{'contents'}->[-1]->{'type'} eq 'empty_spaces_before_argument' 2001 or $current->{'contents'}->[-1]->{'type'} eq 'empty_spaces_after_close_brace')) { 2002 2003 my $spaces_element = $current->{'contents'}->[-1]; 2004 2005 my $owning_element; 2006 if ($spaces_element->{'extra'} 2007 and $spaces_element->{'extra'}->{'command'}) { 2008 $owning_element = $spaces_element->{'extra'}->{'command'}; 2009 } 2010 2011 print STDERR "ABORT EMPTY " 2012 .$spaces_element->{'type'} 2013 ." additional text |$additional_spaces|," 2014 ." current |$spaces_element->{'text'}|\n" 2015 if ($self->{'DEBUG'}); 2016 2017 $spaces_element->{'text'} .= $additional_spaces; 2018 # remove empty 'empty*before'. 2019 if ($spaces_element->{'text'} eq '') { 2020 pop @{$current->{'contents'}}; 2021 2022 } elsif ($spaces_element->{'type'} eq 'empty_line') { 2023 # exactly the same condition as to begin a paragraph 2024 if ((!$current->{'type'} or $type_with_paragraph{$current->{'type'}}) 2025 and !$no_paragraph_contexts{$self->{'context_stack'}->[-1]}) { 2026 $spaces_element->{'type'} = 'empty_spaces_before_paragraph'; 2027 } else { 2028 delete $spaces_element->{'type'}; 2029 } 2030 } elsif ($spaces_element->{'type'} eq 'empty_line_after_command' 2031 or $spaces_element->{'type'} eq 'empty_spaces_before_argument') { 2032 if ($owning_element) { 2033 # Remove element from main tree. It will still be referenced in 2034 # the 'extra' hash as 'spaces_before_argument'. 2035 pop @{$current->{'contents'}}; 2036 2037 $owning_element->{'extra'}->{'spaces_before_argument'} 2038 = $spaces_element->{'text'}; 2039 } else { 2040 $spaces_element->{'type'} = 'empty_spaces_after_command'; 2041 } 2042 } 2043 2044 return 1; 2045 } 2046 return 0; 2047} 2048 2049# isolate last space in a command to help expansion disregard unuseful spaces. 2050sub _isolate_last_space 2051{ 2052 my ($self, $current) = @_; 2053 2054 return if (!$current->{'contents'} or !@{$current->{'contents'}}); 2055 2056 # Store a final comment command in the 'extra' hash. 2057 if (scalar(@{$current->{'contents'}}) >= 1 2058 and $current->{'contents'}->[-1]->{'cmdname'} 2059 and ($current->{'contents'}->[-1]->{'cmdname'} eq 'c' 2060 or $current->{'contents'}->[-1]->{'cmdname'} eq 'comment')) { 2061 $current->{'extra'}->{'comment_at_end'} = pop @{$current->{'contents'}}; 2062 # TODO: @c should probably not be allowed inside most brace commands 2063 # as this would be difficult to implement properly in TeX. 2064 } 2065 2066 return if !@{$current->{'contents'}} 2067 or !defined($current->{'contents'}->[-1]->{'text'}) 2068 or ($current->{'contents'}->[-1]->{'type'} 2069 and (!$current->{'type'} 2070 or $current->{'type'} ne 'line_arg')) 2071 or $current->{'contents'}->[-1]->{'text'} !~ /\s+$/; 2072 2073 if ($current->{'type'} and $current->{'type'} eq 'menu_entry_node') { 2074 if ($current->{'contents'}->[-1]->{'text'} !~ /\S/) { 2075 $current->{'contents'}->[-1]->{'type'} = 'space_at_end_menu_node'; 2076 } else { 2077 $current->{'contents'}->[-1]->{'text'} =~ s/(\s+)$//; 2078 my $new_spaces = { 'text' => $1, 'parent' => $current, 2079 'type' => 'space_at_end_menu_node' }; 2080 push @{$current->{'contents'}}, $new_spaces; 2081 } 2082 } else { 2083 # Store final spaces in 'spaces_after_argument'. 2084 if ($current->{'contents'}->[-1]->{'text'} !~ /\S/) { 2085 my $end_spaces = $current->{'contents'}->[-1]->{'text'}; 2086 pop @{$current->{'contents'}}; 2087 $current->{'extra'}->{'spaces_after_argument'} = $end_spaces; 2088 } else { 2089 $current->{'contents'}->[-1]->{'text'} =~ s/(\s+)$//; 2090 $current->{'extra'}->{'spaces_after_argument'} = $1; 2091 } 2092 } 2093} 2094 2095# $NODE->{'contents'} is the Texinfo for the specification of a node. 2096# Returned object is a hash with two fields: 2097# 2098# manual_content - Texinfo tree for a manual name extracted from the 2099# node specification. 2100# node_content - Texinfo tree for the node name on its own 2101# 2102# retrieve a leading manual name in parentheses, if there is one. 2103sub _parse_node_manual($) 2104{ 2105 my $node = shift; 2106 return Texinfo::Common::parse_node_manual ($node); 2107} 2108 2109sub _parse_float_type($) 2110{ 2111 my $current = shift; 2112 if ($current->{'args'} and @{$current->{'args'}}) { 2113 if (@{$current->{'args'}->[0]->{'contents'}}) { 2114 my $normalized 2115 = Texinfo::Convert::Texinfo::convert( 2116 {'contents' => $current->{'args'}->[0]->{'contents'}}); 2117 $current->{'extra'}->{'type'}->{'content'} = 2118 $current->{'args'}->[0]->{'contents'}; 2119 $current->{'extra'}->{'type'}->{'normalized'} = $normalized; 2120 return 1; 2121 } 2122 } 2123 $current->{'extra'}->{'type'}->{'normalized'} = ''; 2124 return 0; 2125} 2126 2127# split non-space text elements into strings without [ ] ( ) , and single 2128# character strings with one of them 2129sub _split_delimiters 2130{ 2131 my ($self, $root) = @_; 2132 2133 if (defined $root->{'type'} # 'spaces' for spaces 2134 or !defined $root->{'text'}) { 2135 return $root; 2136 } else { 2137 my @elements; 2138 my $type; 2139 my $chars = quotemeta '[](),'; 2140 my $text = $root->{'text'}; 2141 while (1) { 2142 if ($text =~ s/^([^$chars]+)//) { 2143 push @elements, {'text' => $1, 'parent' => $root->{'parent'}}; 2144 } elsif ($text =~ s/^([$chars])//) { 2145 push @elements, {'text' => $1, 'type' => 'delimiter', 2146 'parent' => $root->{'parent'}}; 2147 } else { 2148 last; 2149 } 2150 } 2151 return @elements; 2152 } 2153} 2154 2155# split text elements into whitespace and non-whitespace 2156sub _split_def_args 2157{ 2158 my ($self, $root) = @_; 2159 2160 if ($root->{'type'} and $root->{'type'} eq 'spaces_inserted') { 2161 return $root; 2162 } elsif (defined $root->{'text'}) { 2163 my @elements; 2164 my $type; 2165 my @split_text = split /(?<=\s)(?=\S)|(?<=\S)(?=\s)/, $root->{'text'}; 2166 if ($split_text[0] =~ /^\s*$/) { 2167 $type = 'spaces'; 2168 } 2169 for my $t (@split_text) { 2170 my $e = {'text' => $t }; 2171 if ($type) { 2172 $e->{'type'} = $type; 2173 $type = undef; 2174 } else { 2175 $type = 'spaces'; 2176 } 2177 $e->{'parent'} = $root->{'parent'}; 2178 push @elements, $e; 2179 } 2180 return @elements; 2181 } elsif ($root->{'type'} and $root->{'type'} eq 'bracketed') { 2182 _isolate_last_space($self, $root); 2183 $root->{'type'} = 'bracketed_def_content'; 2184 } 2185 return $root; 2186} 2187 2188# definition line parsing 2189sub _parse_def($$$) 2190{ 2191 my ($self, $command, $current) = @_; 2192 2193 my $contents = $current->{'contents'}; 2194 my $empty_spaces_after_command; 2195 2196 my @new_contents; 2197 my @contents = @$contents; 2198 if ($contents[0] and $contents[0]->{'type'} 2199 and ($contents[0]->{'type'} eq 'empty_spaces_after_command' 2200 or $contents[0]->{'type'} eq 'empty_line_after_command')) { 2201 $empty_spaces_after_command = shift @contents; 2202 } 2203 2204 if ($def_aliases{$command}) { 2205 my $real_command = $def_aliases{$command}; 2206 my $prepended = $def_map{$command}->{$real_command}; 2207 2208 2209 my $bracketed = { 'type' => 'bracketed_inserted', 2210 'parent' => $current }; 2211 my $content = { 'text' => $prepended, 'parent' => $bracketed }; 2212 if ($self->{'documentlanguage'}) { 2213 $content->{'type'} = 'untranslated'; 2214 $content->{'extra'}->{'documentlanguage'} = $self->{'documentlanguage'}; 2215 } 2216 @{$bracketed->{'contents'}} = ($content); 2217 2218 unshift @contents, $bracketed, 2219 { 'text' => ' ', 'type' => 'spaces_inserted', 2220 'parent' => $current, 2221 }; 2222 2223 $command = $def_aliases{$command}; 2224 } 2225 @contents = map (_split_def_args($self, $_), @contents ); 2226 @new_contents = @contents; 2227 2228 $current->{'contents'} = \@new_contents; 2229 2230 my @result; 2231 my @args = @{$def_map{$command}}; 2232 my $arg_type; 2233 2234 $arg_type = pop @args if ($args[-1] eq 'arg' or $args[-1] eq 'argtype'); 2235 # If $arg_type is not set (for @def* commands that are not documented 2236 # to take args), everything happens as if arg_type was set to 'arg'. 2237 2238 # Fill in everything up to the args, collecting adjacent non-whitespace 2239 # elements into a single element, e.g 'a@i{b}c'. 2240 my $argument_content = []; 2241 my $arg = shift (@args); 2242 2243 my $i = 0; # the offset in @new_contents of $token 2244 while (@contents) { 2245 my $token = $contents[0]; 2246 # finish previous item 2247 if ( $token->{'type'} 2248 and ($token->{'type'} eq 'spaces' 2249 or $token->{'type'} eq 'spaces_inserted' 2250 or $token->{'type'} eq 'bracketed_def_content' 2251 or $token->{'type'} eq 'bracketed_inserted' 2252 or $token->{'type'} eq 'delimiter')) { 2253 # we create a {'contents' =>} only if there is more than one 2254 # content gathered. 2255 if (scalar(@$argument_content)) { 2256 if (scalar(@$argument_content) > 1) { 2257 my $e = {'contents' => $argument_content, 2258 'type' => 'def_aggregate', 2259 'parent' => $current }; 2260 push @result, [$arg, $e]; 2261 # Replace in the main tree. 2262 splice @new_contents, 2263 $i - scalar(@$argument_content), 2264 scalar(@$argument_content), 2265 $e; 2266 for my $e2 (@$argument_content) { 2267 $e2->{'parent'} = $e; 2268 } 2269 $i -= scalar(@$argument_content) - 1; 2270 } elsif (scalar(@$argument_content) == 1) { 2271 push @result, [$arg, $argument_content->[0]]; 2272 } 2273 $argument_content = []; 2274 if ($token->{'type'} eq 'spaces' 2275 or $token->{'type'} eq 'spaces_inserted') { 2276 $arg = shift (@args); 2277 } 2278 } 2279 } 2280 2281 if ($token->{'type'} and ($token->{'type'} eq 'bracketed_def_content' 2282 or $token->{'type'} eq 'bracketed_inserted')) { 2283 push @result, [$arg, $token]; 2284 shift @contents; 2285 $arg = shift (@args); 2286 } elsif ($token->{'type'} 2287 and ($token->{'type'} eq 'spaces' 2288 or $token->{'type'} eq 'spaces_inserted')) { 2289 if ($token->{'text'}) { 2290 if ($token->{'text'} =~ /\n$/) { 2291 $token->{'type'} = 'spaces_at_end'; 2292 } 2293 push @result, ['spaces', $token]; 2294 shift @contents; 2295 } else { 2296 $i++; 2297 last; 2298 } 2299 } elsif ($token->{'type'} and $token->{'type'} eq 'delimiter') { 2300 push @result, ['delimiter', shift @contents]; 2301 } else { 2302 my $text_or_cmd = shift @contents; 2303 push @$argument_content, $text_or_cmd; 2304 } 2305 $i++; 2306 last if (! defined($arg)); 2307 } 2308 if (scalar(@$argument_content) > 1) { 2309 my $e = {'contents' => $argument_content, 2310 'type' => 'def_aggregate' }; 2311 push @result, [$arg, $e]; 2312 # Replace in the main tree. 2313 splice @new_contents, $i - scalar(@$argument_content), 2314 scalar(@$argument_content), $e; 2315 } elsif (scalar(@$argument_content) == 1) { 2316 push @result, [$arg, $argument_content->[0]]; 2317 } 2318 2319 if (scalar(@contents) > 0) { 2320 splice @new_contents, -scalar(@contents); 2321 } 2322 unshift @new_contents, $empty_spaces_after_command 2323 if $empty_spaces_after_command; 2324 2325 @contents = map (_split_delimiters($self, $_), @contents ); 2326 @new_contents = (@new_contents, @contents); 2327 2328 # Create the part of the def_args array for any arguments. 2329 my @args_results; 2330 while (@contents) { 2331 my $spaces; 2332 my $next_token = shift @contents; 2333 if ($next_token->{'type'} and $next_token->{'type'} eq 'spaces') { 2334 $spaces = $next_token; 2335 $next_token = shift @contents; 2336 } 2337 if (defined($spaces)) { 2338 if ($spaces->{'text'} =~ /\n$/) { 2339 $spaces->{'type'} = 'spaces_at_end'; 2340 } 2341 push @args_results, ['spaces', $spaces] 2342 } 2343 last if (!defined($next_token)); 2344 if ($next_token->{'type'} and $next_token->{'type'} eq 'delimiter') { 2345 push @args_results, ['delimiter', $next_token]; 2346 } else { 2347 push @args_results, ['arg', $next_token]; 2348 } 2349 } 2350 2351 # If a command like @deftypefn, mark the type arguments 2352 if ($arg_type and $arg_type eq 'argtype') { 2353 my $next_is_type = 1; 2354 foreach my $arg(@args_results) { 2355 if ($arg->[0] eq 'spaces') { 2356 } elsif ($arg->[0] eq 'delimiter') { 2357 $next_is_type = 1; 2358 } elsif ($arg->[1]->{'cmdname'} and $arg->[1]->{'cmdname'} ne 'code') { 2359 $next_is_type = 1; 2360 } elsif ($next_is_type) { 2361 $arg->[0] = 'typearg'; 2362 $next_is_type = 0; 2363 } else { 2364 $next_is_type = 1; 2365 } 2366 } 2367 } 2368 2369 for my $pair (@result, @args_results) { 2370 $pair->[1]->{'extra'}->{'def_role'} = $pair->[0]; 2371 } 2372 2373 return [@result, @args_results]; 2374} 2375 2376# register a label, that is something that may be the target of a reference 2377# and must be unique in the document. Corresponds to @node, @anchor and 2378# @float second arg. 2379sub _register_label($$$) 2380{ 2381 my ($self, $current, $label) = @_; 2382 2383 push @{$self->{'targets'}}, $current; 2384 if ($label->{'node_content'}) { 2385 $current->{'extra'}->{'node_content'} = $label->{'node_content'}; 2386 } 2387} 2388 2389# store an index entry. 2390# $current is the command element. 2391# $content holds the actual content. 2392# for index entries and v|ftable items, it is the index entry content, 2393# for def, it is the parsed arguments, based on the definition line 2394# arguments. 2395sub _enter_index_entry($$$$$$$) 2396{ 2397 my ($self, $command_container, $command, $current, $content, 2398 $content_normalized, $line_nr) = @_; 2399 2400 $content_normalized = $content if (!defined($content_normalized)); 2401 2402 my $index_name = $self->{'command_index'}->{$command_container}; 2403 my $index = $self->{'index_names'}->{$index_name}; 2404 2405 my $number = (defined($index->{'index_entries'}) 2406 ? (scalar(@{$index->{'index_entries'}}) + 1) 2407 : 1); 2408 my $index_entry = { 'index_name' => $index_name, 2409 'index_at_command' => $command, 2410 'index_type_command' => $command_container, 2411 'content' => $content, 2412 'content_normalized' => $content_normalized, 2413 'command' => $current, 2414 'number' => $number, 2415 }; 2416 if (defined $current->{'extra'}->{'sortas'}) { 2417 $index_entry->{'sortas'} = $current->{'extra'}->{'sortas'}; 2418 } 2419 if (@{$self->{'regions_stack'}}) { 2420 $index_entry->{'region'} = $self->{'regions_stack'}->[-1]; 2421 } elsif ($self->{'current_node'}) { 2422 $index_entry->{'node'} = $self->{'current_node'}; 2423 } elsif (!$self->{'current_section'}) { 2424 $self->line_warn(sprintf(__("entry for index `%s' outside of any node"), 2425 $index_name), $line_nr); 2426 } 2427 2428 # Skip these as these entries do not refer to the place in the document where 2429 # the index commands occurred. 2430 if (!defined $current->{'extra'}->{'seeentry'} 2431 and !defined $current->{'extra'}->{'seealso'}) { 2432 push @{$index->{'index_entries'}}, $index_entry; 2433 } 2434 2435 $current->{'extra'}->{'index_entry'} = $index_entry; 2436} 2437 2438# Used for file names and index sort strings to allow including the special 2439# Texinfo characters. 2440sub _convert_to_text { 2441 my $e = shift; 2442 2443 my ($text, $superfluous_arg) = ('', 0); 2444 2445 for my $c (@{$e->{'contents'}}) { 2446 # Allow @@, @{ and @} to give a way for @, { and } to appear in 2447 # filenames (although it's not a good idea to use these characters 2448 # in filenames). 2449 if (defined $c->{'text'}) { 2450 $text .= $c->{'text'}; 2451 } elsif ($c->{'cmdname'} 2452 and ($c->{'cmdname'} eq '@' 2453 or $c->{'cmdname'} eq 'atchar')) { 2454 $text .= '@'; 2455 } elsif ($c->{'cmdname'} 2456 and ($c->{'cmdname'} eq '{' 2457 or $c->{'cmdname'} eq 'lbracechar')) { 2458 $text .= '{'; 2459 } elsif ($c->{'cmdname'} 2460 and ($c->{'cmdname'} eq '}' 2461 or $c->{'cmdname'} eq 'rbracechar')) { 2462 $text .= '}'; 2463 } else { 2464 $superfluous_arg = 1; 2465 } 2466 } 2467 return ($text, $superfluous_arg); 2468} 2469 2470# close constructs and do stuff at end of line (or end of the document) 2471sub _end_line($$$); 2472sub _end_line($$$) 2473{ 2474 my ($self, $current, $line_nr) = @_; 2475 2476 my $current_old = $current; 2477 2478 my $included_file = 0; 2479 2480 # a line consisting only of spaces. 2481 if ($current->{'contents'} and @{$current->{'contents'}} 2482 and $current->{'contents'}->[-1]->{'type'} 2483 and $current->{'contents'}->[-1]->{'type'} eq 'empty_line') { 2484 print STDERR "END EMPTY LINE\n" if ($self->{'DEBUG'}); 2485 if ($current->{'type'} and $current->{'type'} eq 'paragraph') { 2486 my $empty_line = pop @{$current->{'contents'}}; 2487 $current = _end_paragraph($self, $current, $line_nr); 2488 push @{$current->{'contents'}}, $empty_line; 2489 $empty_line->{'parent'} = $current; 2490 } elsif ($current->{'type'} 2491 and $current->{'type'} eq 'preformatted' 2492 and $current->{'parent'}->{'type'} 2493 and $current->{'parent'}->{'type'} eq 'menu_entry_description') { 2494 my $empty_line = pop @{$current->{'contents'}}; 2495 if ($current->{'type'} eq 'preformatted') { 2496 my $empty_preformatted = (!@{$current->{'contents'}}); 2497 $current = $current->{'parent'}; 2498 pop @{$current->{'contents'}} if ($empty_preformatted); 2499 } 2500 my $context = pop @{$self->{'context_stack'}}; 2501 if ($context ne 'preformatted') { 2502 $self->_bug_message("context $context instead of preformatted in empty line after menu_entry_description", 2503 $line_nr, $current); 2504 } 2505 2506 # first parent is menu_entry 2507 $current = $current->{'parent'}->{'parent'}; 2508 2509 push @{$current->{'contents'}}, { 'type' => 'menu_comment', 2510 'parent' => $current, 2511 'contents' => [] }; 2512 $current = $current->{'contents'}->[-1]; 2513 push @{$current->{'contents'}}, { 'type' => 'preformatted', 2514 'parent' => $current, 2515 'contents' => [] }; 2516 $current = $current->{'contents'}->[-1]; 2517 push @{$current->{'contents'}}, { 'type' => 'after_description_line', 2518 'text' => $empty_line->{'text'}, 2519 'parent' => $current }; 2520 push @{$self->{'context_stack'}}, 'preformatted'; 2521 print STDERR "MENU: END DESCRIPTION, OPEN COMMENT\n" if ($self->{'DEBUG'}); 2522 } elsif (!$no_paragraph_contexts{$self->{'context_stack'}->[-1]}) { 2523 $current = _end_paragraph($self, $current, $line_nr); 2524 } 2525 2526 # end of a menu line. 2527 } elsif ($current->{'type'} 2528 and ($current->{'type'} eq 'menu_entry_name' 2529 or $current->{'type'} eq 'menu_entry_node')) { 2530 my $empty_menu_entry_node = 0; 2531 my $end_comment; 2532 if ($current->{'type'} eq 'menu_entry_node') { 2533 if (@{$current->{'contents'}} 2534 and $current->{'contents'}->[-1]->{'cmdname'} 2535 and ($current->{'contents'}->[-1]->{'cmdname'} eq 'c' 2536 or $current->{'contents'}->[-1]->{'cmdname'} eq 'comment')) { 2537 $end_comment = pop @{$current->{'contents'}}; 2538 } 2539 if (!@{$current->{'contents'}} 2540 # empty if only the end of line or spaces 2541 or (@{$current->{'contents'}} == 1 2542 and defined($current->{'contents'}->[-1]->{'text'}) 2543 and $current->{'contents'}->[-1]->{'text'} !~ /\S/)) { 2544 $empty_menu_entry_node = 1; 2545 push @{$current->{'contents'}}, $end_comment if ($end_comment); 2546 } 2547 } 2548 # we abort the menu entry if there is no node name 2549 if ($empty_menu_entry_node 2550 or $current->{'type'} eq 'menu_entry_name') { 2551 my $description_or_menu_comment; 2552 print STDERR "FINALLY NOT MENU ENTRY\n" if ($self->{'DEBUG'}); 2553 my $menu = $current->{'parent'}->{'parent'}; 2554 my $menu_entry = pop @{$menu->{'contents'}}; 2555 if (@{$menu->{'contents'}} and $menu->{'contents'}->[-1]->{'type'} 2556 and $menu->{'contents'}->[-1]->{'type'} eq 'menu_entry') { 2557 my $entry = $menu->{'contents'}->[-1]; 2558 my $description; 2559 foreach my $entry_element (reverse(@{$entry->{'args'}})) { 2560 if ($entry_element->{'type'} eq 'menu_entry_description') { 2561 $description = $entry_element; 2562 last; 2563 } 2564 } 2565 if ($description) { 2566 $description_or_menu_comment = $description; 2567 } else { 2568 # Normally this cannot happen 2569 $self->_bug_message("No description in menu_entry", 2570 $line_nr, $current); 2571 push @{$entry->{'args'}}, {'type' => 'menu_entry_description', 2572 'parent' => $entry, 2573 'contents' => [] }; 2574 $description_or_menu_comment = $entry->{'args'}->[-1]; 2575 } 2576 } elsif (@{$menu->{'contents'}} and $menu->{'contents'}->[-1]->{'type'} 2577 and $menu->{'contents'}->[-1]->{'type'} eq 'menu_comment') { 2578 $description_or_menu_comment = $menu->{'contents'}->[-1]; 2579 } 2580 if ($description_or_menu_comment) { 2581 $current = $description_or_menu_comment; 2582 if ($current->{'contents'}->[-1] and $current->{'contents'}->[-1]->{'type'} 2583 and $current->{'contents'}->[-1]->{'type'} eq 'preformatted') { 2584 $current = $current->{'contents'}->[-1]; 2585 } else { 2586 # this should not happen 2587 $self->_bug_message("description or menu comment not in preformatted", 2588 $line_nr, $current); 2589 push @{$current->{'contents'}}, {'type' => 'preformatted', 2590 'parent' => $current, 2591 'contents' => [] }; 2592 $current = $current->{'contents'}->[-1]; 2593 } 2594 push @{$self->{'context_stack'}}, 'preformatted'; 2595 } else { 2596 push @{$menu->{'contents'}}, {'type' => 'menu_comment', 2597 'parent' => $menu, 2598 'contents' => [] }; 2599 $current = $menu->{'contents'}->[-1]; 2600 push @{$current->{'contents'}}, {'type' => 'preformatted', 2601 'parent' => $current, 2602 'contents' => [] }; 2603 $current = $current->{'contents'}->[-1]; 2604 push @{$self->{'context_stack'}}, 'preformatted'; 2605 print STDERR "THEN MENU_COMMENT OPEN\n" if ($self->{'DEBUG'}); 2606 } 2607 while (@{$menu_entry->{'args'}}) { 2608 my $arg = shift @{$menu_entry->{'args'}}; 2609 if (defined($arg->{'text'})) { 2610 $current = _merge_text($self, $current, $arg->{'text'}); 2611 } else { 2612 while (@{$arg->{'contents'}}) { 2613 my $content = shift @{$arg->{'contents'}}; 2614 if (defined($content->{'text'})) { 2615 $current = _merge_text($self, $current, 2616 $content->{'text'}); 2617 $content = undef; 2618 } else { 2619 $content->{'parent'} = $current; 2620 push @{$current->{'contents'}}, $content; 2621 } 2622 } 2623 } 2624 $arg = undef; 2625 } 2626 # MENU_COMMENT open 2627 $menu_entry = undef; 2628 } else { 2629 print STDERR "MENU ENTRY END LINE\n" if ($self->{'DEBUG'}); 2630 $current = $current->{'parent'}; 2631 $current = _enter_menu_entry_node($self, $current, $line_nr); 2632 if (defined($end_comment)) { 2633 $end_comment->{'parent'} = $current; 2634 push @{$current->{'contents'}}, $end_comment; 2635 } 2636 } 2637 # def line 2638 } elsif ($current->{'parent'} 2639 and $current->{'parent'}->{'type'} 2640 and $current->{'parent'}->{'type'} eq 'def_line') { 2641 my $def_context = pop @{$self->{'context_stack'}}; 2642 if ($def_context ne 'def') { 2643 $self->_bug_message("context $def_context instead of def", 2644 $line_nr, $current); 2645 die; 2646 } 2647 my $def_command = $current->{'parent'}->{'extra'}->{'def_command'}; 2648 my $arguments = _parse_def($self, $def_command, $current); 2649 if (scalar(@$arguments)) { 2650 #$current->{'parent'}->{'extra'}->{'def_args'} = $arguments; 2651 my $def_parsed_hash; 2652 foreach my $arg (@$arguments) { 2653 die if (!defined($arg->[0])); 2654 last if ($arg->[0] eq 'arg' or $arg->[0] eq 'typearg' 2655 or $arg->[0] eq 'delimiter'); 2656 next if ($arg->[0] eq 'spaces'); 2657 $def_parsed_hash->{$arg->[0]} = $arg->[1]; 2658 } 2659 $current->{'parent'}->{'extra'}->{'def_parsed_hash'} = $def_parsed_hash; 2660 # do an standard index entry tree 2661 my $index_entry; 2662 if (defined($def_parsed_hash->{'name'})) { 2663 $index_entry = $def_parsed_hash->{'name'} 2664 # empty bracketed 2665 unless ($def_parsed_hash->{'name'}->{'type'} 2666 and $def_parsed_hash->{'name'}->{'type'} eq 'bracketed_def_content' 2667 and (!$def_parsed_hash->{'name'}->{'contents'} 2668 or (!scalar(@{$def_parsed_hash->{'name'}->{'contents'}})) 2669 or (scalar(@{$def_parsed_hash->{'name'}->{'contents'}}) == 1 2670 and defined($def_parsed_hash->{'name'}->{'contents'}->[0]->{'text'}) 2671 and $def_parsed_hash->{'name'}->{'contents'}->[0]->{'text'} !~ /\S/))); 2672 } 2673 if (defined($index_entry)) { 2674 my $index_contents_normalized; 2675 if ($def_parsed_hash->{'class'}) { 2676 # Delay getting the text until Texinfo::Structuring::sort_index_keys 2677 # in order to avoid using gdt. 2678 # We need to store the language as well in case there are multiple 2679 # languages in the document. 2680 if ($command_index{$def_command} eq 'fn' 2681 or $command_index{$def_command} eq 'vr' 2682 and $def_command ne 'defcv') { 2683 undef $index_entry; 2684 $current->{'parent'}->{'extra'}->{'documentlanguage'} 2685 = $self->{'documentlanguage'}; 2686 } 2687 } 2688 my $index_contents; 2689 if ($index_entry) { 2690 $index_contents_normalized = [$index_entry]; 2691 $index_contents = [$index_entry]; 2692 } 2693 2694 _enter_index_entry($self, 2695 $current->{'parent'}->{'extra'}->{'def_command'}, 2696 $current->{'parent'}->{'extra'}->{'original_def_cmdname'}, 2697 $current->{'parent'}, $index_contents, 2698 $index_contents_normalized, $line_nr); 2699 } else { 2700 $self->_command_warn($current->{'parent'}, $line_nr, 2701 __('missing name for @%s'), 2702 $current->{'parent'}->{'extra'}->{'original_def_cmdname'}); 2703 } 2704 } else { 2705 $self->_command_warn($current->{'parent'}, $line_nr, 2706 __('missing category for @%s'), 2707 $current->{'parent'}->{'extra'}->{'original_def_cmdname'}); 2708 } 2709 $current = $current->{'parent'}->{'parent'}; 2710 $current = _begin_preformatted($self, $current); 2711 2712 # other block command lines 2713 } elsif ($current->{'type'} 2714 and $current->{'type'} eq 'block_line_arg') { 2715 my $empty_text; 2716 my $context = pop @{$self->{'context_stack'}}; 2717 if ($context ne 'line') { 2718 $self->_bug_message("context $context instead of line in block_line_arg", 2719 $line_nr, $current); 2720 } 2721 # @multitable args 2722 if ($current->{'parent'}->{'cmdname'} 2723 and $current->{'parent'}->{'cmdname'} eq 'multitable') { 2724 # parse the prototypes and put them in a special arg 2725 my @prototype_row; 2726 foreach my $content (@{$current->{'contents'}}) { 2727 if ($content->{'type'} and $content->{'type'} eq 'bracketed') { 2728 push @prototype_row, { 'contents' => $content->{'contents'}, 2729 'type' => 'bracketed_multitable_prototype'}; 2730 } elsif ($content->{'text'}) { 2731 # TODO: this should be a warning or an error - all prototypes 2732 # on a @multitable line should be in braces, as documented in the 2733 # Texinfo manual. 2734 if ($content->{'text'} =~ /\S/) { 2735 foreach my $prototype (split /\s+/, $content->{'text'}) { 2736 push @prototype_row, { 'text' => $prototype, 2737 'type' => 'row_prototype' } unless ($prototype eq ''); 2738 } 2739 } 2740 } else { 2741 if (!$content->{'cmdname'} 2742 or ($content->{'cmdname'} ne 'c' 2743 and $content->{'cmdname'} ne 'comment')) { 2744 $self->_command_warn($current, $line_nr, 2745 __("unexpected argument on \@%s line: %s"), 2746 $current->{'parent'}->{'cmdname'}, 2747 Texinfo::Convert::Texinfo::convert($content)); 2748 } 2749 } 2750 } 2751 2752 my $multitable = $current->{'parent'}; 2753 $multitable->{'extra'}->{'max_columns'} = scalar(@prototype_row); 2754 if (!scalar(@prototype_row)) { 2755 $self->_command_warn($multitable, $line_nr, 2756 __("empty multitable")); 2757 } 2758 $multitable->{'extra'}->{'prototypes'} = \@prototype_row; 2759 } 2760 _isolate_last_space($self, $current); 2761 $current = $current->{'parent'}; 2762 delete $current->{'remaining_args'}; 2763 # don't consider empty argument of block @-commands as argument, 2764 # reparent them as contents 2765 if ($current->{'args'}->[0]->{'contents'}->[0] 2766 and $current->{'args'}->[0]->{'contents'}->[0]->{'type'} 2767 and $current->{'args'}->[0]->{'contents'}->[0]->{'type'} eq 'empty_line_after_command') 2768 { 2769 my $empty_text = $current->{'args'}->[0]->{'contents'}->[0]; 2770 $empty_text->{'parent'} = $current; 2771 unshift @{$current->{'contents'}}, $empty_text; 2772 delete $current->{'args'}; 2773 } 2774 2775 # @float args 2776 if ($current->{'cmdname'} and $current->{'cmdname'} eq 'float') { 2777 $current->{'line_nr'} = $line_nr; 2778 my $type = ''; 2779 my $float_label; 2780 if ($current->{'args'} and $current->{'args'}->[1]) { 2781 $float_label = _parse_node_manual($current->{'args'}->[1]); 2782 _check_internal_node($self, $float_label, $line_nr); 2783 } 2784 _register_label($self, $current, $float_label); 2785 _parse_float_type($current); 2786 $type = $current->{'extra'}->{'type'}->{'normalized'}; 2787 push @{$self->{'floats'}->{$type}}, $current; 2788 $current->{'extra'}->{'float_section'} = $self->{'current_section'} 2789 if (defined($self->{'current_section'})); 2790 } 2791 2792 if ($current->{'cmdname'} 2793 and $block_item_commands{$current->{'cmdname'}}) { 2794 if ($current->{'cmdname'} eq 'enumerate') { 2795 my $spec = '1'; 2796 if ($current->{'args'} and $current->{'args'}->[0] 2797 and $current->{'args'}->[0]->{'contents'} 2798 and @{$current->{'args'}->[0]->{'contents'}}) { 2799 if (scalar(@{$current->{'args'}->[0]->{'contents'}}) > 1) { 2800 $self->_command_error($current, $line_nr, 2801 __("superfluous argument to \@%s"), 2802 $current->{'cmdname'}); 2803 } 2804 my $arg = $current->{'args'}->[0]->{'contents'}->[0]; 2805 if (!defined($arg->{'text'}) or $arg->{'text'} !~ /^(([[:digit:]]+)|([[:alpha:]]+))$/) { 2806 $self->_command_error($current, $line_nr, 2807 __("bad argument to \@%s"), 2808 $current->{'cmdname'}); 2809 } else { 2810 $spec = $arg->{'text'}; 2811 } 2812 } 2813 $current->{'extra'}->{'enumerate_specification'} = $spec; 2814 } elsif ($item_line_commands{$current->{'cmdname'}}) { 2815 if (!$current->{'extra'} 2816 or !$current->{'extra'}->{'command_as_argument'}) { 2817 $self->_command_error($current, $line_nr, 2818 __("%s requires an argument: the formatter for %citem"), 2819 $current->{'cmdname'}, ord('@')); 2820 } elsif (!$brace_commands{$current->{'extra'}->{'command_as_argument'}->{'cmdname'}}) { 2821 $self->_command_error($current, $line_nr, 2822 __("command \@%s not accepting argument in brace should not be on \@%s line"), 2823 $current->{'extra'}->{'command_as_argument'}->{'cmdname'}, 2824 $current->{'cmdname'}); 2825 delete $current->{'extra'}->{'command_as_argument'}; 2826 } 2827 } 2828 # This code checks that the command_as_argument of the @itemize 2829 # is alone on the line, otherwise it is not a command_as_argument. 2830 if ($current->{'extra'} 2831 and $current->{'extra'}->{'command_as_argument'} 2832 and $current->{'cmdname'} eq 'itemize') { 2833 my @args = @{$current->{'args'}->[0]->{'contents'}}; 2834 while (@args) { 2835 my $arg = shift @args; 2836 last if ($arg eq $current->{'extra'}->{'command_as_argument'}); 2837 } 2838 while (@args) { 2839 my $arg = shift @args; 2840 if (!(($arg->{'cmdname'} 2841 and ($arg->{'cmdname'} eq 'c' 2842 or $arg->{'cmdname'} eq 'comment')) 2843 or (defined($arg->{'text'}) and $arg->{'text'} !~ /\S/))) { 2844 delete $current->{'extra'}->{'command_as_argument'}->{'type'}; 2845 delete $current->{'extra'}->{'command_as_argument'}; 2846 last; 2847 } 2848 } 2849 } 2850 if ($current->{'extra'} 2851 and $current->{'extra'}->{'command_as_argument'} 2852 and $accent_commands{$current->{'extra'}->{'command_as_argument'}->{'cmdname'}} 2853 and ($current->{'cmdname'} eq 'itemize' 2854 or $item_line_commands{$current->{'cmdname'}})) { 2855 $self->_command_warn($current, $line_nr, 2856 __("accent command `\@%s' not allowed as \@%s argument"), 2857 $current->{'extra'}->{'command_as_argument'}->{'cmdname'}, 2858 $current->{'cmdname'}); 2859 delete $current->{'extra'}->{'command_as_argument'}; 2860 } 2861 if ($current->{'cmdname'} eq 'itemize' 2862 and (!$current->{'args'} 2863 or !$current->{'args'}->[0] 2864 or !$current->{'args'}->[0]->{'contents'} 2865 or !@{$current->{'args'}->[0]->{'contents'}})) { 2866 my $inserted = { 'cmdname' => 'bullet', 2867 'contents' => [], 2868 'type' => 'command_as_argument_inserted', 2869 'parent' => $current }; 2870 unshift @{$current->{'args'}}, $inserted; 2871 $current->{'extra'}->{'command_as_argument'} = $inserted; 2872 } elsif ($item_line_commands{$current->{'cmdname'}} and 2873 !$current->{'extra'}->{'command_as_argument'}) { 2874 my $inserted = { 'cmdname' => 'asis', 2875 'contents' => [], 2876 'type' => 'command_as_argument_inserted', 2877 'parent' => $current }; 2878 unshift @{$current->{'args'}}, $inserted; 2879 $current->{'extra'}->{'command_as_argument'} = $inserted; 2880 } 2881 push @{$current->{'contents'}}, { 'type' => 'before_item', 2882 'contents' => [], 'parent', $current }; 2883 $current = $current->{'contents'}->[-1]; 2884 } 2885 if ($current->{'cmdname'} and $menu_commands{$current->{'cmdname'}}) { 2886 push @{$current->{'contents'}}, {'type' => 'menu_comment', 2887 'parent' => $current, 2888 'contents' => [] }; 2889 $current = $current->{'contents'}->[-1]; 2890 print STDERR "MENU_COMMENT OPEN\n" if ($self->{'DEBUG'}); 2891 push @{$self->{'context_stack'}}, 'preformatted'; 2892 } 2893 $current = _begin_preformatted($self, $current); 2894 2895 # if we are after a @end verbatim, we must restart a preformatted if needed, 2896 # since there is no @end command explicitly associated to raw commands 2897 # it won't be done elsewhere. 2898 } elsif ($current->{'contents'} 2899 and $current->{'contents'}->[-1] 2900 and $current->{'contents'}->[-1]->{'type'} 2901 and $current->{'contents'}->[-1]->{'type'} eq 'empty_line_after_command' 2902 and $current->{'contents'}->[-2] 2903 and $current->{'contents'}->[-2]->{'cmdname'} 2904 and $current->{'contents'}->[-2]->{'cmdname'} eq 'verbatim') { 2905 $current = _begin_preformatted($self, $current); 2906 # misc command line arguments 2907 # Never go here if skipline/noarg/... 2908 } elsif ($current->{'type'} 2909 and $current->{'type'} eq 'line_arg') { 2910 my $context = pop @{$self->{'context_stack'}}; 2911 if ($context ne 'line') { 2912 $self->_bug_message("context $context instead of line in line_arg", 2913 $line_nr, $current); 2914 } 2915 _isolate_last_space($self, $current); 2916 2917 # first parent is the @command, second is the parent 2918 $current = $current->{'parent'}; 2919 my $misc_cmd = $current; 2920 my $command = $current->{'cmdname'}; 2921 my $end_command; 2922 print STDERR "MISC END \@$command\n" if ($self->{'DEBUG'}); 2923 2924 if ($self->{'line_commands'}->{$command} =~ /^\d$/) { 2925 my $args = _parse_line_command_args($self, $current, $line_nr); 2926 $current->{'extra'}->{'misc_args'} = $args if (defined($args)); 2927 } elsif ($self->{'line_commands'}->{$command} eq 'text') { 2928 my ($text, $superfluous_arg) 2929 = _convert_to_text ($current->{'args'}->[0]); 2930 2931 if ($text eq '') { 2932 if (not $superfluous_arg) { 2933 $self->_command_warn($current, $line_nr, 2934 __("\@%s missing argument"), $command); 2935 } 2936 # Otherwise an error message is issued below. 2937 $current->{'extra'}->{'missing_argument'} = 1; 2938 } else { 2939 $current->{'extra'}->{'text_arg'} = $text; 2940 if ($command eq 'end') { 2941 # REMACRO 2942 my $line = $text; 2943 if ($line =~ s/^([[:alnum:]][[:alnum:]-]+)//) { 2944 $end_command = $1; 2945 2946 if (!exists $block_commands{$end_command}) { 2947 $self->_command_warn($current, $line_nr, 2948 __("unknown \@end %s"), $end_command); 2949 $end_command = undef; 2950 } else { 2951 print STDERR "END BLOCK $end_command\n" if ($self->{'DEBUG'}); 2952 if ($block_commands{$end_command} eq 'conditional') { 2953 if (@{$self->{'conditionals_stack'}} 2954 and $self->{'conditionals_stack'}->[-1] eq $end_command) { 2955 pop @{$self->{'conditionals_stack'}}; 2956 } else { 2957 $self->_command_error($current, $line_nr, 2958 __("unmatched `%c%s'"), ord('@'), 'end'); 2959 $end_command = undef; 2960 } 2961 } 2962 $current->{'extra'}->{'command_argument'} = $end_command 2963 if (defined($end_command)); 2964 } 2965 if (($superfluous_arg or $line =~ /\S/) 2966 and defined($end_command)) { 2967 my $texi_line 2968 = Texinfo::Convert::Texinfo::convert($current->{'args'}->[0]); 2969 $texi_line =~ s/^\s*([[:alnum:]][[:alnum:]-]+)//; 2970 $self->_command_error($current, $line_nr, 2971 __("superfluous argument to \@%s %s: %s"), 2972 $command, $end_command, $texi_line); 2973 $superfluous_arg = 0; # Don't issue another error message below. 2974 } 2975 } else { 2976 $self->_command_error($current, $line_nr, 2977 __("bad argument to \@%s: %s"), 2978 $command, $line); 2979 } 2980 } elsif ($superfluous_arg) { 2981 # An error message is issued below. 2982 } elsif ($command eq 'include') { 2983 my $file = Texinfo::Common::locate_include_file($self, $text) ; 2984 if (defined($file)) { 2985 my $filehandle = do { local *FH }; 2986 if (_open_in ($self, $filehandle, $file)) { 2987 $included_file = 1; 2988 print STDERR "Included $file($filehandle)\n" if ($self->{'DEBUG'}); 2989 my ($directories, $suffix); 2990 ($file, $directories, $suffix) = fileparse($file); 2991 unshift @{$self->{'input'}}, { 2992 'name' => $file, 2993 'line_nr' => 0, 2994 'pending' => [], 2995 'fh' => $filehandle }; 2996 } else { 2997 $self->_command_error($current, $line_nr, 2998 __("\@%s: could not open %s: %s"), 2999 $command, $text, $!); 3000 } 3001 } else { 3002 $self->_command_error($current, $line_nr, 3003 __("\@%s: could not find %s"), 3004 $command, $text); 3005 } 3006 } elsif ($command eq 'verbatiminclude') { 3007 $current->{'extra'}->{'input_perl_encoding'} 3008 = $self->{'info'}->{'input_perl_encoding'} 3009 if defined $self->{'info'}->{'input_perl_encoding'}; 3010 } elsif ($command eq 'documentencoding') { 3011 my ($texinfo_encoding, $perl_encoding, $input_encoding) 3012 = Texinfo::Encoding::encoding_alias($text); 3013 $self->_command_warn($current, $line_nr, 3014 __("encoding `%s' is not a canonical texinfo encoding"), 3015 $text) 3016 if (!$texinfo_encoding or $texinfo_encoding ne lc($text)); 3017 if ($input_encoding) { 3018 $current->{'extra'}->{'input_encoding_name'} = $input_encoding; 3019 } 3020 if (!$perl_encoding) { 3021 $self->_command_warn($current, $line_nr, 3022 __("unrecognized encoding name `%s'"), $text); 3023 } else { 3024 $current->{'extra'}->{'input_perl_encoding'} = $perl_encoding; 3025 3026 if ($input_encoding) { 3027 $self->{'info'}->{'input_encoding_name'} = $input_encoding; 3028 } 3029 3030 $self->{'info'}->{'input_perl_encoding'} = $perl_encoding; 3031 foreach my $input (@{$self->{'input'}}) { 3032 binmode($input->{'fh'}, ":encoding($perl_encoding)") if ($input->{'fh'}); 3033 } 3034 } 3035 } elsif ($command eq 'documentlanguage') { 3036 my @messages = Texinfo::Common::warn_unknown_language($text); 3037 foreach my $message(@messages) { 3038 $self->_command_warn($current, $line_nr, $message); 3039 } 3040 if (!$self->{'set'}->{'documentlanguage'}) { 3041 $self->{'documentlanguage'} = $text; 3042 } 3043 } 3044 } 3045 if ($superfluous_arg) { 3046 my $texi_line 3047 = Texinfo::Convert::Texinfo::convert($current->{'args'}->[0]); 3048 $texi_line =~ s/^\s*//; 3049 $texi_line =~ s/\s*$//; 3050 3051 $self->_command_error($current, $line_nr, 3052 __("bad argument to \@%s: %s"), 3053 $command, $texi_line); 3054 3055 } 3056 } elsif ($command eq 'node') { 3057 foreach my $arg (@{$current->{'args'}}) { 3058 my $node = _parse_node_manual($arg); 3059 push @{$current->{'extra'}->{'nodes_manuals'}}, $node; 3060 } 3061 _check_internal_node($self, $current->{'extra'}->{'nodes_manuals'}->[0], 3062 $line_nr); 3063 _register_label($self, $current, 3064 $current->{'extra'}->{'nodes_manuals'}->[0]); 3065 $self->{'current_node'} = $current; 3066 } elsif ($command eq 'listoffloats') { 3067 _parse_float_type($current); 3068 } else { 3069 # Handle all the other 'line' commands. Here just check that they 3070 # have an argument. Empty @top is allowed 3071 if (!@{$current->{'args'}->[0]->{'contents'}} and $command ne 'top') { 3072 $self->_command_warn($current, $line_nr, 3073 __("\@%s missing argument"), $command); 3074 $current->{'extra'}->{'missing_argument'} = 1; 3075 } else { 3076 if (($command eq 'item' or $command eq 'itemx') 3077 and $current->{'parent'}->{'cmdname'} 3078 and $self->{'command_index'}->{$current->{'parent'}->{'cmdname'}}) { 3079 _enter_index_entry($self, $current->{'parent'}->{'cmdname'}, 3080 $command, $current, 3081 $current->{'args'}->[0]->{'contents'}, 3082 undef, $line_nr); 3083 } elsif ($self->{'command_index'}->{$current->{'cmdname'}}) { 3084 _enter_index_entry($self, $current->{'cmdname'}, 3085 $current->{'cmdname'}, $current, 3086 $current->{'args'}->[0]->{'contents'}, 3087 undef, $line_nr); 3088 $current->{'type'} = 'index_entry_command'; 3089 } 3090 } 3091 } 3092 $current = $current->{'parent'}; 3093 if ($end_command) { 3094 print STDERR "END COMMAND $end_command\n" if ($self->{'DEBUG'}); 3095 my $end = pop @{$current->{'contents'}}; 3096 if ($block_commands{$end_command} ne 'conditional') { 3097 my $closed_command; 3098 ($closed_command, $current) 3099 = _close_commands($self, $current, $line_nr, $end_command); 3100 my $inline_copying; 3101 if ($closed_command) { 3102 $closed_command->{'extra'}->{'end_command'} = $misc_cmd; 3103 _close_command_cleanup($self, $closed_command); 3104 $end->{'parent'} = $closed_command; 3105 3106 push @{$closed_command->{'contents'}}, $end; 3107 3108 # closing a menu command, but still in a menu. Open a menu_comment 3109 if ($menu_commands{$closed_command->{'cmdname'}} 3110 and $self->{'context_stack'}->[-1] eq 'menu') { 3111 print STDERR "CLOSE MENU but still in menu context\n" 3112 if ($self->{'DEBUG'}); 3113 push @{$current->{'contents'}}, {'type' => 'menu_comment', 3114 'parent' => $current, 3115 'contents' => [] }; 3116 $current = $current->{'contents'}->[-1]; 3117 push @{$self->{'context_stack'}}, 'preformatted'; 3118 } 3119 } else { 3120 # block command not found for @end 3121 } 3122 $current = _begin_preformatted($self, $current) 3123 if ($close_preformatted_commands{$end_command}); 3124 } 3125 } else { 3126 $current = _begin_preformatted($self, $current) 3127 if ($close_preformatted_commands{$command}); 3128 } 3129 # if a file was included, remove completly the include file command. 3130 # Also ignore @setfilename in included file, as said in the manual. 3131 if ($included_file or ($command eq 'setfilename' 3132 and scalar(@{$self->{'input'}}) > 1)) { 3133 # TODO keep the information with sourcemark 3134 pop @{$current->{'contents'}}; 3135 } elsif ($command eq 'setfilename' 3136 and ($self->{'current_node'} or $self->{'current_section'})) { 3137 $self->_command_warn($misc_cmd, $line_nr, 3138 __("\@%s after the first element"), $command); 3139 # columnfractions 3140 } elsif ($command eq 'columnfractions') { 3141 # in a multitable, we are in a block_line_arg 3142 if (!$current->{'parent'} or !$current->{'parent'}->{'cmdname'} 3143 or $current->{'parent'}->{'cmdname'} ne 'multitable') { 3144 $self->_command_error($current, $line_nr, 3145 __("\@%s only meaningful on a \@multitable line"), 3146 $command); 3147 } else { 3148 # This is the multitable block_line_arg line context 3149 my $context = pop @{$self->{'context_stack'}}; 3150 if ($context ne 'line') { 3151 $self->_bug_message("context $context instead of line for multitable", 3152 $line_nr, $current); 3153 } 3154 $current = $current->{'parent'}; 3155 $current->{'extra'}->{'max_columns'} = 0; 3156 if (defined($misc_cmd->{'extra'}->{'misc_args'})) { 3157 $current->{'extra'}->{'max_columns'} = 3158 scalar(@{$misc_cmd->{'extra'}->{'misc_args'}}); 3159 $current->{'extra'}->{'columnfractions'} = $misc_cmd; 3160 } 3161 push @{$current->{'contents'}}, { 'type' => 'before_item', 3162 'contents' => [], 'parent', $current }; 3163 $current = $current->{'contents'}->[-1]; 3164 } 3165 } elsif ($root_commands{$command}) { 3166 $current = $current->{'contents'}->[-1]; 3167 delete $current->{'remaining_args'}; 3168 3169 # associate the section (not part) with the current node. 3170 if ($command ne 'node' and $command ne 'part') { 3171 if ($self->{'current_node'} 3172 and !$self->{'current_node'}->{'extra'}->{'associated_section'}) { 3173 $self->{'current_node'}->{'extra'}->{'associated_section'} = $current; 3174 $current->{'extra'}->{'associated_node'} = $self->{'current_node'}; 3175 } 3176 if ($self->{'current_part'}) { 3177 $current->{'extra'}->{'associated_part'} = $self->{'current_part'}; 3178 $self->{'current_part'}->{'extra'}->{'part_associated_section'} 3179 = $current; 3180 if ($current->{'cmdname'} eq 'top') { 3181 $self->line_warn("\@part should not be associated with \@top", 3182 $self->{'current_part'}->{'line_nr'}); 3183 } 3184 delete $self->{'current_part'}; 3185 } 3186 $self->{'current_section'} = $current; 3187 } elsif ($command eq 'part') { 3188 $self->{'current_part'} = $current; 3189 if ($self->{'current_node'} 3190 and !$self->{'current_node'}->{'extra'}->{'associated_section'}) { 3191 $self->line_warn (sprintf(__( 3192 "\@node precedes \@%s, but parts may not be associated with nodes"), 3193 $command), $line_nr); 3194 } 3195 } 3196 } 3197 # do that last in order to have the line processed if one of the above 3198 # case is also set. 3199 } elsif ( 3200 $current->{'contents'} 3201 and (scalar(@{$current->{'contents'}}) == 1 3202 and (($current->{'contents'}->[-1]->{'type'} 3203 and $current->{'contents'}->[-1]->{'type'} eq 'empty_line_after_command')) 3204 or (scalar(@{$current->{'contents'}}) == 2 3205 and $current->{'contents'}->[-1]->{'cmdname'} 3206 and ($current->{'contents'}->[-1]->{'cmdname'} eq 'c' 3207 or $current->{'contents'}->[-1]->{'cmdname'} eq 'comment') 3208 and $current->{'contents'}->[-2] 3209 and $current->{'contents'}->[-2]->{'type'} 3210 and $current->{'contents'}->[-2]->{'type'} eq 'empty_line_after_command'))) { 3211 # empty line after a @menu or before a preformatted. Reparent to the menu 3212 # or other format 3213 if ($current->{'type'} 3214 and $preformatted_contexts{$current->{'type'}}) { 3215 my $parent = $current->{'parent'}; 3216 if ($parent->{'type'} and $parent->{'type'} eq 'menu_comment' 3217 and scalar(@{$parent->{'contents'}}) == 1) { 3218 $parent = $parent->{'parent'}; 3219 } 3220 my $to_reparent = pop @{$parent->{'contents'}}; 3221 print STDERR "LINE AFTER COMMAND IN PREFORMATTED ($to_reparent->{'type'})\n" if ($self->{'DEBUG'}); 3222 while (@{$current->{'contents'}}) { 3223 my $content = shift @{$current->{'contents'}}; 3224 $content->{'parent'} = $parent; 3225 push @{$parent->{'contents'}}, $content; 3226 } 3227 push @{$parent->{'contents'}}, $to_reparent; 3228 } 3229 } 3230 3231 # this happens if there is a nesting of line @-commands on a line. 3232 # they are reprocessed here. 3233 if ($self->{'context_stack'}->[-1] eq 'line' 3234 or $self->{'context_stack'}->[-1] eq 'def') { 3235 print STDERR "Still opened line command $self->{'context_stack'}->[-1]:"._print_current($current) 3236 if ($self->{'DEBUG'}); 3237 if ($self->{'context_stack'}->[-1] eq 'def') { 3238 while ($current->{'parent'} and !($current->{'parent'}->{'type'} 3239 and $current->{'parent'}->{'type'} eq 'def_line')) { 3240 $current = _close_current($self, $current, $line_nr); 3241 } 3242 } else { 3243 while ($current->{'parent'} and !($current->{'type'} 3244 and ($current->{'type'} eq 'block_line_arg' 3245 or $current->{'type'} eq 'line_arg'))) { 3246 $current = _close_current($self, $current, $line_nr); 3247 } 3248 } 3249 3250 # check for infinite loop bugs... 3251 if ($current eq $current_old) { 3252 my $indent = '- '; 3253 my $tree_msg = $indent . _print_current($current); 3254 while ($current->{'parent'}) { 3255 $indent = '-'.$indent; 3256 $current = $current->{'parent'}; 3257 $tree_msg .= $indent . _print_current($current); 3258 } 3259 $self->_bug_message("Nothing closed while a line context remains\n$tree_msg", 3260 $line_nr); 3261 die; 3262 } 3263 3264 $current = $self->_end_line($current, $line_nr); 3265 } 3266 return $current; 3267} 3268 3269# $command may be undef if we are after a wrong misc command such as 3270# a buggy @tab. 3271sub _start_empty_line_after_command($$$) { 3272 my ($line, $current, $command) = @_; 3273 3274 $line =~ s/^([^\S\r\n]*)//; 3275 push @{$current->{'contents'}}, { 'type' => 'empty_line_after_command', 3276 'text' => $1, 3277 'parent' => $current, 3278 }; 3279 if (defined($command)) { 3280 $current->{'contents'}->[-1]->{'extra'} = {'command' => $command}; 3281 } 3282 return $line; 3283} 3284 3285sub _check_empty_node($$$$) 3286{ 3287 my ($self, $parsed_node, $command, $line_nr) = @_; 3288 3289 if (!defined($parsed_node) or !$parsed_node->{'node_content'}) { 3290 $self->line_error (sprintf(__("empty argument in \@%s"), 3291 $command), $line_nr); 3292 return 0; 3293 } else { 3294 return 1; 3295 } 3296} 3297 3298sub _check_internal_node($$$) 3299{ 3300 my ($self, $parsed_node, $line_nr) = @_; 3301 3302 if ($parsed_node and $parsed_node->{'manual_content'}) { 3303 $self->line_error (sprintf(__("syntax for an external node used for `%s'"), 3304 Texinfo::Structuring::node_extra_to_texi($parsed_node)), $line_nr) 3305 } 3306} 3307 3308sub _check_node_label($$$$) 3309{ 3310 my ($self, $parsed_node, $command, $line_nr) = @_; 3311 3312 _check_internal_node($self, $parsed_node, $line_nr); 3313 return _check_empty_node($self, $parsed_node, $command, $line_nr); 3314} 3315 3316sub _register_extra_menu_entry_information($$;$) 3317{ 3318 my ($self, $current, $line_nr) = @_; 3319 3320 foreach my $arg (@{$current->{'args'}}) { 3321 if ($arg->{'type'} eq 'menu_entry_name') { 3322 $current->{'extra'}->{'menu_entry_name'} = $arg; 3323 my $normalized_menu_entry_name = 3324 Texinfo::Convert::NodeNameNormalization::normalize_node($arg); 3325 if ($normalized_menu_entry_name !~ /[^-]/) { 3326 $self->line_warn(sprintf(__("empty menu entry name in `%s'"), 3327 Texinfo::Convert::Texinfo::convert($current)), $line_nr); 3328 } 3329 } elsif ($arg->{'type'} eq 'menu_entry_node') { 3330 _isolate_last_space($self, $arg); 3331 my $parsed_entry_node = _parse_node_manual($arg); 3332 if (! defined($parsed_entry_node)) { 3333 if ($self->{'FORMAT_MENU'} eq 'menu') { 3334 $self->line_error (__("empty node name in menu entry"), $line_nr); 3335 } 3336 } else { 3337 delete $parsed_entry_node->{'normalized'}; 3338 $current->{'extra'}->{'menu_entry_node'} = $parsed_entry_node; 3339 } 3340 } elsif ($arg->{'type'} eq 'menu_entry_description') { 3341 $current->{'extra'}->{'menu_entry_description'} = $arg; 3342 } 3343 } 3344} 3345 3346sub _enter_menu_entry_node($$$) 3347{ 3348 my ($self, $current, $line_nr) = @_; 3349 3350 my $description = { 'type' => 'menu_entry_description', 3351 'contents' => [], 3352 'parent' => $current }; 3353 push @{$current->{'args'}}, $description; 3354 _register_extra_menu_entry_information($self, $current, $line_nr); 3355 $current->{'line_nr'} = $line_nr; 3356 push @{$self->{'internal_references'}}, $current; 3357 3358 $current = $description; 3359 push @{$current->{'contents'}}, {'type' => 'preformatted', 3360 'parent' => $current, 3361 'contents' => [] }; 3362 $current = $current->{'contents'}->[-1]; 3363 push @{$self->{'context_stack'}}, 'preformatted'; 3364 return $current; 3365} 3366 3367sub _command_with_command_as_argument($) 3368{ 3369 my $current = shift; 3370 return ($current and $current->{'type'} 3371 and $current->{'type'} eq 'block_line_arg' 3372 and $current->{'parent'} 3373 and $current->{'parent'}->{'cmdname'} and 3374 ($current->{'parent'}->{'cmdname'} eq 'itemize' 3375 or $item_line_commands{$current->{'parent'}->{'cmdname'}}) 3376 and scalar(@{$current->{'contents'}}) == 1); 3377} 3378 3379sub _is_index_element { 3380 my ($self, $element) = @_; 3381 3382 if (!$element->{'cmdname'} 3383 or (!$self->{'command_index'}->{$element->{'cmdname'}} 3384 and $element->{'cmdname'} ne 'subentry')) { 3385 return 0; 3386 } 3387 return 1; 3388} 3389 3390# This combines several regular expressions used in '_parse_texi' to 3391# look at what is next on the remaining part of the line. 3392# NOTE - this sub has an XS override 3393sub _parse_texi_regex { 3394 my ($line) = @_; 3395 3396 my ($at_command, $open_brace, $asterisk, $single_letter_command, 3397 $separator_match, $misc_text) 3398 = ($line =~ /^\@([[:alnum:]][[:alnum:]-]*) 3399 |^(\{) 3400 |^(\*) 3401 |^\@(["'~\@&\}\{,\.!\? \t\n\*\-\^`=:\|\/\\]) 3402 |^([{}@,:\t.\f]) 3403 |^([^{}@,:\t.\n\f]+) 3404 /x); 3405 3406 if ($open_brace) { 3407 $separator_match = $open_brace; 3408 } elsif ($asterisk) { 3409 ($misc_text) = ($line =~ /^([^{}@,:\t.\n\f]+)/); 3410 } 3411 3412 return ($at_command, $open_brace, $asterisk, $single_letter_command, 3413 $separator_match, $misc_text); 3414} 3415 3416sub _check_line_directive { 3417 my ($self, $line, $line_nr) = @_; 3418 3419 if ($self->{'CPP_LINE_DIRECTIVES'} 3420 and defined($line_nr->{'file_name'}) 3421 and $line_nr->{'file_name'} ne '' 3422 and !$line_nr->{'macro'} 3423 and $line =~ /^\s*#\s*(line)? (\d+)(( "([^"]+)")(\s+\d+)*)?\s*$/) { 3424 _save_line_directive ($self, int($2), $5); 3425 return 1; 3426 } 3427 return 0; 3428} 3429 3430# Check whether $COMMAND can appear within $CURRENT->{'parent'}. 3431sub _check_valid_nesting { 3432 my ($self, $current, $command, $line_nr) = @_; 3433 3434 my $invalid_parent; 3435 # error messages for forbidden constructs, like @node in @r, 3436 # block command on line command, @xref in @anchor or node... 3437 if ($current->{'parent'}) { 3438 if ($current->{'parent'}->{'cmdname'}) { 3439 if (defined($self->{'valid_nestings'}->{$current->{'parent'}->{'cmdname'}}) 3440 and !$self->{'valid_nestings'}->{$current->{'parent'}->{'cmdname'}}->{$command} 3441 # we make sure that we are on a root @-command line and 3442 # not in contents 3443 and (!$root_commands{$current->{'parent'}->{'cmdname'}} 3444 or ($current->{'type'} 3445 and $current->{'type'} eq 'line_arg')) 3446 # we make sure that we are on a block @-command line and 3447 # not in contents 3448 and (!($block_commands{$current->{'parent'}->{'cmdname'}}) 3449 or ($current->{'type'} 3450 and $current->{'type'} eq 'block_line_arg')) 3451 # we make sure that we are on an @item/@itemx line and 3452 # not in an @enumerate, @multitable or @itemize @item. 3453 and (($current->{'parent'}->{'cmdname'} ne 'itemx' 3454 and $current->{'parent'}->{'cmdname'} ne 'item') 3455 or ($current->{'type'} 3456 and $current->{'type'} eq 'line_arg'))) { 3457 $invalid_parent = $current->{'parent'}->{'cmdname'}; 3458 } 3459 } elsif ($self->{'context_stack'}->[-1] eq 'def' 3460 # FIXME instead of hardcoding in_full_line_commands_no_refs 3461 # it would be better to use the parent command valid_nesting. 3462 and !$in_full_line_commands_no_refs{$command}) { 3463 my $def_block = $current; 3464 while ($def_block->{'parent'} and (!$def_block->{'parent'}->{'type'} 3465 or $def_block->{'parent'}->{'type'} ne 'def_line')) { 3466 $def_block = $def_block->{'parent'}; 3467 } 3468 3469 $invalid_parent = $def_block->{'parent'}->{'parent'}->{'cmdname'}; 3470 } 3471 } 3472 3473 if (defined($invalid_parent)) { 3474 $self->line_warn(sprintf(__("\@%s should not appear in \@%s"), 3475 $command, $invalid_parent), $line_nr); 3476 } 3477} 3478 3479 3480# the main subroutine 3481sub _parse_texi($;$) 3482{ 3483 my ($self, $root) = @_; 3484 3485 $root = { 'contents' => [], 'type' => 'text_root' } if (!defined($root)); 3486 my $current = $root; 3487 3488 my $line_nr; 3489 3490 NEXT_LINE: 3491 while (1) { 3492 my $line; 3493 ($line, $line_nr) = _next_text($self, $line_nr); 3494 last if (!defined($line)); 3495 3496 if ($self->{'DEBUG'}) { 3497 my $line_text = ''; 3498 $line_text = "$line_nr->{'line_nr'}.$line_nr->{'macro'}" if ($line_nr); 3499 print STDERR "NEW LINE(".join('|', @{$self->{'context_stack'}}).":@{$self->{'conditionals_stack'}}:$line_text): $line"; 3500 #print STDERR "CONTEXT_STACK ".join('|',@{$self->{'context_stack'}})."\n"; 3501 } 3502 3503 if (not 3504 # raw format or verb 3505 (($current->{'cmdname'} 3506 and $block_commands{$current->{'cmdname'}} 3507 and ($block_commands{$current->{'cmdname'}} eq 'raw' 3508 or $block_commands{$current->{'cmdname'}} eq 'conditional')) 3509 or 3510 ($current->{'parent'} and $current->{'parent'}->{'cmdname'} 3511 and $current->{'parent'}->{'cmdname'} eq 'verb') 3512 ) 3513 # not def line 3514 and $self->{'context_stack'}->[-1] ne 'def') { 3515 next NEXT_LINE if _check_line_directive ($self, $line, $line_nr); 3516 print STDERR "BEGIN LINE\n" if ($self->{'DEBUG'}); 3517 3518 if ($current->{'contents'} 3519 and $current->{'contents'}->[-1] 3520 and $current->{'contents'}->[-1]->{'type'} 3521 and $current->{'contents'}->[-1]->{'type'} 3522 eq 'empty_spaces_before_argument') { 3523 # Remove this element and update 'extra' values. 3524 # FIXME: should we continue with this element instead? 3525 _abort_empty_line($self, $current); 3526 } 3527 $line =~ s/^([^\S\r\n]*)//; 3528 push @{$current->{'contents'}}, { 'type' => 'empty_line', 3529 'text' => $1, 3530 'parent' => $current }; 3531 } 3532 3533 while (1) { 3534 # in a raw or ignored conditional block command 3535 if ($current->{'cmdname'} and 3536 $block_commands{$current->{'cmdname'}} and 3537 ($block_commands{$current->{'cmdname'}} eq 'raw' 3538 or $block_commands{$current->{'cmdname'}} eq 'conditional')) { 3539 # r?macro may be nested 3540 if (($current->{'cmdname'} eq 'macro' 3541 or $current->{'cmdname'} eq 'rmacro') 3542 and $line =~ /^\s*\@r?macro\s+/) { 3543 $line =~ s/\s*\@(r?macro)//; 3544 push @{$current->{'contents'}}, { 'cmdname' => $1, 3545 'parent' => $current, 3546 'contents' => [], 3547 'extra' => {'arg_line' => $line }}; 3548 $current = $current->{'contents'}->[-1]; 3549 last; 3550 # ifclear/ifset may be nested 3551 } elsif (($current->{'cmdname'} eq 'ifclear' 3552 or $current->{'cmdname'} eq 'ifset' 3553 or $current->{'cmdname'} eq 'ifcommanddefined' 3554 or $current->{'cmdname'} eq 'ifcommandnotdefined') 3555 and $line =~ /^\s*\@$current->{'cmdname'}/) { 3556 $line =~ s/\s*\@($current->{'cmdname'})//; 3557 push @{$current->{'contents'}}, { 'cmdname' => $1, 3558 'parent' => $current, 3559 'contents' => [], 3560 'extra' => {'line' => $line }}; 3561 $current = $current->{'contents'}->[-1]; 3562 last; 3563 } elsif ($line =~ /^(\s*?)\@end\s+([a-zA-Z][\w-]*)/ 3564 and ($2 eq $current->{'cmdname'})) { 3565 my $end_command = $2; 3566 $line =~ s/^(\s*?)(\@end\s+$current->{'cmdname'})//; 3567 if ($1 eq '') { 3568 # FIXME exclude other formats, like @macro, @ifset, @ignore? 3569 if ($current->{'cmdname'} ne 'verbatim' 3570 and @{$current->{'contents'}} 3571 and $current->{'contents'}->[-1]->{'type'} 3572 and $current->{'contents'}->[-1]->{'type'} eq 'raw') { 3573 if ($current->{'contents'}->[-1]->{'text'} =~ s/(\n)//) { 3574 push @{$current->{'contents'}}, {'type' => 'last_raw_newline', 3575 'text' => $1, 'parent' => $current}; 3576 } 3577 } 3578 } else { 3579 push @{$current->{'contents'}}, 3580 { 'text' => $1, 'type' => 'raw', 'parent' => $current }; 3581 $self->line_warn(sprintf(__("\@end %s should only appear at the beginning of a line"), 3582 $end_command), $line_nr); 3583 } 3584 # if there is a user defined macro that expandes to spaces, there 3585 # will be a spurious warning. 3586 $self->line_warn(sprintf( 3587 __("superfluous argument to \@%s %s: %s"), 'end', $end_command, 3588 $line), $line_nr) 3589 if ($line =~ /\S/ and $line !~ /^\s*\@c(omment)?\b/); 3590 # store toplevel macro specification 3591 if (($end_command eq 'macro' or $end_command eq 'rmacro') 3592 and (! $current->{'parent'} 3593 or !$current->{'parent'}->{'cmdname'} 3594 or ($current->{'parent'}->{'cmdname'} ne 'macro' 3595 and $current->{'parent'}->{'cmdname'} ne 'rmacro'))) { 3596 my $macrobody = 3597 Texinfo::Convert::Texinfo::convert({ 'contents' 3598 => $current->{'contents'} }); 3599 if ($current->{'args'} and $current->{'args'}->[0]) { 3600 my $name = $current->{'args'}->[0]->{'text'}; 3601 if (exists($self->{'macros'}->{$name})) { 3602 $self->line_warn(sprintf(__("macro `%s' previously defined"), 3603 $name), $current->{'line_nr'}); 3604 $self->line_warn(sprintf(__( 3605 "here is the previous definition of `%s'"), 3606 $name), $self->{'macros'}->{$name}->{'element'}->{'line_nr'}); 3607 } 3608 if ($all_commands{$name}) { 3609 $self->line_warn(sprintf(__( 3610 "redefining Texinfo language command: \@%s"), 3611 $name), $current->{'line_nr'}); 3612 } 3613 if (!$current->{'extra'}->{'invalid_syntax'}) { 3614 $self->{'macros'}->{$name} = { 3615 'element' => $current, 3616 'macrobody' => $macrobody 3617 }; 3618 # Don't need 'args_index' in final tree. 3619 if (defined $current->{'extra'}->{'args_index'}) { 3620 $self->{'macros'}->{$name}->{'args_index'} 3621 = $current->{'extra'}->{'args_index'}; 3622 delete $current->{'extra'}->{'args_index'}; 3623 } 3624 } elsif (defined $current->{'extra'}->{'args_index'}) { 3625 delete $current->{'extra'}->{'args_index'}; 3626 } 3627 } 3628 } 3629 $current = $current->{'parent'}; 3630 if ($block_commands{$end_command} eq 'conditional') { 3631 # don't store ignored @if* 3632 my $conditional = pop @{$current->{'contents'}}; 3633 if (!defined($conditional->{'cmdname'} 3634 or $conditional->{'cmdname'} ne $end_command)) { 3635 $self->_bug_message("Ignored command is not the conditional $end_command", 3636 $line_nr, $conditional); 3637 die; 3638 } 3639 # Ignore until end of line 3640 if ($line !~ /\n/) { 3641 ($line, $line_nr) = _new_line($self, $line_nr); 3642 print STDERR "IGNORE CLOSE line: $line" if ($self->{'DEBUG'}); 3643 } 3644 print STDERR "CLOSED conditional $end_command\n" if ($self->{'DEBUG'}); 3645 last; 3646 } else { 3647 print STDERR "CLOSED raw $end_command\n" if ($self->{'DEBUG'}); 3648 $line =~ s/^([^\S\r\n]*)//; 3649 # Start an element to have the spaces at the end of the line 3650 # ignored. 3651 push @{$current->{'contents'}}, 3652 { 'type' => 'empty_line_after_command', 3653 'text' => $1, 3654 'parent' => $current, 3655 }; 3656 } 3657 } else { 3658 if (@{$current->{'contents'}} 3659 and $current->{'contents'}->[-1]->{'type'} 3660 and $current->{'contents'}->[-1]->{'type'} eq 'empty_line_after_command' 3661 and $current->{'contents'}->[-1]->{'text'} !~ /\n/ 3662 and $line !~ /\S/) { 3663 $current->{'contents'}->[-1]->{'text'} .= $line; 3664 } else { 3665 push @{$current->{'contents'}}, 3666 { 'text' => $line, 'type' => 'raw', 'parent' => $current }; 3667 } 3668 last; 3669 } 3670 # in @verb. type should be 'brace_command_arg' 3671 } elsif ($current->{'parent'} and $current->{'parent'}->{'cmdname'} 3672 and $current->{'parent'}->{'cmdname'} eq 'verb') { 3673 # collect the first character if not already done 3674 if (!defined($current->{'parent'}->{'extra'}->{'delimiter'})) { 3675 if ($line =~ /^$/) { 3676 $current->{'parent'}->{'extra'}->{'delimiter'} = ''; 3677 $self->line_error(sprintf( 3678 __("\@%s without associated character"), 'verb'), $line_nr); 3679 } else { 3680 $line =~ s/^(.)//; 3681 $current->{'parent'}->{'extra'}->{'delimiter'} = $1; 3682 } 3683 } 3684 my $char = quotemeta($current->{'parent'}->{'extra'}->{'delimiter'}); 3685 if ($line =~ s/^(.*?)$char\}/\}/) { 3686 push @{$current->{'contents'}}, 3687 { 'text' => $1, 'type' => 'raw', 'parent' => $current } 3688 if ($1 ne ''); 3689 print STDERR "END VERB\n" if ($self->{'DEBUG'}); 3690 } else { 3691 push @{$current->{'contents'}}, 3692 { 'text' => $line, 'type' => 'raw', 'parent' => $current }; 3693 print STDERR "LINE VERB: $line" if ($self->{'DEBUG'}); 3694 last; 3695 } 3696 } 3697 3698 # this mostly happens in the following cases: 3699 # after expansion of user defined macro that doesn't end with EOL 3700 # after a protection of @\n in @def* line 3701 # at the end of an expanded Texinfo fragment 3702 while ($line eq '') { 3703 print STDERR "EMPTY TEXT\n" 3704 if ($self->{'DEBUG'}); 3705 ($line, $line_nr) = _next_text($self, $line_nr); 3706 if (!defined($line)) { 3707 # end of the file or of a text fragment. 3708 $current = _end_line ($self, $current, $line_nr); 3709 # It may happen that there is an @include file on the line, it 3710 # will be picked up at NEXT_LINE, beginning a new line 3711 next NEXT_LINE; 3712 } 3713 } 3714 3715 # handle user defined macros before anything else since 3716 # their expansion may lead to changes in the line 3717 # REMACRO 3718 my $at_command_length; 3719 3720 my ($at_command, $open_brace, $asterisk, $single_letter_command, 3721 $separator_match, $misc_text) = _parse_texi_regex ($line); 3722 3723 if ($at_command) { 3724 $at_command_length = length($at_command) + 1; 3725 } 3726 if ($at_command 3727 and ($self->{'macros'}->{$at_command} 3728 or (exists $self->{'aliases'}->{$at_command} and 3729 $self->{'macros'}->{$self->{'aliases'}->{$at_command}}))) { 3730 substr($line, 0, $at_command_length) = ''; 3731 my $command = $at_command; 3732 my $alias_command; 3733 if (exists($self->{'aliases'}->{$command})) { 3734 $alias_command = $command; 3735 $command = $self->{'aliases'}->{$command}; 3736 } 3737 3738 my $expanded_macro = $self->{'macros'}->{$command}->{'element'}; 3739 my $args_number = scalar(@{$expanded_macro->{'args'}}) -1; 3740 my $arguments = []; 3741 if ($line =~ s/^\s*{\s*//) { # macro with args 3742 ($arguments, $line, $line_nr) = 3743 _expand_macro_arguments($self, $expanded_macro, $line, $line_nr); 3744 } elsif (($args_number >= 2) or ($args_number <1)) { 3745 # as agreed on the bug-texinfo mailing list, no warn when zero 3746 # arg and not called with {}. 3747 $self->line_warn(sprintf(__( 3748 "\@%s defined with zero or more than one argument should be invoked with {}"), 3749 $command), $line_nr) 3750 if ($args_number >= 2); 3751 } else { 3752 if ($line !~ /\n/) { 3753 ($line, $line_nr) = _new_line($self, $line_nr); 3754 $line = '' if (!defined($line)); 3755 } 3756 $line =~ s/^\s*// if ($line =~ /\S/); 3757 my $has_end_of_line = chomp $line; 3758 $arguments = [$line]; 3759 $line = "\n" if ($has_end_of_line); 3760 } 3761 my $expanded = _expand_macro_body ($self, 3762 $self->{'macros'}->{$command}, 3763 $arguments, $line_nr); 3764 print STDERR "MACROBODY: $expanded".'||||||'."\n" 3765 if ($self->{'DEBUG'}); 3766 # empty result. It is ignored here. 3767 if ($expanded eq '') { 3768 next; 3769 } 3770 if ($self->{'MAX_MACRO_CALL_NESTING'} 3771 and scalar(@{$self->{'macro_stack'}}) > $self->{'MAX_MACRO_CALL_NESTING'}) { 3772 $self->line_warn(sprintf(__( 3773"macro call nested too deeply (set MAX_NESTED_MACROS to override; current value %d)"), 3774 $self->{'MAX_MACRO_CALL_NESTING'}), $line_nr); 3775 next; 3776 } 3777 if ($expanded_macro->{'cmdname'} eq 'macro') { 3778 my $found = 0; 3779 foreach my $macro (@{$self->{'macro_stack'}}) { 3780 if ($macro->{'args'}->[0]->{'text'} eq $command) { 3781 $self->line_error(sprintf(__( 3782 "recursive call of macro %s is not allowed; use \@rmacro if needed"), 3783 $command), $line_nr); 3784 $found = 1; 3785 last; 3786 } 3787 } 3788 next if ($found); 3789 } 3790 3791 my $expanded_lines = _text_to_lines($expanded); 3792 next if (!@$expanded_lines); 3793 chomp ($expanded_lines->[-1]); 3794 pop @$expanded_lines if ($expanded_lines->[-1] eq ''); 3795 print STDERR "MACRO EXPANSION LINES: ".join('|', @$expanded_lines) 3796 ."|\nEND LINES MACRO EXPANSION\n" if ($self->{'DEBUG'}); 3797 next if (!@$expanded_lines); 3798 unshift @{$self->{'macro_stack'}}, $expanded_macro; 3799 print STDERR "UNSHIFT MACRO_STACK: $expanded_macro->{'args'}->[0]->{'text'}\n" 3800 if ($self->{'DEBUG'}); 3801 my $new_lines = _complete_line_nr($expanded_lines, 3802 $line_nr->{'line_nr'}, $line_nr->{'file_name'}, 3803 $expanded_macro->{'args'}->[0]->{'text'}, 1); 3804 $line_nr->{'end_macro'} = 1; 3805 unshift @{$self->{'input'}->[0]->{'pending'}}, [$line, $line_nr]; 3806 my $new_text = shift @$new_lines; 3807 ($line, $line_nr) = ($new_text->[0], $new_text->[1]); 3808 unshift @{$self->{'input'}->[0]->{'pending'}}, @$new_lines; 3809 3810 # Now handle all the cases that may lead to command closing 3811 # or following character association with an @-command, especially 3812 # accent command, that is handle @-command with braces that don't 3813 # always need a brace. 3814 3815 # The condition below is only caught right after command opening, 3816 # otherwise we are in the 'args' and not right in the command container. 3817 } elsif ($current->{'cmdname'} 3818 and defined($brace_commands{$current->{'cmdname'}}) 3819 and !$open_brace) { 3820 # special case for @-command as argument of @itemize or @*table. 3821 if (_command_with_command_as_argument($current->{'parent'})) { 3822 print STDERR "FOR PARENT \@$current->{'parent'}->{'parent'}->{'cmdname'} command_as_argument $current->{'cmdname'}\n" if ($self->{'DEBUG'}); 3823 $current->{'type'} = 'command_as_argument' if (!$current->{'type'}); 3824 $current->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'} 3825 = $current; 3826 $current = $current->{'parent'}; 3827 # now accent commands 3828 } elsif ($accent_commands{$current->{'cmdname'}}) { 3829 if ($line =~ /^[^\S\r\n]/) { 3830 if ($current->{'cmdname'} =~ /^[a-zA-Z]/) { 3831 $line =~ s/^([^\S\r\n]+)//; 3832 $current->{'extra'}->{'spaces'} = '' 3833 if (!defined($current->{'extra'}->{'spaces'})); 3834 $current->{'extra'}->{'spaces'} .= $1; 3835 } else { 3836 $self->line_warn(sprintf( 3837 __("accent command `\@%s' must not be followed by whitespace"), 3838 $current->{'cmdname'}), $line_nr); 3839 $current = $current->{'parent'}; 3840 } 3841 } elsif ($line =~ /^\@/) { 3842 $self->line_error(sprintf( 3843 __("use braces to give a command as an argument to \@%s"), 3844 $current->{'cmdname'}), $line_nr); 3845 $current = $current->{'parent'}; 3846 } elsif ($line =~ s/^(.)//o) { 3847 print STDERR "ACCENT \@$current->{'cmdname'}\n" 3848 if ($self->{'DEBUG'}); 3849 my $following_arg = {'type' => 'following_arg', 3850 'parent' => $current}; 3851 $following_arg->{'contents'} = [{ 'text' => $1, 3852 'parent' => $following_arg } ]; 3853 $current->{'args'} = [ $following_arg ]; 3854 if ($current->{'cmdname'} eq 'dotless' and $1 ne 'i' and $1 ne 'j') { 3855 $self->line_error(sprintf( 3856 __("%c%s expects `i' or `j' as argument, not `%s'"), 3857 ord('@'), $current->{'cmdname'}, $1), $line_nr); 3858 } 3859 if ($current->{'cmdname'} =~ /^[a-zA-Z]/) { 3860 $current->{'args'}->[-1]->{'type'} = 'space_command_arg'; 3861 } 3862 $current = $current->{'parent'}; 3863 } else { # The accent is at end of line 3864 # whitespace for commands with letter. 3865 print STDERR "STRANGE ACC \@$current->{'cmdname'}\n" if ($self->{'DEBUG'}); 3866 $self->line_warn(sprintf( 3867 __("accent command `\@%s' must not be followed by new line"), 3868 $current->{'cmdname'}), $line_nr); 3869 $current = $current->{'parent'}; 3870 } 3871 next; 3872 } else { 3873 # ignore space after a braced @-command like TeX does 3874 if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'} 3875 and $line =~ s/^\s+//) { 3876 next; 3877 } 3878 $self->line_error(sprintf(__("\@%s expected braces"), 3879 $current->{'cmdname'}), $line_nr); 3880 $current = $current->{'parent'}; 3881 } 3882 # maybe a menu entry beginning: a * at the beginning of a menu line 3883 } elsif ($current->{'type'} 3884 and $current->{'type'} eq 'preformatted' 3885 and $current->{'parent'}->{'type'} 3886 and ($current->{'parent'}->{'type'} eq 'menu_comment' 3887 or $current->{'parent'}->{'type'} eq 'menu_entry_description') 3888 and $asterisk 3889 and @{$current->{'contents'}} 3890 and $current->{'contents'}->[-1]->{'type'} 3891 and $current->{'contents'}->[-1]->{'type'} eq 'empty_line' 3892 and $current->{'contents'}->[-1]->{'text'} eq '') { 3893 print STDERR "MENU STAR\n" if ($self->{'DEBUG'}); 3894 _abort_empty_line($self, $current); 3895 $line =~ s/^\*//; 3896 push @{$current->{'contents'}}, { 'parent' => $current, 3897 'type' => 'menu_star', 3898 'text' => '*' }; 3899 # a space after a * at the beginning of a menu line 3900 } elsif ($current->{'contents'} and @{$current->{'contents'}} 3901 and $current->{'contents'}->[-1]->{'type'} 3902 and $current->{'contents'}->[-1]->{'type'} eq 'menu_star') { 3903 if ($line !~ /^\s+/) { 3904 print STDERR "ABORT MENU STAR ($line)\n" if ($self->{'DEBUG'}); 3905 delete $current->{'contents'}->[-1]->{'type'}; 3906 } else { 3907 print STDERR "MENU ENTRY (certainly)\n" if ($self->{'DEBUG'}); 3908 # this is the menu star collected previously 3909 pop @{$current->{'contents'}}; 3910 $line =~ s/^(\s+)//; 3911 my $leading_text = '*' . $1; 3912 if ($current->{'type'} eq 'preformatted' 3913 and $current->{'parent'}->{'type'} 3914 and $current->{'parent'}->{'type'} eq 'menu_comment') { 3915 my $menu = $current->{'parent'}->{'parent'}; 3916 if (!@{$current->{'contents'}}) { 3917 pop @{$current->{'parent'}->{'contents'}}; 3918 if (!scalar(@{$current->{'parent'}->{'contents'}})) { 3919 pop @{$menu->{'contents'}}; 3920 } 3921 } 3922 $current = $menu; 3923 } else { 3924 # first parent preformatted, third is menu_entry 3925 if ($current->{'type'} ne 'preformatted' 3926 or $current->{'parent'}->{'type'} ne 'menu_entry_description' 3927 or $current->{'parent'}->{'parent'}->{'type'} ne 'menu_entry' 3928 or !$menu_commands{$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'}}) { 3929 $self->_bug_message("Not in menu comment nor description", 3930 $line_nr, $current); 3931 } 3932 $current = $current->{'parent'}->{'parent'}->{'parent'}; 3933 } 3934 my $context = pop @{$self->{'context_stack'}}; 3935 if ($context ne 'preformatted') { 3936 $self->_bug_message("context $context instead of preformatted after menu leading star", 3937 $line_nr, $current); 3938 } 3939 push @{$current->{'contents'}}, { 'type' => 'menu_entry', 3940 'parent' => $current, 3941 }; 3942 $current = $current->{'contents'}->[-1]; 3943 $current->{'args'} = [ { 'type' => 'menu_entry_leading_text', 3944 'text' => $leading_text, 3945 'parent' => $current }, 3946 { 'type' => 'menu_entry_name', 3947 'contents' => [], 3948 'parent' => $current } ]; 3949 $current = $current->{'args'}->[-1]; 3950 } 3951 # after a separator in menu 3952 } elsif ($current->{'args'} and @{$current->{'args'}} 3953 and $current->{'args'}->[-1]->{'type'} 3954 and $current->{'args'}->[-1]->{'type'} eq 'menu_entry_separator') { 3955 my $separator = $current->{'args'}->[-1]->{'text'}; 3956 # separator is ::, we concatenate and let the while restart 3957 # in order to collect spaces below 3958 if ($separator eq ':' and $line =~ s/^(:)//) { 3959 $current->{'args'}->[-1]->{'text'} .= $1; 3960 # a . not followed by a space. Not a separator. 3961 } elsif ($separator eq '.' and $line =~ /^\S/) { 3962 pop @{$current->{'args'}}; 3963 $current = $current->{'args'}->[-1]; 3964 $current = _merge_text($self, $current, $separator); 3965 # here we collect spaces following separators. 3966 } elsif ($line =~ s/^([^\S\r\n]+)//) { 3967 # FIXME a trailing end of line could be considered to be part 3968 # of the separator. Right now it is part of the description, 3969 # since it is catched (in the next while) as one of the case below 3970 $current->{'args'}->[-1]->{'text'} .= $1; 3971 # now handle the menu part that was closed 3972 } elsif ($separator =~ /^::/) { 3973 print STDERR "MENU NODE no entry $separator\n" if ($self->{'DEBUG'}); 3974 # it was previously registered as menu_entry_name, it is 3975 # changed to node 3976 $current->{'args'}->[-2]->{'type'} = 'menu_entry_node'; 3977 $current = _enter_menu_entry_node($self, $current, $line_nr); 3978 # end of the menu entry name 3979 } elsif ($separator =~ /^:/) { 3980 print STDERR "MENU ENTRY $separator\n" if ($self->{'DEBUG'}); 3981 push @{$current->{'args'}}, { 'type' => 'menu_entry_node', 3982 'contents' => [], 3983 'parent' => $current }; 3984 $current = $current->{'args'}->[-1]; 3985 # anything else is the end of the menu node following a menu_entry_name 3986 } else { 3987 print STDERR "MENU NODE $separator\n" if ($self->{'DEBUG'}); 3988 $current = _enter_menu_entry_node($self, $current, $line_nr); 3989 } 3990 # REMACRO 3991 } elsif ($at_command or $single_letter_command) { 3992 my $command; 3993 if (!$at_command) { 3994 $command = $single_letter_command; 3995 substr($line, 0, 2) = ''; 3996 } else { 3997 $command = $at_command; 3998 substr($line, 0, $at_command_length) = ''; 3999 } 4000 4001 print STDERR "COMMAND $command\n" if ($self->{'DEBUG'}); 4002 if (!$all_commands{$command} 4003 and !$self->{'macros'}->{$command} 4004 and !$self->{'definfoenclose'}->{$command} 4005 and !$self->{'aliases'}->{$command} 4006 and !$self->{'command_index'}->{$command}) { 4007 $self->line_error(sprintf(__("unknown command `%s'"), 4008 $command), $line_nr); 4009 _abort_empty_line($self, $current); 4010 my $paragraph = _begin_paragraph($self, $current, $line_nr); 4011 $current = $paragraph if ($paragraph); 4012 next; 4013 } 4014 4015 my $alias_command; 4016 if (exists($self->{'aliases'}->{$command})) { 4017 $alias_command = $command; 4018 $command = $self->{'aliases'}->{$command}; 4019 } 4020 4021 if ($command eq 'value') { 4022 $line =~ s/^\s*// 4023 if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'}); 4024 # REVALUE 4025 if ($line =~ s/^{([\w\-][^\s{\\}~`\^+"<>|@]*)}//) { 4026 my $value = $1; 4027 if (exists($self->{'values'}->{$value})) { 4028 if (!defined($self->{'values'}->{$value})) { 4029 print STDERR "BUG? $value exists but not defined\n"; 4030 } elsif (!ref($self->{'values'}->{$value})) { 4031 $line = $self->{'values'}->{$value} . $line; 4032 } else { 4033 print STDERR "BUG? $value defined as reference\n"; 4034 } 4035 } else { 4036 # Flag not defined. This is an error if it comes from 4037 # a user's document. It is also expected behaviour for 4038 # Texinfo::Report::gdt, where we want to defer substitution 4039 # of the value until after the containing Texinfo is parsed. 4040 _abort_empty_line($self, $current); 4041 # caller should expand something along 4042 # gdt('@{No value for `{value}\'@}', {'value' => $value}, {'keep_texi'=> 1}); 4043 push @{$current->{'contents'}}, { 'cmdname' => 'value', 4044 'type' => $value, 4045 'contents' => [], 4046 'parent' => $current }; 4047 if (!$self->{'in_gdt'}) { 4048 $self->line_warn( 4049 sprintf(__("undefined flag: %s"), $value), $line_nr); 4050 } 4051 } 4052 } else { 4053 $self->line_error(__("bad syntax for \@value"), $line_nr); 4054 } 4055 next; 4056 } 4057 4058 if (defined($deprecated_commands{$command})) { 4059 if ($deprecated_commands{$command} eq '') { 4060 $self->line_warn(sprintf(__("%c%s is obsolete."), 4061 ord('@'), $command), $line_nr); 4062 } else { 4063 $self->line_warn(sprintf(__("%c%s is obsolete; %s"), 4064 ord('@'), $command, 4065 __($deprecated_commands{$command})), $line_nr); 4066 } 4067 } 4068 4069 # special case with @ followed by a newline protecting end of lines 4070 # in @def* 4071 my $def_line_continuation 4072 = ($self->{'context_stack'}->[-1] eq 'def' and $command eq "\n"); 4073 4074 if (not $def_line_continuation 4075 and not _abort_empty_line($self, $current) 4076 and $begin_line_commands{$command}) { 4077 $self->line_warn( 4078 sprintf(__("\@%s should only appear at the beginning of a line"), 4079 $command), $line_nr); 4080 } 4081 4082 _check_valid_nesting ($self, $current, $command, $line_nr); 4083 4084 last if ($def_line_continuation); 4085 4086 unless ($self->{'no_paragraph_commands'}->{$command}) { 4087 my $paragraph = _begin_paragraph($self, $current, $line_nr); 4088 $current = $paragraph if ($paragraph); 4089 } 4090 4091 if ($self->{'close_paragraph_commands'}->{$command}) { 4092 $current = _end_paragraph($self, $current, $line_nr); 4093 } 4094 if ($self->{'close_preformatted_commands'}->{$command}) { 4095 $current = _end_preformatted($self, $current, $line_nr); 4096 } 4097 4098 if ($in_index_commands{$command} 4099 and $current->{'contents'} 4100 and $current->{'contents'}->[-1] 4101 and $current->{'contents'}->[-1]->{'text'}) { 4102 $current->{'contents'}->[-1]->{'text'} =~ s/(\s+)$//; 4103 if ($1 ne '') { 4104 if ($current->{'contents'}->[-1]->{'text'} eq '') { 4105 $current->{'contents'}->[-1]->{'text'} = $1; 4106 $current->{'contents'}->[-1]->{'type'} = 'empty_spaces_before_argument'; 4107 } else { 4108 my $new_spaces = { 'text' => $1, 'parent' => $current, 4109 'type' => 'empty_spaces_before_argument' }; 4110 push @{$current->{'contents'}}, $new_spaces; 4111 } 4112 } 4113 } 4114 4115 if (defined($other_commands{$command}) 4116 and ($command ne 'item' or !_item_line_parent($current))) { 4117 # noarg skipspace 4118 my $arg_spec = $other_commands{$command}; 4119 my $misc; 4120 4121 if ($arg_spec eq 'noarg') { 4122 if ($in_heading_commands{$command}) { 4123 $self->line_error( 4124 sprintf(__("\@%s should only appear in heading or footing"), 4125 $command), $line_nr); 4126 } 4127 $misc = {'cmdname' => $command, 'parent' => $current}; 4128 push @{$current->{'contents'}}, $misc; 4129 _register_global_command($self, $misc, $line_nr); 4130 $current = _begin_preformatted($self, $current) 4131 if ($close_preformatted_commands{$command}); 4132 } else { 4133 if ($command eq 'item' 4134 or $command eq 'headitem' or $command eq 'tab') { 4135 my $parent; 4136 # @itemize or @enumerate 4137 if ($parent = _item_container_parent($current)) { 4138 if ($command eq 'item') { 4139 print STDERR "ITEM_CONTAINER\n" if ($self->{'DEBUG'}); 4140 $parent->{'items_count'}++; 4141 $misc = { 'cmdname' => $command, 'parent' => $parent, 4142 'contents' => [], 4143 'extra' => 4144 {'item_number' => $parent->{'items_count'}} }; 4145 push @{$parent->{'contents'}}, $misc; 4146 $current = $parent->{'contents'}->[-1]; 4147 } else { 4148 $self->line_error(sprintf(__( 4149 "\@%s not meaningful inside `\@%s' block"), 4150 $command, $parent->{'cmdname'}), $line_nr); 4151 } 4152 $current = _begin_preformatted($self, $current); 4153 # @*table 4154 } elsif ($parent = _item_line_parent($current)) { 4155 $self->line_error(sprintf(__( 4156 "\@%s not meaningful inside `\@%s' block"), 4157 $command, $parent->{'cmdname'}), $line_nr); 4158 $current = _begin_preformatted($self, $current); 4159 # @multitable 4160 } elsif ($parent = _item_multitable_parent($current)) { 4161 if ($command eq 'item' or $command eq 'headitem' 4162 or $command eq 'tab') { 4163 if (!$parent->{'extra'}->{'max_columns'}) { 4164 $self->line_warn( 4165 sprintf(__("\@%s in empty multitable"), 4166 $command), $line_nr); 4167 } elsif ($command eq 'tab') { 4168 my $row = $parent->{'contents'}->[-1]; 4169 die if (!$row->{'type'}); 4170 if ($row->{'type'} eq 'before_item') { 4171 $self->line_error(__("\@tab before \@item"), $line_nr); 4172 } elsif ($row->{'cells_count'} >= $parent->{'extra'}->{'max_columns'}) { 4173 $self->line_error(sprintf(__( 4174 "too many columns in multitable item (max %d)"), 4175 $parent->{'extra'}->{'max_columns'}), $line_nr); 4176 } else { 4177 $row->{'cells_count'}++; 4178 $misc = { 'cmdname' => $command, 4179 'parent' => $row, 4180 'contents' => [], 4181 'extra' => 4182 {'cell_number' => $row->{'cells_count'}} }; 4183 push @{$row->{'contents'}}, $misc; 4184 $current = $row->{'contents'}->[-1]; 4185 #$current = $self->_begin_preformatted($current); 4186 print STDERR "TAB\n" if ($self->{'DEBUG'}); 4187 } 4188 } else { 4189 print STDERR "ROW\n" if ($self->{'DEBUG'}); 4190 $parent->{'rows_count'}++; 4191 my $row = { 'type' => 'row', 'contents' => [], 4192 'cells_count' => 1, 4193 'extra' => {'row_number' => $parent->{'rows_count'} }, 4194 'parent' => $parent }; 4195 push @{$parent->{'contents'}}, $row; 4196 $misc = { 'cmdname' => $command, 4197 'parent' => $row, 4198 'contents' => [], 4199 'extra' => {'cell_number' => 1}}; 4200 push @{$row->{'contents'}}, $misc; 4201 $current = $row->{'contents'}->[-1]; 4202 } 4203 } else { 4204 $self->line_error(sprintf(__( 4205 "\@%s not meaningful inside `\@%s' block"), 4206 $command, $parent->{'cmdname'}), $line_nr); 4207 } 4208 $current = _begin_preformatted($self, $current); 4209 } elsif ($command eq 'tab') { 4210 $self->line_error(__( 4211 "ignoring \@tab outside of multitable"), $line_nr); 4212 $current = _begin_preformatted($self, $current); 4213 } else { 4214 $self->line_error (sprintf(__( 4215 "\@%s outside of table or list"), $command), $line_nr); 4216 $current = _begin_preformatted($self, $current); 4217 } 4218 $misc->{'line_nr'} = $line_nr if (defined($misc)); 4219 } else { 4220 $misc = { 'cmdname' => $command, 'parent' => $current, 4221 'line_nr' => $line_nr }; 4222 push @{$current->{'contents'}}, $misc; 4223 } 4224 $line = _start_empty_line_after_command($line, $current, $misc); 4225 if ($command eq 'indent' 4226 or $command eq 'noindent') { 4227 if ($line !~ /\n/) { 4228 my ($new_line, $new_line_nr) = _new_line($self, $line_nr); 4229 $line .= $new_line if (defined($new_line)); 4230 } 4231 $line =~ s/^(\s*)//; 4232 if ($1) { 4233 $current = _merge_text($self, $current, $1); 4234 } 4235 if ($line ne '' 4236 and $current->{'contents'}->[-1]->{'type'} eq 4237 'empty_line_after_command') { 4238 $current->{'contents'}->[-1]->{'type'} 4239 = 'empty_spaces_after_command'; 4240 } 4241 my $paragraph = _begin_paragraph($self, $current, $line_nr); 4242 $current = $paragraph if $paragraph; 4243 if ($line eq '') { 4244 last; 4245 } 4246 } 4247 } 4248 # line commands 4249 } elsif (defined($self->{'line_commands'}->{$command})) { 4250 if ($root_commands{$command} or $command eq 'bye') { 4251 $current = _close_commands($self, $current, $line_nr, undef, 4252 $command); 4253 # root_level commands leads to setting a new root 4254 # for the whole document and stuffing the preceding text 4255 # as the first content, this is done only once. 4256 if ($current->{'type'} and $current->{'type'} eq 'text_root') { 4257 if ($command ne 'bye') { 4258 $root = { 'type' => 'document_root', 'contents' => [$current] }; 4259 $current->{'parent'} = $root; 4260 $current = $root; 4261 } 4262 } else { 4263 die if (!defined($current->{'parent'})); 4264 $current = $current->{'parent'}; 4265 } 4266 } 4267 4268 # skipline text line lineraw /^\d$/ 4269 my $arg_spec = $self->{'line_commands'}->{$command}; 4270 my $misc; 4271 4272 # all the cases using the raw line 4273 if ($arg_spec eq 'skipline' or $arg_spec eq 'lineraw' 4274 or $arg_spec eq 'special') { 4275 my $ignored = 0; 4276 if ($command eq 'insertcopying') { 4277 my $parent = $current; 4278 while ($parent) { 4279 if ($parent->{'cmdname'} and $parent->{'cmdname'} eq 'copying') { 4280 $self->line_error( 4281 sprintf(__("\@%s not allowed inside `\@%s' block"), 4282 $command, $parent->{'cmdname'}), $line_nr); 4283 $ignored = 1; 4284 last; 4285 } 4286 $parent = $parent->{'parent'}; 4287 } 4288 } 4289 4290 # complete the line if there was a user macro expansion 4291 if ($line !~ /\n/) { 4292 my ($new_line, $new_line_nr) = _new_line($self, $line_nr); 4293 $line .= $new_line if (defined($new_line)); 4294 } 4295 $misc = {'cmdname' => $command, 4296 'parent' => $current}; 4297 my $args = []; 4298 my $has_comment; 4299 if ($arg_spec eq 'lineraw' or $arg_spec eq 'skipline') { 4300 $args = [ $line ]; 4301 } elsif ($arg_spec eq 'special') { 4302 ($args, $has_comment) 4303 = _parse_special_misc_command($self, $line, $command, $line_nr); 4304 $misc->{'extra'}->{'arg_line'} = $line; 4305 } 4306 4307 # if using the @set txi* instead of a proper @-command, replace 4308 # by the tree obtained with the @-command. Even though 4309 # _end_line is called below, as $current is not line_arg 4310 # there should not be anything done in addition than what is 4311 # done for @clear or @set. 4312 if (($command eq 'set' or $command eq 'clear') 4313 and scalar(@$args) >= 1 4314 and $set_flag_command_equivalent{$args->[0]}) { 4315 my $arg; 4316 if ($command eq 'set') { 4317 $arg = 'on'; 4318 } else { 4319 $arg = 'off'; 4320 } 4321 $command = $set_flag_command_equivalent{$args->[0]}; 4322 $misc = {'cmdname' => $command, 4323 'parent' => $current, 4324 'line_nr' => $line_nr, 4325 'extra' => {'misc_args' => [$arg]}}; 4326 my $misc_line_args = {'type' => 'line_arg', 4327 'parent' => $misc}; 4328 $misc->{'args'} = [$misc_line_args]; 4329 $misc->{'extra'}->{'spaces_before_argument'} = ' '; 4330 $misc_line_args->{'contents'} = [ 4331 { 'text' => $arg, 4332 'parent' => $misc_line_args, }, 4333 { 'text' => "\n", 4334 'parent' => $misc_line_args, 4335 'type' => 'spaces_at_end', } ]; 4336 push @{$current->{'contents'}}, $misc; 4337 } else { 4338 if (!$ignored) { 4339 push @{$current->{'contents'}}, $misc; 4340 foreach my $arg (@$args) { 4341 push @{$misc->{'args'}}, 4342 { 'type' => 'misc_arg', 'text' => $arg, 4343 'parent' => $current->{'contents'}->[-1] }; 4344 } 4345 $misc->{'extra'}->{'misc_args'} = $args 4346 if (scalar(@$args) and $arg_spec ne 'skipline'); 4347 } else { 4348 $misc = undef; 4349 } 4350 } 4351 if ($command eq 'raisesections') { 4352 $self->{'sections_level'}++; 4353 } elsif ($command eq 'lowersections') { 4354 $self->{'sections_level'}--; 4355 } elsif ($command eq 'novalidate') { 4356 $self->{'info'}->{'novalidate'} = 1; 4357 } 4358 _register_global_command($self, $misc, $line_nr) 4359 if $misc; 4360 # the end of line is ignored for special commands 4361 if ($arg_spec ne 'special' or !$has_comment) { 4362 $current = _end_line($self, $current, $line_nr); 4363 } 4364 4365 last NEXT_LINE if ($command eq 'bye'); 4366 # Even if _end_line is called, it is not done since there is 4367 # no line_arg 4368 $current = _begin_preformatted($self, $current) 4369 if ($close_preformatted_commands{$command}); 4370 last; 4371 } else { 4372 # $arg_spec is text, line or a number 4373 # @item or @itemx in @table 4374 if ($command eq 'item' or $command eq 'itemx') { 4375 my $parent; 4376 print STDERR "ITEM_LINE\n" if ($self->{'DEBUG'}); 4377 if ($parent = _item_line_parent($current)) { 4378 $current = $parent; 4379 _gather_previous_item($self, $current, $command, $line_nr); 4380 } else { 4381 $self->line_error (sprintf(__( 4382 "\@%s outside of table or list"), $command), $line_nr); 4383 $current = _begin_preformatted($self, $current); 4384 } 4385 $misc = { 'cmdname' => $command, 'parent' => $current }; 4386 push @{$current->{'contents'}}, $misc; 4387 $misc->{'line_nr'} = $line_nr; 4388 } else { 4389 $misc = { 'cmdname' => $command, 'line_nr' => $line_nr }; 4390 if ($command eq 'subentry') { 4391 my $parent = $current->{'parent'}; 4392 if (!_is_index_element($self, $parent)) { 4393 $self->line_warn( 4394 sprintf(__("\@%s should only appear in an index entry"), 4395 $command), $line_nr); 4396 } 4397 $parent->{'extra'}->{'subentry'} = $misc; 4398 my $subentry_level = 1; 4399 if ($parent->{'cmdname'} eq 'subentry') { 4400 $subentry_level = $parent->{'extra'}->{'level'} + 1; 4401 } 4402 $misc->{'extra'}->{'level'} = $subentry_level; 4403 if ($subentry_level > 2) { 4404 $self->line_error(__( 4405 "no more than two levels of index subentry are allowed"), 4406 $line_nr); 4407 } 4408 # Do not make the @subentry element a child of the index 4409 # command. This means that spaces are preserved properly 4410 # when converting back to Texinfo. 4411 $current = _end_line($self, $current, $line_nr); 4412 } 4413 push @{$current->{'contents'}}, $misc; 4414 $misc->{'parent'} = $current; 4415 if ($sectioning_commands{$command}) { 4416 if ($self->{'sections_level'}) { 4417 $current->{'contents'}->[-1]->{'extra'}->{'sections_level'} 4418 = $self->{'sections_level'}; 4419 } 4420 } 4421 if ($root_commands{$command}) { 4422 $misc->{'contents'} = []; 4423 } 4424 # def*x 4425 if ($def_commands{$command}) { 4426 my $base_command = $command; 4427 $base_command =~ s/x$//; 4428 # check that the def*x is first after @def*, no paragraph 4429 # in-between. 4430 my $after_paragraph = _check_no_text($current); 4431 push @{$self->{'context_stack'}}, 'def'; 4432 $current->{'contents'}->[-1]->{'type'} = 'def_line'; 4433 $current->{'contents'}->[-1]->{'extra'} = 4434 {'def_command' => $base_command, 4435 'original_def_cmdname' => $command}; 4436 if ($current->{'cmdname'} 4437 and $current->{'cmdname'} eq $base_command) { 4438 pop @{$current->{'contents'}}; 4439 _gather_def_item($current, $command); 4440 push @{$current->{'contents'}}, $misc; 4441 } 4442 if (!$current->{'cmdname'} 4443 or $current->{'cmdname'} ne $base_command 4444 or $after_paragraph) { 4445 $self->line_error(sprintf(__( 4446 "must be after `\@%s' to use `\@%s'"), 4447 $base_command, $command), $line_nr); 4448 $current->{'contents'}->[-1]->{'extra'}->{'not_after_command'} = 1; 4449 } 4450 } 4451 } 4452 $current = $current->{'contents'}->[-1]; 4453 $current->{'args'} = [{ 'type' => 'line_arg', 4454 'contents' => [], 4455 'parent' => $current }]; 4456 # @node is the only misc command with args separated with comma 4457 # FIXME a 3 lingering here deep into the code may not 4458 # be very wise... However having a hash only for one @-command 4459 # is not very appealing either... 4460 if ($command eq 'node') { 4461 $current->{'remaining_args'} = 3; 4462 } elsif ($command eq 'author') { 4463 my $parent = $current; 4464 my $found; 4465 while ($parent->{'parent'}) { 4466 $parent = $parent->{'parent'}; 4467 last if ($parent->{'type'} 4468 and $parent->{'type'} eq 'brace_command_context'); 4469 if ($parent->{'cmdname'}) { 4470 if ($parent->{'cmdname'} eq 'titlepage') { 4471 $current->{'extra'}->{'titlepage'} = $parent; 4472 $found = 1; 4473 } elsif ($parent->{'cmdname'} eq 'quotation' or 4474 $parent->{'cmdname'} eq 'smallquotation') { 4475 push @{$parent->{'extra'}->{'authors'}}, $current; 4476 $current->{'extra'}->{'quotation'} = $parent; 4477 $found = 1; 4478 } 4479 last if ($found); 4480 } 4481 } 4482 if (!$found) { 4483 $self->line_warn(sprintf(__( 4484 "\@%s not meaningful outside `\@titlepage' and `\@quotation' environments"), 4485 $command), $current->{'line_nr'}); 4486 } 4487 } elsif ($command eq 'dircategory' and $self->{'current_node'}) { 4488 $self->line_warn(__("\@dircategory after first node"), 4489 $line_nr); 4490 } elsif ($command eq 'printindex') { 4491 # Record that @printindex occurs in this node so we know it 4492 # is an index node. 4493 if ($self->{'current_node'}) { 4494 $self->{'current_node'}->{'extra'}->{'isindex'} = 1; 4495 } 4496 } 4497 4498 $current = $current->{'args'}->[-1]; 4499 push @{$self->{'context_stack'}}, 'line' 4500 unless ($def_commands{$command}); 4501 $line = _start_empty_line_after_command($line, $current, $misc); 4502 } 4503 _register_global_command($self, $misc, $line_nr) 4504 if $misc; 4505 if ($command eq 'dircategory') { 4506 push @{$self->{'info'}->{'dircategory_direntry'}}, $misc; 4507 } 4508 # @-command with matching @end opening 4509 } elsif (exists($block_commands{$command})) { 4510 if ($command eq 'macro' or $command eq 'rmacro') { 4511 my $macro = _parse_macro_command_line($self, $command, $line, 4512 $current, $line_nr); 4513 push @{$current->{'contents'}}, $macro; 4514 $current = $current->{'contents'}->[-1]; 4515 last; 4516 } elsif ($block_commands{$command} eq 'conditional') { 4517 my $ifvalue_true = 0; 4518 if ($command eq 'ifclear' or $command eq 'ifset') { 4519 # REVALUE 4520 if ($line =~ /^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) { 4521 my $name = $1; 4522 if ((exists($self->{'values'}->{$name}) and $command eq 'ifset') 4523 or (!exists($self->{'values'}->{$name}) 4524 and $command eq 'ifclear')) { 4525 $ifvalue_true = 1; 4526 } 4527 print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n" if ($self->{'DEBUG'}); 4528 } elsif ($line !~ /\S/) { 4529 $self->line_error(sprintf( 4530 __("%c%s requires a name"), ord('@'), $command), $line_nr); 4531 } else { 4532 $self->line_error(sprintf( 4533 __("bad name for \@%s"), $command), $line_nr); 4534 } 4535 } elsif ($command eq 'ifcommanddefined' 4536 or $command eq 'ifcommandnotdefined') { 4537 # REMACRO 4538 if ($line =~ /^\s+([[:alnum:]][[:alnum:]\-]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) { 4539 my $name = $1; 4540 my $command_is_defined = ( 4541 exists($Texinfo::Common::all_commands{$name}) 4542 or $self->{'macros'}->{$name} 4543 or $self->{'definfoenclose'}->{$name} 4544 or $self->{'aliases'}->{$name} 4545 or $self->{'command_index'}->{$name} 4546 ); 4547 if (($command_is_defined 4548 and $command eq 'ifcommanddefined') 4549 or (! $command_is_defined 4550 and $command eq 'ifcommandnotdefined')) { 4551 $ifvalue_true = 1; 4552 } 4553 print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n" if ($self->{'DEBUG'}); 4554 } elsif ($line !~ /\S/) { 4555 $self->line_error(sprintf( 4556 __("%c%s requires a name"), ord('@'), $command), $line_nr); 4557 } else { 4558 $self->line_error(sprintf( 4559 __("bad name for \@%s"), $command), $line_nr); 4560 } 4561 } elsif ($command =~ /^ifnot(.*)/) { 4562 $ifvalue_true = 1 if !($self->{'expanded_formats_hash'}->{$1} 4563 # exception as explained in the texinfo manual 4564 or ($1 eq 'info' 4565 and $self->{'expanded_formats_hash'}->{'plaintext'})); 4566 print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n" if ($self->{'DEBUG'}); 4567 } else { 4568 die unless ($command =~ /^if(.*)/); 4569 $ifvalue_true = 1 if ($self->{'expanded_formats_hash'}->{$1} 4570 or ($1 eq 'info' 4571 and $self->{'expanded_formats_hash'}->{'plaintext'})); 4572 print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n" if ($self->{'DEBUG'}); 4573 } 4574 if ($ifvalue_true) { 4575 push @{$self->{'conditionals_stack'}}, $command; 4576 } else { 4577 push @{$current->{'contents'}}, { 'cmdname' => $command, 4578 'parent' => $current, 4579 'contents' => [] }; 4580 $current = $current->{'contents'}->[-1]; 4581 } 4582 # FIXME(Karl) ignore what is remaining on the line, to eat 4583 # the end of line? 4584 last; 4585 } else { 4586 my $block; 4587 # a menu command closes a menu_comment, but not the other 4588 # block commands. This won't catch menu commands buried in 4589 # other formats (that are incorrect anyway). 4590 if ($menu_commands{$command} and $current->{'type'} 4591 and ($current->{'type'} eq 'menu_comment' 4592 or $current->{'type'} eq 'menu_entry_description')) { 4593 4594 my $menu; 4595 4596 $menu = $current->{'parent'}; 4597 pop @{$menu->{'contents'}} 4598 if (!@{$current->{'contents'}}); 4599 4600 my $context = pop @{$self->{'context_stack'}}; 4601 if ($context ne 'preformatted') { 4602 $self->_bug_message("context $context instead of preformatted in new menu", 4603 $line_nr, $current); 4604 } 4605 4606 if ($menu->{'type'} and $menu->{'type'} eq 'menu_entry') { 4607 $menu = $menu->{'parent'}; 4608 } 4609 4610 $current = $menu; 4611 } 4612 # the def command holds a line_def* which corresponds with the 4613 # definition line. This allows to have a treatement similar 4614 # with def*x. 4615 if ($def_commands{$command}) { 4616 push @{$self->{'context_stack'}}, 'def'; 4617 $block = { 'parent' => $current, 4618 'cmdname' => $command, 4619 'contents' => [] }; 4620 push @{$current->{'contents'}}, $block; 4621 $current = $current->{'contents'}->[-1]; 4622 push @{$current->{'contents'}}, { 4623 'type' => 'def_line', 4624 'parent' => $current, 4625 'line_nr' => $line_nr, 4626 'extra' => 4627 {'def_command' => $command, 4628 'original_def_cmdname' => $command} 4629 }; 4630 } else { 4631 $block = { 'cmdname' => $command, 4632 'parent' => $current, 4633 'contents' => [] }; 4634 push @{$current->{'contents'}}, $block; 4635 } 4636 $current = $current->{'contents'}->[-1]; 4637 4638 if ($block_arg_commands{$command}) { 4639 if ($preformatted_commands{$command}) { 4640 push @{$self->{'context_stack'}}, 'preformatted'; 4641 } elsif ($math_commands{$command}) { 4642 push @{$self->{'context_stack'}}, 'math'; 4643 } elsif ($format_raw_commands{$command}) { 4644 push @{$self->{'context_stack'}}, 'rawpreformatted'; 4645 if (not $self->{'expanded_formats_hash'}->{$command}) { 4646 push @{$current->{'contents'}}, { 4647 'parent' => $current, 4648 'type' => 'elided_block', 4649 'contents' => [] 4650 }; 4651 while (not $line =~ /^\s*\@end\s+$command/) { 4652 ($line, $line_nr) = _new_line($self, $line_nr); 4653 if (!$line) { 4654 # unclosed block 4655 $line = ''; 4656 last; 4657 } 4658 } 4659 push @{$current->{'contents'}}, 4660 { 'type' => 'empty_line_after_command', 4661 'text' => "\n", 4662 'parent' => $current }; 4663 push @{$current->{'contents'}}, { 'type' => 'empty_line', 4664 'text' => '', 4665 'parent' => $current }; 4666 next; 4667 } 4668 } 4669 if ($region_commands{$command}) { 4670 if (@{$self->{'regions_stack'}}) { 4671 $self->line_error( 4672 sprintf(__("region %s inside region %s is not allowed"), 4673 $command, $self->{'regions_stack'}->[-1]->{'cmdname'}), 4674 $line_nr); 4675 } 4676 push @{$self->{'regions_stack'}}, $block; 4677 } 4678 if ($menu_commands{$command}) { 4679 if ($self->{'context_stack'}->[-1] eq 'preformatted') { 4680 push @{$self->{'context_stack'}}, 'preformatted'; 4681 } else { 4682 push @{$self->{'context_stack'}}, 'menu'; 4683 } 4684 push @{$self->{'info'}->{'dircategory_direntry'}}, $block 4685 if ($command eq 'direntry'); 4686 if ($self->{'current_node'}) { 4687 if ($command eq 'direntry') { 4688 if ($self->{'FORMAT_MENU'} eq 'menu') { 4689 $self->line_warn(__("\@direntry after first node"), 4690 $line_nr); 4691 } 4692 } elsif ($command eq 'menu') { 4693 if (!(defined $current->{'parent'}->{'cmdname'}) 4694 or $root_commands{$current->{'parent'}->{'cmdname'}}) { 4695 push @{$self->{'current_node'}->{'menus'}}, $current; 4696 } else { 4697 $self->line_warn(__("\@menu in invalid context"), 4698 $line_nr); 4699 } 4700 } 4701 } 4702 } 4703 $current->{'args'} = [ { 4704 'type' => 'block_line_arg', 4705 'contents' => [], 4706 'parent' => $current } ]; 4707 4708 if ($block_commands{$command} =~ /^\d+$/ 4709 and $block_commands{$command} - 1 > 0) { 4710 $current->{'remaining_args'} = $block_commands{$command} - 1; 4711 } elsif ($block_commands{$command} eq 'variadic') { 4712 $current->{'remaining_args'} = -1; # unlimited args 4713 } 4714 $current = $current->{'args'}->[-1]; 4715 push @{$self->{'context_stack'}}, 'line' 4716 unless ($def_commands{$command}); 4717 } 4718 $block->{'line_nr'} = $line_nr; 4719 _register_global_command($self, $block, $line_nr); 4720 4721 $line = _start_empty_line_after_command($line, $current, $block); 4722 } 4723 } elsif (defined($brace_commands{$command})) { 4724 push @{$current->{'contents'}}, { 'cmdname' => $command, 4725 'parent' => $current, 4726 'contents' => [] }; 4727 $current->{'contents'}->[-1]->{'line_nr'} = $line_nr 4728 if ($keep_line_nr_brace_commands{$command} 4729 and !$self->{'definfoenclose'}->{$command}); 4730 if ($in_index_commands{$command} 4731 and !_is_index_element($self, $current->{'parent'})) { 4732 $self->line_warn( 4733 sprintf(__("\@%s should only appear in an index entry"), 4734 $command), $line_nr); 4735 } 4736 4737 $current = $current->{'contents'}->[-1]; 4738 if ($command eq 'click') { 4739 $current->{'extra'}->{'clickstyle'} = $self->{'clickstyle'}; 4740 } elsif ($command eq 'kbd') { 4741 if ($self->{'context_stack'}->[-1] eq 'preformatted' 4742 and $self->{'kbdinputstyle'} ne 'distinct') { 4743 $current->{'extra'}->{'code'} = 1; 4744 } elsif ($self->{'kbdinputstyle'} eq 'code' 4745 or ($self->{'kbdinputstyle'} eq 'example' 4746 and $self->_in_code($current->{'parent'}))) { 4747 $current->{'extra'}->{'code'} = 1; 4748 } 4749 } 4750 if ($self->{'definfoenclose'}->{$command}) { 4751 $current->{'type'} = 'definfoenclose_command'; 4752 $current->{'extra'}->{'begin'} = 4753 $self->{'definfoenclose'}->{$command}->[0]; 4754 $current->{'extra'}->{'end'} = 4755 $self->{'definfoenclose'}->{$command}->[1]; 4756 } 4757 } elsif (exists ($no_brace_commands{$command})) { 4758 push @{$current->{'contents'}}, 4759 { 'cmdname' => $command, 'parent' => $current }; 4760 # FIXME generalize? 4761 if ($command eq '\\' and $self->{'context_stack'}->[-1] ne 'math') { 4762 $self->line_warn(sprintf(__("\@%s should only appear in math context"), 4763 $command), $line_nr); 4764 } 4765 if ($command eq "\n") { 4766 $current = _end_line($self, $current, $line_nr); 4767 last; 4768 } 4769 } 4770 } elsif ($separator_match) { 4771 my $separator = $separator_match; 4772 substr ($line, 0, 1) = ''; 4773 print STDERR "SEPARATOR: $separator\n" if ($self->{'DEBUG'}); 4774 if ($separator eq '@') { 4775 # this may happen with a @ at the very end of a file, therefore 4776 # not followed by anything. 4777 $self->line_error(__("unexpected \@"), $line_nr); 4778 } elsif ($separator eq '{') { 4779 _abort_empty_line($self, $current); 4780 if ($current->{'cmdname'} 4781 and defined($brace_commands{$current->{'cmdname'}})) { 4782 my $command = $current->{'cmdname'}; 4783 $current->{'args'} = [ { 'parent' => $current, 4784 'contents' => [] } ]; 4785 4786 if ($brace_commands{$command} 4787 and $brace_commands{$command} =~ /^\d$/ 4788 and $brace_commands{$command} > 1) { 4789 $current->{'remaining_args'} = $brace_commands{$command} - 1; 4790 } 4791 4792 $current = $current->{'args'}->[-1]; 4793 if ($context_brace_commands{$command}) { 4794 if ($command eq 'caption' or $command eq 'shortcaption') { 4795 my $float; 4796 if (!$current->{'parent'}->{'parent'} 4797 or !$current->{'parent'}->{'parent'}->{'cmdname'} 4798 or $current->{'parent'}->{'parent'}->{'cmdname'} ne 'float') { 4799 $float = $current->{'parent'}; 4800 while ($float->{'parent'} and !($float->{'cmdname'} 4801 and $float->{'cmdname'} eq 'float')) { 4802 $float = $float->{'parent'}; 4803 } 4804 if (!($float->{'cmdname'} and $float->{'cmdname'} eq 'float')) { 4805 $self->line_error(sprintf(__( 4806 "\@%s is not meaningful outside `\@float' environment"), 4807 $command), $line_nr); 4808 $float = undef; 4809 } else { 4810 $self->line_warn(sprintf(__( 4811 "\@%s should be right below `\@float'"), 4812 $command), $line_nr); 4813 } 4814 } else { 4815 $float = $current->{'parent'}->{'parent'}; 4816 } 4817 if ($float) { 4818 if ($float->{'extra'}->{$command}) { 4819 $self->line_warn(sprintf(__("ignoring multiple \@%s"), 4820 $command), $line_nr); 4821 } else { 4822 $current->{'parent'}->{'extra'}->{'float'} = $float; 4823 $float->{'extra'}->{$command} = $current->{'parent'}; 4824 } 4825 } 4826 } 4827 if ($math_commands{$command}) { 4828 push @{$self->{'context_stack'}}, 'math'; 4829 } else { 4830 push @{$self->{'context_stack'}}, $command; 4831 } 4832 $line =~ s/([^\S\f\n]*)//; 4833 $current->{'type'} = 'brace_command_context'; 4834 push @{$current->{'contents'}}, { 'type' => 'empty_spaces_before_argument', 4835 'text' => $1, 4836 'parent' => $current, 4837 'extra' => {'command' => $current->{'parent'}} 4838 }; 4839 } else { 4840 $current->{'type'} = 'brace_command_arg'; 4841 if ($brace_commands{$command} 4842 and $brace_commands{$command} =~ /^\d$/ 4843 and $brace_commands{$command} > 0) { 4844 push @{$current->{'contents'}}, 4845 {'type' => 'empty_spaces_before_argument', 4846 'text' => '', 4847 'parent' => $current, 4848 'extra' => {'command' => $current} 4849 }; 4850 } 4851 push @{$self->{'context_stack'}}, $command 4852 if ($command eq 'inlineraw'); 4853 } 4854 print STDERR "OPENED \@$current->{'parent'}->{'cmdname'}, remaining: " 4855 .(defined($current->{'parent'}->{'remaining_args'}) ? "remaining: $current->{'parent'}->{'remaining_args'}, " : '') 4856 .($current->{'type'} ? "type: $current->{'type'}" : '')."\n" 4857 if ($self->{'DEBUG'}); 4858 } elsif ($current->{'parent'} 4859 and (($current->{'parent'}->{'cmdname'} 4860 and $current->{'parent'}->{'cmdname'} eq 'multitable') 4861 or ($current->{'parent'}->{'type'} 4862 and $current->{'parent'}->{'type'} eq 'def_line'))) { 4863 push @{$current->{'contents'}}, 4864 { 'type' => 'bracketed', 'contents' => [], 4865 'parent' => $current }; 4866 $current = $current->{'contents'}->[-1]; 4867 # we need the line number here in case @ protects end of line 4868 $current->{'line_nr'} = $line_nr 4869 if ($current->{'parent'}->{'parent'}->{'type'} 4870 and $current->{'parent'}->{'parent'}->{'type'} eq 'def_line'); 4871 push @{$current->{'contents'}}, 4872 {'type' => 'empty_spaces_before_argument', 4873 'text' => '', 4874 'parent' => $current, 4875 'extra' => {'command' => $current} 4876 }; 4877 print STDERR "BRACKETED in def/multitable\n" if ($self->{'DEBUG'}); 4878 # lone braces accepted right in a rawpreformatted 4879 } elsif ($current->{'type'} 4880 and $current->{'type'} eq 'rawpreformatted') { 4881 push @{$current->{'contents'}}, {'text' => '{', 4882 'parent' => $current }; 4883 # matching braces accepted in a rawpreformatted or math or ignored 4884 # code 4885 } elsif ($self->{'context_stack'}->[-1] eq 'math' 4886 or $self->{'context_stack'}->[-1] eq 'rawpreformatted' 4887 or $self->{'context_stack'}->[-1] eq 'inlineraw') { 4888 push @{$current->{'contents'}}, 4889 { 'type' => 'bracketed', 'contents' => [], 4890 'parent' => $current, 'line_nr' => $line_nr }; 4891 $current = $current->{'contents'}->[-1]; 4892 print STDERR "BRACKETED in math\n" if ($self->{'DEBUG'}); 4893 } else { 4894 $self->line_error(sprintf(__("misplaced %c"), 4895 ord('{')), $line_nr); 4896 } 4897 4898 } elsif ($separator eq '}') { 4899 _abort_empty_line($self, $current); 4900 if ($current->{'type'} and ($current->{'type'} eq 'bracketed')) { 4901 $current = $current->{'parent'}; 4902 # the following will not happen for footnote if there is 4903 # a paragraph withing the footnote 4904 } elsif ($current->{'parent'} 4905 and $current->{'parent'}->{'cmdname'} 4906 and exists $brace_commands{$current->{'parent'}->{'cmdname'}}) { 4907 # for math and footnote out of paragraph 4908 if ($context_brace_commands{$current->{'parent'}->{'cmdname'}}) { 4909 my $top_context = pop @{$self->{'context_stack'}}; 4910 my $command_context = $current->{'parent'}->{'cmdname'}; 4911 if ($math_commands{$current->{'parent'}->{'cmdname'}}) { 4912 $command_context = 'math'; 4913 } 4914 if ($top_context ne $command_context) { 4915 $self->_bug_message("context $top_context instead of brace command $current->{'parent'}->{'cmdname'} context $command_context", 4916 $line_nr, $current); 4917 die; 4918 } 4919 } 4920 # first is the arg. 4921 4922 if ($brace_commands{$current->{'parent'}->{'cmdname'}} 4923 and $brace_commands{$current->{'parent'}{'cmdname'}} =~ /^\d$/ 4924 and $brace_commands{$current->{'parent'}->{'cmdname'}} > 0 4925 and $current->{'parent'}->{'cmdname'} ne 'math') { 4926 # @inline* always have end spaces considered as normal text 4927 _isolate_last_space($self, $current) 4928 unless ($inline_commands{$current->{'parent'}->{'cmdname'}}); 4929 } 4930 my $closed_command = $current->{'parent'}->{'cmdname'}; 4931 print STDERR "CLOSING(brace) \@$current->{'parent'}->{'cmdname'}\n" 4932 if ($self->{'DEBUG'}); 4933 delete $current->{'parent'}->{'remaining_args'}; 4934 if (defined($brace_commands{$closed_command}) 4935 and $brace_commands{$closed_command} eq '0' 4936 and @{$current->{'contents'}}) { 4937 $self->line_warn(sprintf(__( 4938 "command \@%s does not accept arguments"), 4939 $closed_command), $line_nr); 4940 } 4941 if ($current->{'parent'}->{'cmdname'} eq 'anchor') { 4942 $current->{'parent'}->{'line_nr'} = $line_nr; 4943 my $parsed_anchor = _parse_node_manual($current); 4944 if (_check_node_label($self, $parsed_anchor, 4945 $current->{'parent'}->{'cmdname'}, $line_nr)) { 4946 _register_label($self, $current->{'parent'}, $parsed_anchor); 4947 if (@{$self->{'regions_stack'}}) { 4948 $current->{'extra'}->{'region'} = $self->{'regions_stack'}->[-1]; 4949 } 4950 } 4951 } elsif ($ref_commands{$current->{'parent'}->{'cmdname'}}) { 4952 my $ref = $current->{'parent'}; 4953 if (@{$ref->{'args'}}) { 4954 my @args; 4955 for $a (@{$ref->{'args'}}) { 4956 if (@{$a->{'contents'}}) { 4957 push @args, $a->{'contents'}; 4958 } else { 4959 push @args, undef; 4960 } 4961 } 4962 if (($closed_command eq 'inforef' 4963 and !defined($args[0]) and !defined($args[2])) 4964 or ($closed_command ne 'inforef' 4965 and !defined($args[0]) and !defined($args[3]) 4966 and !defined($args[4]))) { 4967 $self->line_warn(sprintf(__( 4968 "command \@%s missing a node or external manual argument"), 4969 $closed_command), $line_nr); 4970 } else { 4971 my $parsed_ref_node = _parse_node_manual($ref->{'args'}->[0]); 4972 if (defined $parsed_ref_node) { 4973 if ($closed_command ne 'inforef' 4974 and !defined($args[3]) and !defined($args[4]) 4975 and !$parsed_ref_node->{'manual_content'}) { 4976 push @{$self->{'internal_references'}}, $ref; 4977 } 4978 $ref->{'extra'}->{'node_argument'} = $parsed_ref_node 4979 } 4980 } 4981 if (defined($args[1])) { 4982 my $normalized_cross_ref_name = 4983 Texinfo::Convert::NodeNameNormalization::normalize_node( 4984 {'contents' => $args[1]}); 4985 if ($normalized_cross_ref_name !~ /[^-]/) { 4986 $self->line_warn(sprintf(__( 4987 "in \@%s empty cross reference name after expansion `%s'"), 4988 $closed_command, 4989 Texinfo::Convert::Texinfo::convert({'contents' => $args[1]})), 4990 $line_nr); 4991 } 4992 } 4993 if ($closed_command ne 'inforef' and defined($args[2])) { 4994 my $normalized_cross_ref_title = 4995 Texinfo::Convert::NodeNameNormalization::normalize_node({'contents' => $args[2]}); 4996 if ($normalized_cross_ref_title !~ /[^-]/) { 4997 $self->line_warn(sprintf(__( 4998 "in \@%s empty cross reference title after expansion `%s'"), 4999 $closed_command, 5000 Texinfo::Convert::Texinfo::convert({'contents' => $args[2]})), 5001 $line_nr); 5002 } 5003 } 5004 } 5005 } elsif ($current->{'parent'}->{'cmdname'} eq 'image') { 5006 my $image = $current->{'parent'}; 5007 if (!@{$image->{'args'}} 5008 or !defined($image->{'args'}->[0]) 5009 or scalar(@{$image->{'args'}->[0]->{'contents'}}) == 0) { 5010 $self->line_error( 5011 __("\@image missing filename argument"), $line_nr); 5012 } 5013 $image->{'extra'}->{'input_perl_encoding'} 5014 = $self->{'info'}->{'input_perl_encoding'} 5015 if defined $self->{'info'}->{'input_perl_encoding'}; 5016 } elsif($current->{'parent'}->{'cmdname'} eq 'dotless') { 5017 my $dotless = $current->{'parent'}; 5018 if (@{$current->{'contents'}}) { 5019 my $text = $current->{'contents'}->[0]->{'text'}; 5020 if (!defined ($text) 5021 or ($text ne 'i' and $text ne 'j')) { 5022 $self->line_error(sprintf( 5023 __("%c%s expects `i' or `j' as argument, not `%s'"), 5024 ord('@'), $dotless->{'cmdname'}, 5025 Texinfo::Convert::Texinfo::convert($current)), $line_nr); 5026 } 5027 } 5028 } elsif ($explained_commands{$current->{'parent'}->{'cmdname'}} 5029 or $inline_commands{$current->{'parent'}->{'cmdname'}}) { 5030 my $current_command = $current->{'parent'}; 5031 if ($inline_commands{$current_command->{'cmdname'}}) { 5032 if ($current_command->{'cmdname'} eq 'inlineraw') { 5033 my $context_command = pop @{$self->{'context_stack'}}; 5034 if ($context_command ne $current_command->{'cmdname'}) { 5035 $self->_bug_message("context $context_command instead of inlineraw $current_command->{'cmdname'}", 5036 $line_nr, $current); 5037 die; 5038 } 5039 } 5040 } 5041 if (!@{$current_command->{'args'}} 5042 or !defined($current_command->{'args'}->[0]) 5043 or scalar(@{$current_command->{'args'}->[0]->{'contents'}}) == 0) { 5044 $self->line_warn( 5045 sprintf(__("\@%s missing first argument"), 5046 $current_command->{'cmdname'}), $line_nr); 5047 } 5048 } elsif ($current->{'parent'}->{'cmdname'} eq 'errormsg') { 5049 my $error_message_text = $current->{'contents'}->[0]->{'text'}; 5050 $self->line_error($error_message_text, $line_nr) 5051 if $error_message_text; 5052 } elsif ($current->{'parent'}->{'cmdname'} eq 'U') { 5053 my $arg; 5054 if ($current->{'contents'}->[0]) { 5055 $arg = $current->{'contents'}->[0]->{'text'}; 5056 } 5057 if (!defined($arg) || !$arg) { 5058 $self->line_warn(__("no argument specified for \@U"), 5059 $line_nr); 5060 5061 } elsif ($arg !~ /^[0-9A-Fa-f]+$/) { 5062 $self->line_error( 5063 sprintf(__("non-hex digits in argument for \@U: %s"), $arg), 5064 $line_nr); 5065 5066 } elsif (length ($arg) < 4) { 5067 # Perl doesn't mind, but too much trouble to do in TeX. 5068 $self->line_warn(sprintf(__("fewer than four hex digits in argument for \@U: %s"), $arg), 5069 $line_nr); 5070 5071 } else { 5072 # we don't want to call hex at all if the value isn't 5073 # going to fit; so first use eval to check. 5074 # Since integer overflow is only a warning, have to make 5075 # warnings fatal for the eval to be effective. 5076 eval qq!use warnings FATAL => qw(all); hex("$arg")!; 5077 if ($@) { 5078 # leave clue in case something else went wrong. 5079 warn "\@U hex($arg) eval failed: $@\n" if ($self->{'DEBUG'}); 5080 # argument likely exceeds size of integer 5081 } 5082 # ok, value can be given to hex(), so try it. 5083 if ($@ or hex($arg) > 0x10FFFF) { 5084 $self->line_error( 5085 sprintf(__("argument for \@U exceeds Unicode maximum 0x10FFFF: %s"), 5086 $arg), 5087 $line_nr); 5088 } 5089 } 5090 5091 } elsif (_command_with_command_as_argument($current->{'parent'}->{'parent'}) 5092 and scalar(@{$current->{'contents'}}) == 0) { 5093 print STDERR "FOR PARENT \@$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'} command_as_argument braces $current->{'cmdname'}\n" if ($self->{'DEBUG'}); 5094 $current->{'parent'}->{'type'} = 'command_as_argument' 5095 if (!$current->{'parent'}->{'type'}); 5096 $current->{'parent'}->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'} 5097 = $current->{'parent'}; 5098 } elsif ($in_index_commands{$current->{'parent'}->{'cmdname'}}) { 5099 my $command = $current->{'parent'}->{'cmdname'}; 5100 5101 my $index_element = $current->{'parent'}->{'parent'}->{'parent'}; 5102 if ($index_element 5103 and _is_index_element($self, $index_element)) { 5104 if ($command eq 'sortas') { 5105 my ($arg, $superfluous_arg) = _convert_to_text($current); 5106 if (defined($arg)) { 5107 $index_element->{'extra'}->{$command} = $arg; 5108 } 5109 } else { 5110 $index_element->{'extra'}->{$command} = $current->{'parent'}; 5111 } 5112 } 5113 } 5114 _register_global_command($self, $current->{'parent'}, $line_nr); 5115 if ($command_ignore_space_after{$current->{'parent'}->{'cmdname'}}) { 5116 push @{$current->{'parent'}->{'parent'}->{'contents'}}, 5117 {'type' => 'empty_spaces_after_close_brace', 5118 'text' => '', 5119 'parent' => $current->{'parent'}->{'parent'} 5120 }; 5121 } 5122 $current = $current->{'parent'}->{'parent'}; 5123 $current = _begin_preformatted ($self, $current) 5124 if ($close_preformatted_commands{$closed_command}); 5125 # lone braces accepted right in a rawpreformatted 5126 } elsif ($current->{'type'} 5127 and $current->{'type'} eq 'rawpreformatted') { 5128 push @{$current->{'contents'}}, {'text' => '}', 5129 'parent' => $current }; 5130 # footnote caption closing, when there is a paragraph inside. 5131 } elsif ($context_brace_commands{$self->{'context_stack'}->[-1]}) { 5132 # closing the context under broader situations 5133 $current = _end_paragraph($self, $current, $line_nr); 5134 if ($current->{'parent'} 5135 and $current->{'parent'}->{'cmdname'} 5136 and $context_brace_commands{$current->{'parent'}->{'cmdname'}}) { 5137 # and $current->{'parent'}->{'cmdname'} eq $self->{'context_stack'}->[-1]) { 5138 my $top_context = pop @{$self->{'context_stack'}}; 5139 my $command_context = $current->{'parent'}->{'cmdname'}; 5140 if ($math_commands{$current->{'parent'}->{'cmdname'}}) { 5141 $command_context = 'math'; 5142 } 5143 if ($top_context ne $command_context) { 5144 $self->_bug_message("context $top_context instead of brace isolated $current->{'parent'}->{'cmdname'} context $command_context", 5145 $line_nr, $current); 5146 die; 5147 } 5148 print STDERR "CLOSING(context command) \@$current->{'parent'}->{'cmdname'}\n" if ($self->{'DEBUG'}); 5149 my $closed_command = $current->{'parent'}->{'cmdname'}; 5150 _register_global_command($self, $current->{'parent'}, $line_nr); 5151 $current = $current->{'parent'}->{'parent'}; 5152 $current = _begin_preformatted ($self, $current) 5153 if ($close_preformatted_commands{$closed_command}); 5154 } 5155 } else { 5156 $self->line_error(sprintf(__("misplaced %c"), 5157 ord('}')), $line_nr); 5158 } 5159 } elsif ($separator eq ',' 5160 and $current->{'parent'}->{'remaining_args'}) { 5161 _abort_empty_line ($self, $current); 5162 _isolate_last_space($self, $current); 5163 my $type = $current->{'type'}; 5164 $current = $current->{'parent'}; 5165 if ($inline_commands{$current->{'cmdname'}}) { 5166 my $expandp = 0; 5167 if (! $current->{'extra'}->{'format'}) { 5168 my $inline_type; 5169 if (defined $current->{'args'}->[0] 5170 and @{$current->{'args'}->[0]->{'contents'}}) { 5171 $inline_type = $current->{'args'}->[0]->{'contents'}->[0]->{'text'}; 5172 } 5173 5174 if (!$inline_type) { 5175 # condition is missing for some reason 5176 print STDERR "INLINE COND MISSING\n" 5177 if ($self->{'DEBUG'}); 5178 } elsif ($inline_format_commands{$current->{'cmdname'}}) { 5179 if ($self->{'expanded_formats_hash'}->{$inline_type}) { 5180 $expandp = 1; 5181 $current->{'extra'}->{'expand_index'} = 1; 5182 } else { 5183 $expandp = 0; 5184 } 5185 } elsif (($current->{'cmdname'} eq 'inlineifset' 5186 and exists($self->{'values'}->{$inline_type})) 5187 or ($current->{'cmdname'} eq 'inlineifclear' 5188 and ! exists($self->{'values'}->{$inline_type}))) { 5189 $expandp = 1; 5190 $current->{'extra'}->{'expand_index'} = 1; 5191 } else { 5192 $expandp = 0; 5193 } 5194 $current->{'extra'}->{'format'} = $inline_type; 5195 5196 # Skip first argument for a false @inlinefmtifelse 5197 if (!$expandp and $current->{'cmdname'} eq 'inlinefmtifelse') { 5198 $current->{'extra'}->{'expand_index'} = 2; 5199 5200 # Add a dummy argument for the first argument. 5201 push @{$current->{'args'}}, {'type' => 'elided', 5202 'parent' => $current, 5203 'contents' => []}; 5204 5205 # Scan forward to get the next argument. 5206 my $brace_count = 1; 5207 while ($brace_count > 0) { 5208 # Forward to next comma or brace 5209 if ($line =~ s/[^{,}]*([,{}])//) { 5210 if ($1 eq ',' and $brace_count == 1) { 5211 last; 5212 } elsif ($1 eq '{') { 5213 $brace_count++; 5214 } elsif ($1 eq '}') { 5215 $brace_count--; 5216 } 5217 } else { 5218 my $new_text; 5219 ($new_text, $line_nr) = _next_text($self, $line_nr); 5220 if (!$new_text) { 5221 next NEXT_LINE; # error - unbalanced brace 5222 } 5223 $line .= $new_text; 5224 } 5225 } 5226 if ($brace_count == 0) { 5227 # second arg missing 5228 $line = '}' . $line; 5229 } 5230 $current->{'remaining_args'}--; 5231 $expandp = 1; 5232 } 5233 } elsif ($current->{'cmdname'} eq 'inlinefmtifelse') { 5234 # Second arg of @inlinefmtifelse when condition is true. 5235 # Discard second argument. 5236 $expandp = 0; 5237 } 5238 # If this command is not being expanded, add a dummy argument, 5239 # and scan forward to the closing brace. 5240 if (!$expandp) { 5241 push @{$current->{'args'}}, {'type' => 'elided', 5242 'parent' => $current, 5243 'contents' => []}; 5244 my $brace_count = 1; 5245 while ($brace_count > 0) { 5246 if ($line =~ s/[^{}]*([{}])//) { 5247 if ($1 eq '{') { 5248 $brace_count++; 5249 } else { 5250 $brace_count--; 5251 } 5252 } else { 5253 my $new_text; 5254 ($new_text, $line_nr) = _next_text($self, $line_nr); 5255 if (!$new_text) { 5256 next NEXT_LINE; # error - unbalanced brace 5257 } 5258 $line .= $new_text; 5259 } 5260 } 5261 $current = $current->{'args'}->[-1]; 5262 $line = '}' . $line; 5263 next; 5264 } 5265 } 5266 $current->{'remaining_args'}--; 5267 push @{$current->{'args'}}, 5268 { 'type' => $type, 'parent' => $current, 'contents' => [] }; 5269 $current = $current->{'args'}->[-1]; 5270 push @{$current->{'contents'}}, 5271 {'type' => 'empty_spaces_before_argument', 5272 'text' => '', 5273 'parent' => $current, 5274 'extra' => {'command' => $current} 5275 }; 5276 } elsif ($separator eq ',' and $current->{'type'} 5277 and $current->{'type'} eq 'line_arg' 5278 and $current->{'parent'}->{'cmdname'} 5279 and $current->{'parent'}->{'cmdname'} eq 'node') { 5280 $self->line_warn(__("superfluous arguments for node"), $line_nr); 5281 # end of menu node (. must be followed by a space to stop the node). 5282 } elsif (($separator =~ /[,\t.]/ and $current->{'type'} 5283 and $current->{'type'} eq 'menu_entry_node') 5284 or ($separator eq ':' and $current->{'type'} 5285 and $current->{'type'} eq 'menu_entry_name')) { 5286 $current = $current->{'parent'}; 5287 push @{$current->{'args'}}, { 'type' => 'menu_entry_separator', 5288 'text' => $separator, 5289 'parent' => $current }; 5290 } elsif ($separator eq "\f" and $current->{'type'} 5291 and $current->{'type'} eq 'paragraph') { 5292 # form feed stops and restart a paragraph. 5293 $current = $self->_end_paragraph($current); 5294 push @{$current->{'contents'}}, {'text' => $separator, 5295 'type' => 'empty_line', 5296 'parent' => $current }; 5297 push @{$current->{'contents'}}, { 'type' => 'empty_line', 5298 'text' => '', 5299 'parent' => $current }; 5300 5301 } else { 5302 $current = _merge_text($self, $current, $separator); 5303 } 5304 # Misc text except end of line 5305 } elsif (defined $misc_text) { 5306 my $new_text = $misc_text; 5307 substr ($line, 0, length ($misc_text)) = ''; 5308 $current = _merge_text($self, $current, $new_text); 5309 # end of line 5310 } else { 5311 print STDERR "END LINE: ". _print_current($current)."\n" 5312 if ($self->{'DEBUG'}); 5313 if ($line =~ s/^(\n)//) { 5314 $current = _merge_text($self, $current, $1); 5315 } else { 5316 if (scalar(@{$self->{'input'}})) { 5317 $self->_bug_message("Text remaining without normal text but `$line'", 5318 $line_nr, $current); 5319 die; 5320 } 5321 } 5322 $current = _end_line($self, $current, $line_nr); 5323 last; 5324 } 5325 } 5326 } 5327 while (@{$self->{'conditionals_stack'}}) { 5328 my $end_conditional = pop @{$self->{'conditionals_stack'}}; 5329 $self->line_error(sprintf(__("expected \@end %s"), $end_conditional), 5330 $line_nr); 5331 } 5332 $current = _close_commands($self, $current, $line_nr); 5333 5334 if (@{$self->{'context_stack'}} != 1) { 5335 # This happens in 2 cases in the tests: 5336 # @verb not closed on misc commands line 5337 # def line escaped with @ ending the file 5338 if ($self->{'DEBUG'}) { 5339 print STDERR "CONTEXT_STACK no empty end _parse_texi: ".join('|', @{$self->{'context_stack'}})."\n"; 5340 } 5341 @{$self->{'context_stack'}} = ('_root'); 5342 } 5343 5344 # Call 'labels_information' to initialize labels. 5345 my $labels = labels_information($self); 5346 Texinfo::Common::complete_indices($self); 5347 return $root; 5348} 5349 5350# parse special line @-commands, unmacro, set, clear, clickstyle. 5351# Also remove spaces or ignore text, as specified in the line_commands hash. 5352sub _parse_special_misc_command($$$$) 5353{ 5354 my ($self, $line, $command, $line_nr) = @_; 5355 5356 my $args = []; 5357 5358 my $has_comment = 0; 5359 my $remaining; 5360 if ($command eq 'set') { 5361 # REVALUE 5362 if ($line =~ /^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)(\@(c|comment)((\@|\s+).*)?|\s+(.*?))?\s*$/) { 5363 if ($line =~ s/\@(c|comment)((\@|\s+).*)?$//) { 5364 $has_comment = 1; 5365 } 5366 $line =~ /^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)(\s+(.*?))?\s*$/; 5367 my $name = $1; 5368 my $arg = $3; 5369 $arg = '' if (!defined($arg)); 5370 $args = [$name, $arg]; 5371 $self->{'values'}->{$name} = $arg; 5372 } elsif ($line !~ /\S/) { 5373 $self->line_error(sprintf( 5374 __("%c%s requires a name"), ord('@'), $command), $line_nr); 5375 } else { 5376 $self->line_error(sprintf( 5377 __("bad name for \@%s"), $command), $line_nr); 5378 } 5379 } elsif ($command eq 'clear') { 5380 # REVALUE 5381 if ($line =~ /^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) { 5382 $args = [$1]; 5383 delete $self->{'values'}->{$1}; 5384 $has_comment = 1 if (defined($3)); 5385 } elsif ($line !~ /\S/) { 5386 $self->line_error(sprintf( 5387 __("%c%s requires a name"), ord('@'), $command), $line_nr); 5388 } else { 5389 $self->line_error(sprintf( 5390 __("bad name for \@%s"), $command), $line_nr); 5391 } 5392 } elsif ($command eq 'unmacro') { 5393 # REMACRO 5394 if ($line =~ /^\s+([[:alnum:]][[:alnum:]\-]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) { 5395 $args = [$1]; 5396 delete $self->{'macros'}->{$1}; 5397 $has_comment = 1 if (defined($3)); 5398 print STDERR "UNMACRO $1\n" if ($self->{'DEBUG'}); 5399 } elsif ($line !~ /\S/) { 5400 $self->line_error(sprintf( 5401 __("%c%s requires a name"), ord('@'), $command), $line_nr); 5402 } else { 5403 $self->line_error(sprintf( 5404 __("bad name for \@%s"), $command), $line_nr); 5405 } 5406 } elsif ($command eq 'clickstyle') { 5407 # REMACRO 5408 if ($line =~ /^\s+@([[:alnum:]][[:alnum:]\-]*)(\{\})?\s*/) { 5409 $args = ['@'.$1]; 5410 $self->{'clickstyle'} = $1; 5411 $remaining = $line; 5412 $remaining =~ s/^\s+@([[:alnum:]][[:alnum:]\-]*)(\{\})?\s*(\@(c|comment)((\@|\s+).*)?)?//; 5413 $has_comment = 1 if (defined($4)); 5414 } else { 5415 $self->line_error (sprintf(__( 5416 "\@%s should only accept an \@-command as argument, not `%s'"), 5417 $command, $line), $line_nr); 5418 } 5419 } else { 5420 die $self->_bug_message("Unknown special command $command", $line_nr); 5421 } 5422 if (defined($remaining)) { 5423 chomp($remaining); 5424 if ($remaining ne '') { 5425 $self->line_warn(sprintf(__( 5426 "remaining argument on \@%s line: %s"), 5427 $command, $remaining), $line_nr); 5428 } 5429 } 5430 return ($args, $has_comment); 5431} 5432 5433# at the end of an @-command line with arguments, parse the resulting 5434# text, to collect aliases, definfoenclose and collect errors on 5435# wrong arguments. 5436sub _parse_line_command_args($$$) 5437{ 5438 my ($self, $line_command, $line_nr) = @_; 5439 5440 my $args; 5441 5442 my $command = $line_command->{'cmdname'}; 5443 my $arg = $line_command->{'args'}->[0]; 5444 5445 if ($self->{'DEBUG'}) { 5446 print STDERR "MISC ARGS \@$command\n"; 5447 if (@{$arg->{'contents'}}) { 5448 my $idx = 0; 5449 foreach my $content (@{$arg->{'contents'}}) { 5450 my $name = ''; 5451 $name = '@' . $content->{'cmdname'} if ($content->{'cmdname'}); 5452 my $type = ', t: '; 5453 $type .= $content->{'type'} if ($content->{'type'}); 5454 my $text = ', '; 5455 $type .= $content->{'text'} if ($content->{'text'}); 5456 print STDERR " -> $idx $name $type $text\n"; 5457 $idx++; 5458 } 5459 } 5460 } 5461 5462 if (!$arg->{'contents'} or !@{$arg->{'contents'}}) { 5463 $self->_command_error($line_command, $line_nr, 5464 __("\@%s missing argument"), $command); 5465 $line_command->{'extra'}->{'missing_argument'} = 1; 5466 return undef; 5467 } 5468 5469 if (@{$arg->{'contents'}} > 1 5470 or (!defined($arg->{'contents'}->[0]->{'text'}))) { 5471 $self->line_error (sprintf(__("superfluous argument to \@%s"), 5472 $command), $line_nr); 5473 } 5474 return undef if (!defined($arg->{'contents'}->[0]->{'text'})); 5475 5476 my $line = $arg->{'contents'}->[0]->{'text'}; 5477 5478 if ($command eq 'alias') { 5479 # REMACRO 5480 if ($line =~ s/^([[:alnum:]][[:alnum:]-]*)(\s*=\s*)([[:alnum:]][[:alnum:]-]*)$//) { 5481 my $new_command = $1; 5482 my $existing_command = $3; 5483 $args = [$1, $3]; 5484 $self->{'aliases'}->{$new_command} = $existing_command; 5485 if (exists($block_commands{$existing_command})) { 5486 $self->line_warn(sprintf( 5487 __("environment command %s as argument to \@%s"), 5488 $existing_command, $command), $line_nr); 5489 } 5490 } else { 5491 $self->line_error(sprintf( 5492 __("bad argument to \@%s"), $command), $line_nr); 5493 } 5494 5495 } elsif ($command eq 'definfoenclose') { 5496 # REMACRO 5497 if ($line =~ s/^([[:alnum:]][[:alnum:]\-]*)\s*,\s*([^\s,]*)\s*,\s*([^\s,]*)$//) { 5498 $args = [$1, $2, $3 ]; 5499 $self->{'definfoenclose'}->{$1} = [ $2, $3 ]; 5500 print STDERR "DEFINFOENCLOSE \@$1: $2, $3\n" if ($self->{'DEBUG'}); 5501 5502 $brace_commands{$1} = 'style'; 5503 5504 # Warning: there is a risk of mixing of data between a built-in 5505 # command and a user command defined with @definfoenclose. 5506 # %keep_line_nr_brace_commands is one example of this. 5507 } else { 5508 $self->line_error(sprintf( 5509 __("bad argument to \@%s"), $command), $line_nr); 5510 } 5511 } elsif ($command eq 'columnfractions') { 5512 my @possible_fractions = split (/\s+/, $line); 5513 if (!@possible_fractions) { 5514 $self->line_error (sprintf(__("empty \@%s"), $command), 5515 $line_nr); 5516 } else { 5517 foreach my $fraction (@possible_fractions) { 5518 if ($fraction =~ /^\d*\.\d+$|^\d+\.?$/) { 5519 push @$args, $fraction; 5520 } else { 5521 $self->line_error (sprintf( 5522 __("column fraction not a number: %s"), 5523 $fraction), $line_nr); 5524 } 5525 } 5526 } 5527 } elsif ($command eq 'sp') { 5528 if ($line =~ /^([0-9]+)$/) { 5529 $args = [$1]; 5530 } else { 5531 $self->line_error(sprintf(__("\@sp arg must be numeric, not `%s'"), 5532 $line), $line_nr); 5533 } 5534 } elsif ($command eq 'defindex' || $command eq 'defcodeindex') { 5535 # REMACRO 5536 if ($line =~ /^([[:alnum:]][[:alnum:]\-]*)$/) { 5537 my $name = $1; 5538 if ($forbidden_index_name{$name}) { 5539 $self->line_error(sprintf( 5540 __("reserved index name %s"),$name), $line_nr); 5541 } else { 5542 my $in_code = 0; 5543 $in_code = 1 if ($command eq 'defcodeindex'); 5544 $args = [$name]; 5545 $self->{'index_names'}->{$name} = {'in_code' => $in_code}; 5546 if (!exists($self->{'index_names'}->{$name}->{'name'})) { 5547 $self->{'index_names'}->{$name}->{'name'} = $name; 5548 } 5549 if (!exists($self->{'index_names'}->{$name}->{'contained_indices'})) { 5550 $self->{'index_names'}->{$name}->{'contained_indices'}->{$name} = 1; 5551 } 5552 $self->{'line_commands'}->{$name.'index'} = 'line'; 5553 $self->{'no_paragraph_commands'}->{$name.'index'} = 1; 5554 $self->{'valid_nestings'}->{$name.'index'} = \%in_simple_text_commands; 5555 $self->{'command_index'}->{$name.'index'} = $name; 5556 } 5557 } else { 5558 $self->line_error(sprintf( 5559 __("bad argument to \@%s: %s"), $command, $line), $line_nr); 5560 } 5561 } elsif ($command eq 'synindex' || $command eq 'syncodeindex') { 5562 # REMACRO 5563 if ($line =~ /^([[:alnum:]][[:alnum:]\-]*)\s+([[:alnum:]][[:alnum:]\-]*)$/) { 5564 my $index_from = $1; 5565 my $index_to = $2; 5566 $self->line_error(sprintf(__("unknown source index in \@%s: %s"), 5567 $command, $index_from), $line_nr) 5568 unless $self->{'index_names'}->{$index_from}; 5569 $self->line_error(sprintf(__("unknown destination index in \@%s: %s"), 5570 $command, $index_to), $line_nr) 5571 unless $self->{'index_names'}->{$index_to}; 5572 if ($self->{'index_names'}->{$index_from} 5573 and $self->{'index_names'}->{$index_to}) { 5574 my $current_to = $index_to; 5575 # find the merged indices recursively avoiding loops 5576 while ($current_to ne $index_from 5577 and $self->{'merged_indices'}->{$current_to}) { 5578 $current_to = $self->{'merged_indices'}->{$current_to}; 5579 } 5580 if ($current_to ne $index_from) { 5581 my $index_from_info = $self->{'index_names'}->{$index_from}; 5582 my $index_to_info = $self->{'index_names'}->{$current_to}; 5583 5584 my $in_code = 0; 5585 $in_code = 1 if ($command eq 'syncodeindex'); 5586 $self->{'merged_indices'}->{$index_from} = $current_to; 5587 $index_from_info->{'in_code'} = $in_code; 5588 foreach my $contained_index (keys %{$index_from_info->{'contained_indices'}}) { 5589 $index_to_info->{'contained_indices'}->{$contained_index} = 1; 5590 $self->{'index_names'}->{$contained_index}->{'merged_in'} = $current_to; 5591 $self->{'merged_indices'}->{$contained_index} = $current_to; 5592 } 5593 delete $index_from_info->{'contained_indices'}; 5594 $index_from_info->{'merged_in'} = $current_to; 5595 $index_to_info->{'contained_indices'}->{$index_from} = 1; 5596 $args = [$index_from, $index_to]; 5597 } else { 5598 $self->line_warn(sprintf(__( 5599 "\@%s leads to a merging of %s in itself, ignoring"), 5600 $command, $index_from), $line_nr); 5601 } 5602 } 5603 } else { 5604 $self->line_error(sprintf(__("bad argument to \@%s: %s"), 5605 $command, $line), $line_nr); 5606 } 5607 } elsif ($command eq 'printindex') { 5608 # REMACRO 5609 if ($line =~ /^([[:alnum:]][[:alnum:]\-]*)$/) { 5610 my $name = $1; 5611 if (!exists($self->{'index_names'}->{$name})) { 5612 $self->line_error(sprintf(__("unknown index `%s' in \@printindex"), 5613 $name), $line_nr); 5614 5615 } else { 5616 if ($self->{'merged_indices'}->{$name}) { 5617 $self->line_warn(sprintf(__( 5618 "printing an index `%s' merged in another one, `%s'"), 5619 $name, $self->{'merged_indices'}->{$name}), 5620 $line_nr); 5621 } 5622 if (!defined($self->{'current_node'}) 5623 and !defined($self->{'current_section'}) 5624 and !scalar(@{$self->{'regions_stack'}})) { 5625 $self->line_warn(sprintf(__( 5626 "printindex before document beginning: \@printindex %s"), 5627 $name), $line_nr); 5628 } 5629 $args = [$name]; 5630 } 5631 } else { 5632 $self->line_error(sprintf( 5633 __("bad argument to \@%s: %s"), $command, $line), $line_nr); 5634 } 5635 } elsif (grep {$_ eq $command} ('everyheadingmarks', 'everyfootingmarks', 5636 'evenheadingmarks', 'oddheadingmarks', 5637 'evenfootingmarks', 'oddfootingmarks')) { 5638 if ($line eq 'top' or $line eq 'bottom') { 5639 $args = [$line]; 5640 } else { 5641 $self->line_error(sprintf(__( 5642 "\@%s arg must be `top' or `bottom', not `%s'"), 5643 $command, $line), $line_nr); 5644 } 5645 } elsif ($command eq 'fonttextsize') { 5646 if ($line eq '10' or $line eq '11') { 5647 $args = [$line]; 5648 } else { 5649 $self->line_error(sprintf(__( 5650 "Only \@%s 10 or 11 is supported, not `%s'"), 5651 $command, $line), $line_nr); 5652 } 5653 } elsif ($command eq 'footnotestyle') { 5654 if ($line eq 'separate' or $line eq 'end') { 5655 $args = [$line]; 5656 } else { 5657 $self->line_error(sprintf(__( 5658 "\@%s arg must be `separate' or `end', not `%s'"), 5659 $command, $line), $line_nr); 5660 } 5661 } elsif ($command eq 'setchapternewpage') { 5662 if ($line eq 'on' or $line eq 'off' or $line eq 'odd') { 5663 $args = [$1]; 5664 } else { 5665 $self->line_error(sprintf(__( 5666 "\@%s arg must be `on', `off' or `odd', not `%s'"), 5667 $command, $line), $line_nr); 5668 } 5669 } elsif ($command eq 'need') { # only a warning 5670 if (($line =~ /^([0-9]+(\.[0-9]*)?)$/) or 5671 ($line =~ /^(\.[0-9]+)$/)) { 5672 $args = [$1]; 5673 } else { 5674 $self->line_error(sprintf(__("bad argument to \@%s: %s"), 5675 $command, $line), $line_nr); 5676 } 5677 } elsif ($command eq 'paragraphindent') { 5678 if ($line =~ /^([\w\-]+)$/) { 5679 my $value = $1; 5680 if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis') { 5681 $args = [$1]; 5682 } else { 5683 $self->line_error(sprintf(__( 5684 "\@paragraphindent arg must be numeric/`none'/`asis', not `%s'"), 5685 $value), $line_nr); 5686 } 5687 } else { 5688 $self->line_error(sprintf(__( 5689 "\@paragraphindent arg must be numeric/`none'/`asis', not `%s'"), 5690 $line), $line_nr); 5691 } 5692 } elsif ($command eq 'firstparagraphindent') { 5693 if ($line eq 'none' or $line eq 'insert') { 5694 $args = [$line]; 5695 } else { 5696 $self->line_error(sprintf(__( 5697 "\@firstparagraphindent arg must be `none' or `insert', not `%s'"), 5698 $line), $line_nr); 5699 } 5700 } elsif ($command eq 'exampleindent') { 5701 if ($line =~ /^([0-9]+)$/) { 5702 $args = [$1]; 5703 } elsif ($line =~ /^(asis)$/) { 5704 $args = [$1]; 5705 } else { 5706 $self->line_error(sprintf(__( 5707 "\@exampleindent arg must be numeric/`asis', not `%s'"), 5708 $line), $line_nr); 5709 } 5710 } elsif ($command eq 'frenchspacing' 5711 or $command eq 'xrefautomaticsectiontitle' 5712 or $command eq 'codequoteundirected' 5713 or $command eq 'codequotebacktick' 5714 or $command eq 'deftypefnnewline') { 5715 if ($line eq 'on' or $line eq 'off') { 5716 $args = [$line]; 5717 } else { 5718 $self->line_error(sprintf(__("expected \@%s on or off, not `%s'"), 5719 $command, $line), $line_nr); 5720 } 5721 } elsif ($command eq 'kbdinputstyle') { 5722 if ($line eq 'code' or $line eq 'example' or $line eq 'distinct') { 5723 $self->{'kbdinputstyle'} = $line; 5724 $args = [$line]; 5725 } else { 5726 $self->line_error(sprintf(__( 5727 "\@kbdinputstyle arg must be `code'/`example'/`distinct', not `%s'"), 5728 $line), $line_nr); 5729 } 5730 } elsif ($command eq 'allowcodebreaks') { 5731 if ($line eq 'true' or $line eq 'false') { 5732 $args = [$line]; 5733 } else { 5734 $self->line_error(sprintf(__( 5735 "\@allowcodebreaks arg must be `true' or `false', not `%s'"), 5736 $line), $line_nr); 5737 } 5738 } elsif ($command eq 'urefbreakstyle') { 5739 if ($line eq 'after' or $line eq 'before' or $line eq 'none') { 5740 $args = [$line]; 5741 } else { 5742 $self->line_error(sprintf(__( 5743 "\@urefbreakstyle arg must be `after'/`before'/`none', not `%s'"), 5744 $line), $line_nr); 5745 } 5746 } elsif ($command eq 'headings') { 5747 if ($line eq 'off' or $line eq 'on' or $line eq 'single' 5748 or $line eq 'double' or $line eq 'singleafter' or $line eq 'doubleafter') { 5749 $args = [$line]; 5750 } else { 5751 $self->line_error(sprintf(__("bad argument to \@%s: %s"), 5752 $command, $line), $line_nr); 5753 } 5754 } 5755 return $args; 5756} 5757 57581; 5759__END__ 5760=head1 NAME 5761 5762Texinfo::Parser - Parse Texinfo code into a Perl tree 5763 5764=head1 SYNOPSIS 5765 5766 use Texinfo::Parser; 5767 my $parser = Texinfo::Parser::parser(); 5768 my $tree = $parser->parse_texi_file("somefile.texi"); 5769 my ($errors, $errors_count) = $parser->errors(); 5770 foreach my $error_message (@$errors) { 5771 warn $error_message->{'error_line'}; 5772 } 5773 5774 my $index_names = $parser->indices_information(); 5775 my $float_types_arrays = $parser->floats_information(); 5776 my $internal_references_array 5777 = $parser->internal_references_information(); 5778 # An hash reference on normalized node/float/anchor names 5779 my $labels_information = $parser->labels_information(); 5780 # A hash reference, keys are @-command names, value is an 5781 # array reference holding all the corresponding @-commands. 5782 my $global_commands_information = $parser->global_commands_information(); 5783 # a hash reference on some document informations (encodings, 5784 # input file name, dircategory and direntry list, for exampel). 5785 my $global_informations = $parser->global_informations(); 5786 5787=head1 DESCRIPTION 5788 5789Texinfo::Parser will parse Texinfo text into a perl tree. In one pass 5790it expands user-defined @-commands, conditionals (@ifset, @ifinfo...) 5791and @value and constructs the tree. Some extra information is gathered 5792while doing the tree: for example, the block command associated with @end, 5793the number of rows in a multitable, or the node associated with a section. 5794 5795 5796 5797=head1 METHODS 5798 5799No method is exported in the default case. The module allows both 5800an object-oriented syntax, or traditional function, with the parser 5801as an opaque data structure given as an argument to every function. 5802 5803=head2 Initialization 5804 5805The following method is used to construct a new C<Texinfo::Parser> object: 5806 5807=over 5808 5809=item $parser = Texinfo::Parser::parser($options); 5810 5811This method creates a new parser. The options may be provided as a hash 5812reference. There are two types of option. The first type of option 5813change the way the parser behaves; they are described right here. The 5814other type of option allows giving the parser some information as if 5815it came from texinfo code; for example, allow setting aliases (as with 5816C<@alias>), values (as with C<@set>), or merged indices (as with 5817C<@synindex>). These options are described below in L</Texinfo Parser options>. 5818 5819=over 5820 5821=item expanded_formats 5822 5823An array reference of the output formats for which C<@ifI<FORMAT>> 5824conditional blocks should be expanded. Default is empty. 5825 5826=item include_directories 5827 5828An array reference of directories in which C<@include> files should be 5829searched for. Default contains the working directory, F<.>. 5830 5831=item IGNORE_BEFORE_SETFILENAME 5832 5833If set, and C<@setfilename> exists, everything before C<@setfilename> 5834is put in a special container type, @C<preamble_before_setfilename>. 5835This option is set in the default case. 5836 5837=item IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME 5838 5839If set, spaces after an @-command name that take braces are ignored. 5840Default on. 5841 5842=item MAX_MACRO_CALL_NESTING 5843 5844Maximal number of nested user-defined macro calls. Default is 100000. 5845 5846=item FORMAT_MENU 5847 5848Possible values are 'nomenu', 'menu' and 'sectiontoc'. Only report 5849menu-related errors for 'menu'. 5850 5851=begin :comment 5852 5853Used by Sectioning only 5854=item TOP_NODE_UP 5855 5856Text for the up node of the Top node. The default is C<(dir)>. The 5857string may contain @-commands. 5858 5859=end :comment 5860 5861=back 5862 5863=back 5864 5865=head2 Parsing Texinfo text 5866 5867There are three methods that may be called to parse some Texinfo code: 5868C<parse_texi_line> for a line, C<parse_texi_text> for a text fragment, 5869and C<parse_texi_file> for a file. 5870 5871For all those functions, if the I<$parser> argument is undef, a new 5872parser object is generated to parse the line. Otherwise the parser given 5873as an argument is used to parse into a tree. 5874 5875When C<parse_texi_line> is used, the resulting tree is rooted at 5876a C<root_line> type container. Otherwise, the resulting tree should be 5877rooted at a C<text_root> type container if it does not contain nodes or 5878sections, at a C<document_root> type container otherwise. 5879 5880=over 5881 5882=item $tree = parse_texi_line($parser, $text, $first_line_number, $file_name, $macro_name, $fixed_line_number) 5883 5884This function is used to parse a short fragment of Texinfo code. 5885 5886I<$text> may be either an array reference of lines, or a text. 5887 5888The other arguments are optional and allow specifying the position 5889information of the Texinfo code. I<$first_line_number> is the line number 5890of the first text line. I<$file_name> is the name of the file the 5891text comes from. I<$macro> is for the user-defined macro name the text 5892is expanded from. If I<$fixed_line_number> is set, the line number is 5893not increased for the different lines, as if the text was the expansion 5894of a macro. 5895 5896=item $tree = parse_texi_text ($parser, $text, $line_numbers_specification, $file_name, $macro_name, $fixed_line_number) 5897 5898This function is used to parse some Texinfo text. 5899 5900I<$text> may be either an array reference of lines, or a text. 5901 5902The other arguments are optional and allow specifying the position 5903information of the Texinfo code. There are two distinct cases for 5904I<$line_numbers_specification>. 5905 5906=over 5907 5908=item 1. 5909 5910If it is an array reference, it is considered to hold objects describing 5911the position information of each text line. 5912 5913=item 2. 5914 5915If I<$line_numbers_specification> is a scalar, it is the line number of 5916the first text line. In that case (like for C<parse_texi_text>), 5917I<$file_name> is the name of the file the text comes from. 5918and I<$macro> is for the user-defined macro name the text 5919is expanded from. If I<$fixed_line_number> is set, the line number is 5920not increased for the different lines, as if the text was the expansion 5921of a macro. 5922 5923=back 5924 5925=item $tree = parse_texi_file($parser, $file_name) 5926 5927The file with name I<$file_name> is considered to be a Texinfo file and 5928is parsed into a tree. 5929 5930undef is returned if the file couldn't be read. 5931 5932=back 5933 5934The errors collected during the tree parsing are available through the 5935C<errors> method. This method comes from C<Texinfo::Report>, and is 5936described in L<errors|Texinfo::Report/($error_warnings_list, $error_count) = errors ($converter)>. 5937 5938=head2 Getting information on the document 5939 5940After parsing some information about the Texinfo code that was processed 5941is available from the parser. 5942 5943Some global information is available through C<global_informations> 5944 5945=over 5946 5947=item $info = global_informations($parser) 5948 5949The I<$info> returned is a hash reference. The possible keys are 5950 5951=over 5952 5953=item input_file_name 5954 5955The name of the main Texinfo input file. 5956 5957=item input_encoding_name 5958 5959=item input_perl_encoding 5960 5961C<input_encoding_name> string is the encoding name used for the 5962Texinfo code. 5963C<input_perl_encoding> string is a corresponding perl encoding name. 5964 5965=item dircategory_direntry 5966 5967An array of successive C<@dircategory> and C<@direntry> as they appear 5968in the document. 5969 5970=item novalidate 5971 5972If set, it is as if C<@novalidate> was set in the document. 5973 5974 5975=back 5976 5977=back 5978 5979Some command lists are available, such that it is possible to go through 5980the corresponding tree elements without walking the tree. They are 5981available through C<global_commands_information> 5982 5983=over 5984 5985=item $commands = global_commands_information($parser) 5986 5987I<$commands> is an hash reference. The keys are @-command names. The 5988associated values are array references containing all the corresponding 5989tree elements. 5990 5991=back 5992 5993All the @-commands that have an associated label (so can be the 5994target of cross references) - C<@node>, C<@anchor> and C<@float> with 5995label - have a normalized name associated, constructed as described in the 5996B<HTML Xref> node in the Texinfo manual. Those normalized labels and 5997the association with @-commands is available through C<labels_information>: 5998 5999=over 6000 6001=item $labels_information = labels_information($parser) 6002 6003I<$labels_information> is a hash reference whose keys are normalized 6004labels, and the associated value is the corresponding @-command. 6005 6006=back 6007 6008Information on C<@float> is also available, grouped by type of 6009floats, each type correponding to potential C<@listoffloats>. 6010This information is available through the method C<floats_information>. 6011 6012=over 6013 6014=item $float_types = floats_information($parser) 6015 6016I<$float_types> is a hash reference whose keys are normalized float 6017types (the first float argument, or the C<@listoffloats> argument). 6018The normalization is the same as for node names. The value is the list 6019of float tree elements appearing in the texinfo document. 6020 6021=back 6022 6023Internal references, that is, @-commands that refer to node, anchors 6024or floats within the document are also available: 6025 6026=over 6027 6028=item $internal_references_array = internal_references_information($parser); 6029 6030The function returns a list of cross-reference commands referring to 6031the same document. 6032 6033=back 6034 6035Information about defined indices, merged indices and index entries is 6036also available through the C<indices_information> method. 6037 6038=over 6039 6040=item indices_information 6041 6042 $index_names = indices_information($parser); 6043 6044The index names is a hash reference. The keys are 6045 6046=over 6047 6048=item in_code 6049 60501 if the index entries should be formatted as code, 0 in the opposite case. 6051 6052=item name 6053 6054The index name. 6055 6056=item prefix 6057 6058An array reference of prefix associated to the index. 6059 6060=item merged_in 6061 6062In case the index is merged to another index, this key holds the name of 6063the index the index is merged into. It takes into account indirectly 6064merged indices. 6065 6066=item contained_indices 6067 6068An hash reference holding names of indices that are merged into the index, 6069including itself. It also contains indirectly merged indices. This key 6070is removed if the index is itself later merged to another index. 6071 6072=item index_entries 6073 6074An array reference containing index entry structures for index entries 6075associated with the index. The index entry could be associated to 6076@-commands like C<@cindex>, or C<@item> in C<@vtable>, or definition 6077commands entries like C<@deffn>. 6078 6079The keys of the index entry structures are 6080 6081=over 6082 6083=item index_name 6084 6085The index name. 6086 6087=item index_at_command 6088 6089The name of the @-command associated with the index entry. 6090 6091=item index_type_command 6092 6093The @-command associated with the index entry allowing to 6094find the index type. 6095 6096=item content 6097 6098An array reference corresponding to the index entry content. 6099 6100=item content_normalized 6101 6102An array reference corresponding to the index entry content, independent 6103of the current language. 6104 6105=item command 6106 6107The element in the parsed tree associated with the @-command holding the 6108index entry. 6109 6110=item node 6111 6112The node in the parsed tree containing the index entry. 6113 6114=item number 6115 6116The number of the index entry. 6117 6118=item region 6119 6120The region command (C<@copying>, C<@titlepage>) containing the index entry, 6121if it is in such an environement. 6122 6123=back 6124 6125=back 6126 6127The following shows the references corresponding to the default indexes 6128I<cp> and I<fn>, the I<fn> index having its entries formatted as code and 6129the indices corresponding to the following texinfo 6130 6131 @defindex some 6132 @defcodeindex code 6133 6134 $index_names = {'cp' => {'name' => 'cp', 'in_code' => 0, }, 6135 'fn' => {'name' => 'fn', 'in_code' => 1, }, 6136 'some' => {'in_code' => 0}, 6137 'code' => {'in_code' => 1}}; 6138 6139If C<name> is not set, it is set to the index name. 6140 6141=back 6142 6143=head2 Texinfo Parser options 6144 6145Setting these options is the same as seeing some Texinfo constructs in the 6146document. 6147 6148=over 6149 6150=item aliases 6151 6152A hash reference. The key is a command name, the value is the alias, as 6153could be set by C<@alias>. 6154 6155=item clickstyle 6156 6157A string, the command name associated with C<@clickstyle>. 6158 6159=item documentlanguage 6160 6161A string corresponding to a document language set by C<@documentlanguage>. 6162 6163=item indices 6164 6165If it is a hash reference, the keys are index names, the values are 6166index prefix hash references. The index prefix hash reference values are 6167prefix, the value is set if the corresponding index entries should be 6168formatted as if in C<@code>. An example is as L</indices_information>. 6169 6170If it is an array reference, it is a list of index names, as if they were 6171entered as 6172 6173 @defindex name 6174 6175=item kbdinputstyle 6176 6177A string, the C<@kbdinputstyle> style. 6178 6179=item labels 6180 6181A hash reference. Keys are normalized node names as described in the 6182B<HTML Xref> node in the Texinfo manual. Instead of a node, it may also 6183be a float label or an anchor name. The value is the corresponding 6184@-command element in the tree. 6185 6186=item macros 6187 6188The associated hash reference has as keys user-defined macro names. The 6189value is the reference on a macro definition element as obtained by 6190the Parser when parsing a C<@macro>. For example 6191 6192 @macro mymacro{arg} 6193 coucou \arg\ after arg 6194 @end macro 6195 6196Is associated to a macro definition element 6197 6198 {'cmdname' => 'macro', 6199 'args' => [{'text' => 'mymacro', 'type' => 'macro_name'}, 6200 {'text' => 'arg', 'type' => 'macro_arg}], 6201 'contents' => [{'text' => "coucou \arg\ after arg\n", 'type' => 'raw'}], 6202 'extra' => {'arg_line' => " mymacro{arg}\n", }} 6203 6204= item merged_indices 6205 6206The associated hash reference holds merged indices information, each key 6207is merged in the value. Same as setting C<@synindex> or C<syncodeindex>. 6208 6209=item sections_level 6210 6211Modifier of the sections level. Same as calling C<@lowersections> or 6212C<@raisesections>. 6213 6214=item values 6215 6216A hash reference. Keys are names, values are the corresponding values. 6217Same as values set by C<@set>. 6218 6219=back 6220 6221=head1 TEXINFO TREE 6222 6223A Texinfo tree element (called element because node is overloaded in 6224the Texinfo world) is an hash reference. There are three main categories 6225of tree element. Tree elements associated with an @-command have a 6226C<cmdname> key holding the @-command name. Tree elements corresponding 6227to text fragments have a C<text> key holding the corresponding text. 6228Finally, the last category is other containers (hereafter called 6229containers) which in most cases have a C<type> key holding their name. 6230Text fragments and @-command elements may also have an associated type 6231when such information is needed. 6232 6233The children of an @-command or container element are in the array 6234referred to with the C<args> key or with the C<contents> key. The 6235C<args> key is for arguments of @-commands, either in braces or on 6236the rest of the line after the command, depending on the type of command. 6237C<args> is also used for the elements of a menu entry, as a menu 6238entry is well-structured with a limited number of arguments. 6239The C<contents> key array holds the contents of the texinfo 6240code appearing within a block @-command, within a container, 6241or within a C<@node> or sectioning @-command. 6242 6243Another important key for the elements is the C<extra> key which is 6244associated to a hash reference and holds all kinds of information that 6245is gathered during the parsing and may help with the conversion. 6246 6247You can see examples of the tree structure by running makeinfo like 6248this: 6249 6250 makeinfo -c DUMP_TREE=1 -c TEXINFO_OUTPUT_FORMAT=parse document.texi 6251 6252For a simpler, more regular representation of the tree structure, you 6253can do: 6254 6255 makeinfo -c TEXINFO_OUTPUT_FORMAT=debugtree document.texi 6256 6257=head2 Element keys 6258 6259=over 6260 6261=item cmdname 6262 6263The command name of @-command elements. 6264 6265=item text 6266 6267The text fragment of text elements. 6268 6269=item type 6270 6271The type of the element. For C<@verb> it is the delimiter. But otherwise 6272it is the type of element considered as a container. Frequent types 6273encountered are I<paragraph> for a paragraph container, 6274I<brace_command_arg> for the container holding the brace @-commands 6275contents, I<line_arg> and I<block_line_arg> contain the arguments 6276appearing on the line of @-commands. Text fragments may have a type to 6277give an information of the kind of text fragment, for example 6278C<empty_spaces_before_argument> is associated to spaces after a brace 6279opening and before the argument. Many @-commands elements don't have 6280a type associated. 6281 6282=item args 6283 6284Arguments in braces or on @-command line, and the elements of a menu entry. 6285 6286=item contents 6287 6288The Texinfo appearing in the element. For block commands, other 6289containers, C<@node> and sectioning commands. 6290 6291=item parent 6292 6293The parent element. 6294 6295=item line_nr 6296 6297An hash reference corresponding to information on the location of the 6298element in the Texinfo input manual. It should only be available for 6299@-command elements, and only for @-commands that are considered to be 6300complex enough that the location in the document is needed, for example 6301to prepare an error message. 6302 6303The keys of the line number hash references are 6304 6305=over 6306 6307=item line_nr 6308 6309The line number of the @-command. 6310 6311=item file_name 6312 6313The file name where @-command appeared. 6314 6315=item macro 6316 6317The user macro name the @-command is expanded from. 6318 6319=back 6320 6321=item extra 6322 6323A hash reference holding any additional information. 6324See L</Information available in the extra key>. 6325 6326=back 6327 6328=head2 Element types 6329 6330=head3 Types for command elements 6331 6332Some types can be associated with @-commands (in addition to the element 6333being described by C<cmdname>), although usually there will be no type 6334at all. As said above, for C<@verb> the type is the delimiter. For a 6335C<@value> command that is not expanded because there is no corresponding 6336value set, the type is the value argument string. 6337 6338The following are the other possible values of C<type> for tree elements 6339for @-commands. 6340 6341=over 6342 6343=item def_line 6344 6345This type may be associated with a definition command with a x form, 6346like C<@defunx>, C<@defvrx>. For the form without x, the associated 6347I<def_line> is the first C<contents> element. It is described in more 6348details below. 6349 6350=item command_as_argument 6351 6352This is the type of a command given in argument of C<@itemize>, 6353C<@table>, C<@vtable> or C<@ftable>. For example in 6354 6355 @itemize @bullet 6356 @item item 6357 @end itemize 6358 6359the element corresponding with bullet has the following keys: 6360 6361 'cmdname' => 'bullet' 6362 'type' => 'command_as_argument' 6363 6364The parent @-command has an entry in extra for the I<command_as_argument> 6365element: 6366 6367 'cmdname' => 'itemize' 6368 'extra => {'command_as_argument' => $command_element_as_argument} 6369 6370=item index_entry_command 6371 6372This is the type of index entry command like C<@cindex>, and, more 6373importantly user-defined index entry commands. So for example if there 6374is 6375 6376 @defindex foo 6377 ... 6378 6379 @fooindex index entry 6380 6381the C<@fooindex> @-command element will have the I<index_entry_command> 6382type. 6383 6384=item following_arg 6385 6386This type is set for non-alphabetic accent @-commands that don't use braces 6387but instead have their argument right after them, as 6388 6389 @~n 6390 6391=item space_command_arg 6392 6393This type is set for accent @-commands that don't use brace but instead 6394have their argument after some space, as 6395 6396 @ringaccent A 6397 6398=item definfoenclose_command 6399 6400This type is set for an @-command that is redefined by C<@definfoenclose>. 6401The beginning is in C<< {'extra'}->{'begin'} >> and the end in 6402C<< {'extra'}->{'end'} >>. 6403 6404=back 6405 6406=head3 Types for text elements 6407 6408The text elements may have the following types (or may have no type 6409at all): 6410 6411=over 6412 6413=item empty_line 6414 6415An empty line (possibly containing whitespace characters only). 6416 6417=item empty_line_after_command 6418 6419=item empty_spaces_after_command 6420 6421The text is spaces for I<empty_spaces_after_command> 6422or spaces followed by a newline for 6423I<empty_line_after_command>, appearing after an @-command that 6424takes an argument on the line or a block @-command. 6425 6426=item empty_spaces_before_argument 6427 6428The text is spaces appearing after an opening brace or after a 6429comma separating a command's arguments. 6430 6431=item spaces_at_end 6432 6433Space at the end of an argument to a line command, at the end of an 6434comma-separated argument for some brace commands, or at the end of 6435bracketed content on a C<@multitable> line or definition line. 6436 6437=item empty_spaces_after_close_brace 6438 6439Spaces appearing after a closing brace, for some rare commands for which 6440this space should be ignorable (like C<@caption>). 6441 6442=item empty_spaces_before_paragraph 6443 6444Space appearing before a paragraph beginning. 6445 6446=item raw 6447 6448Text in an environment where it should be kept as is (in C<@verbatim>, 6449C<@verb>, C<@html>, C<@macro> body). 6450 6451=item last_raw_newline 6452 6453The last end of line in a raw block (except for C<@verbatim>). 6454 6455=item preamble_text 6456 6457Text appearing before real content, including the C<\input texinfo.tex>. 6458 6459=item space_at_end_menu_node 6460 6461=item after_description_line 6462 6463Space after a node in the menu entry, when there is no description, 6464and space appearing after the description line. 6465 6466=back 6467 6468=head3 Types of container elements 6469 6470The other types of element are the following. These are containers with 6471other elements appearing in their C<contents>. 6472 6473=over 6474 6475=item text_root 6476 6477=item document_root 6478 6479=item root_line 6480 6481These types correspond to document roots. C<text_root> is the document 6482root when there is no C<@node> or sectioning command. When 6483such a command appears, a new root container is used, C<document_root>, 6484and C<text_root> becomes the first element in the contents of C<document_root>. 6485C<root_line> is the type of the root tree when parsing Texinfo line 6486fragments using C<parse_texi_line>. 6487 6488=item preamble 6489 6490This container holds the text appearing before the first content, including 6491the C<\input texinfo.tex> line and following blank lines. 6492 6493=item preamble_before_setfilename 6494 6495This container holds everything that appears before C<@setfilename> 6496if I<IGNORE_BEFORE_SETFILENAME> parser option is set. 6497 6498=item paragraph 6499 6500A paragraph. The C<contents> of a paragraph (like other container 6501elements for Texinfo content) are elements representing the contents of 6502the paragraph in the order they occur, such as simple text elements 6503without a C<cmdname> or C<type>, or @-command elements for commands 6504appearing in the paragraph. 6505 6506=item preformatted 6507 6508Texinfo code within a format that is not filled. Happens within some 6509block commands like C<@example>, but also in menu (in menu descriptions, 6510menu comments...). 6511 6512=item brace_command_arg 6513 6514=item brace_command_context 6515 6516=item line_arg 6517 6518=item block_line_arg 6519 6520Those containers occur within the C<args> array of @-commands taking an 6521argument. I<brace_command_arg> is used for the arguments to commands 6522taking arguments surrounded by braces (and in some cases separated by 6523commas). I<brace_command_context> is used for @-commands with braces 6524that start a new context (C<@footnote>, C<@caption>, C<@math>). 6525 6526I<line_arg> is used for commands that take the texinfo code on the 6527rest of the line as their argument (for example (C<@settitle>, C<@node>, 6528C<@section> and similar). I<block_line_arg> is similar but is used for 6529commands that start a new block (which is to be ended with C<@end>). 6530 6531For example 6532 6533 @code{in code} 6534 6535leads to 6536 6537 {'cmdname' => 'code', 6538 'args' => [{'type' => 'brace_command_arg', 6539 'contents' => [{'text' => 'in code'}]}]} 6540 6541=item misc_arg 6542 6543Used for the arguments to some special line commands whose arguments 6544aren't subject to the usual macro expansion. For example C<@set>, 6545C<@clickstyle>, C<@unmacro>, C<@comment>. The argument is associated to 6546the I<text> key. 6547 6548=item menu_entry 6549 6550=item menu_entry_leading_text 6551 6552=item menu_entry_name 6553 6554=item menu_entry_separator 6555 6556=item menu_entry_node 6557 6558=item menu_entry_description 6559 6560A I<menu_entry> holds a full menu entry, like 6561 6562 * node:: description. 6563 6564The different elements of the menu entry are directly in the 6565I<menu_entry> C<args> array reference. 6566 6567I<menu_entry_leading_text> holds the star and following spaces. 6568I<menu_entry_name> is the menu entry name (if present), I<menu_entry_node> 6569corresponds to the node in the menu entry, I<menu_entry_separator> holds 6570the text after the node and before the description, in most cases 6571C<:: >. Lastly, I<menu_entry_description> is for the description. 6572 6573=item menu_comment 6574 6575The I<menu_comment> container holds what is between menu entries 6576in menus. For example in 6577 6578 @menu 6579 Menu title 6580 6581 * entry:: 6582 6583 Between entries 6584 * other:: 6585 @end menu 6586 6587Both 6588 6589 Menu title 6590 6591and 6592 6593 Between entries 6594 6595will be in I<menu_comment>. 6596 6597=item macro_name 6598 6599=item macro_arg 6600 6601Taken from C<@macro> definition and put in the C<args> key array of 6602the macro, I<macro_name> is the type of the text fragment corresponding 6603to the macro name, I<macro_arg> is the type of the text fragments 6604correponding to macro formal arguments. 6605 6606=item before_item 6607 6608A container for content before the first C<@item> of block @-commands 6609with items (C<@table>, C<@multitable>, C<@enumerate>...). 6610 6611=item table_entry 6612 6613=item table_term 6614 6615=item table_item 6616 6617=item inter_item 6618 6619Those containers appear in C<@table>, C<@ftable> and C<@vtable>. 6620A I<table_entry> container contains an entire row of the table. 6621It contains a I<table_term> container, which holds all the C<@item> and 6622C<@itemx> lines. This is followed by a I<table_item> container, which 6623holds the content that is to go into the second column of the table. 6624 6625If there is any content before an C<@itemx> (normally only comments, 6626empty lines or maybe index entries are allowed), it will be in 6627a container with type I<inter_item>. 6628 6629=item def_line 6630 6631=item def_item 6632 6633=item inter_def_item 6634 6635The I<def_line> type is either associated with a container within a 6636definition command, or is the type of a definition command with a x 6637form, like C<@deffnx>. It holds the definition line arguments. 6638The container with type I<def_item> holds the definition text content. 6639Content appearing before a definition command with a x form is in 6640an I<inter_def_item> container. 6641 6642=item multitable_head 6643 6644=item multitable_body 6645 6646=item row 6647 6648In C<@multitable>, a I<multitable_head> container contains all the rows 6649with C<@headitem>, while I<multitable_body> contains the rows associated 6650with C<@item>. A I<row> container contains the C<@item> and @<tab> 6651forming a row. 6652 6653=item bracketed 6654 6655This a special type containing content in brackets in the context 6656where they are valid, in C<@math>. 6657 6658=item bracketed_def_content 6659 6660Content in brackets on definition command lines. 6661 6662=item def_aggregate 6663 6664Contains several elements that together are a single unit on a @def* line. 6665 6666=item bracketed_multitable_prototype 6667 6668=item row_prototype 6669 6670On C<@multitable> line, content in brackets is in 6671I<bracketed_multitable_prototype>, text not in brackets 6672is in I<row_prototype>. 6673 6674=back 6675 6676=head2 Information available in the extra key 6677 6678=head3 Extra keys available for more than one @-command 6679 6680=over 6681 6682=item end_command 6683 6684The C<@end> associated to the block @-command. 6685 6686=item missing_argument 6687 6688Set for some @-commands with line arguments and a missing argument. 6689 6690=item arg_line 6691 6692The string correspond to the line after the @-command 6693for @-commands that have special arguments on their line, 6694and for C<@macro> line. 6695 6696=item text_arg 6697 6698The string correspond to the line after the @-command for @-commands 6699that have an argument interpreted as simple text, like C<@setfilename>, 6700C<@end> or C<@documentencoding>. 6701 6702=item index_entry 6703 6704The index entry information (described in L</index_entries> 6705in details) is associated to @-commands that have an associated 6706index entry. 6707 6708=item misc_args 6709 6710An array holding strings, the arguments of @-commands taking simple 6711textual arguments as arguments, like C<@everyheadingmarks>, 6712C<@frenchspacing>, C<@alias>, C<@synindex>, C<@columnfractions>. 6713Also filled for C<@set>, C<@clickstyle>, C<@unmacro> or C<@comment> 6714arguments. 6715 6716=item spaces_before_argument 6717 6718For @-commands with opening brace followed by spaces held in a 6719C<empty_spaces_before_argument> element, a reference to those spaces. 6720 6721=item spaces 6722 6723For accent commands acting on one letter only, like C<@ringaccent> 6724appearing like 6725 6726 @ringaccent A 6727 6728there is a I<spaces> key which holds the spaces appearing between 6729the command and the argument. 6730 6731=back 6732 6733=head3 Extra keys specific of certain @-commands or containers 6734 6735=over 6736 6737=item C<@macro> 6738 6739I<invalid_syntax> is set if there was an error on the C<@macro> 6740line. I<arg_line> holds the line after C<@macro>. 6741 6742=item C<@node> 6743 6744The arguments are in the I<nodes_manuals> array. Each 6745of the entries is a hash with a I<node_content> key for 6746an array holding the corresponding content, a I<manual_content> key 6747if there is an associated external manual name, and a I<normalized> 6748key for the normalized label, built as specified in the Texinfo manual 6749in the B<HTML Xref> node. 6750 6751An I<associated_section> key holds the tree element of the 6752sectioning command that follows the node. 6753 6754=item C<@part> 6755 6756The next sectioning command is in I<part_associated_section>. 6757 6758=item sectioning command 6759 6760The node preceding the command is in I<associated_node>. 6761The part preceding the command is in I<associated_part>. 6762If the level of the document was modified by C<@raisections> 6763or C<@lowersections>, the differential level is in I<sections_level>. 6764 6765=item C<@float> 6766 6767=item C<@listoffloats> 6768 6769If float has a second argument, and for C<@listoffloats> 6770argument there is a I<type> key which is also a hash reference, 6771with two keys. I<content> is an array holding the associated 6772contents, I<normalized> holds the normalized float type. 6773 6774I<caption> and I<shortcaption> holds the corresponding 6775tree elements for float. The C<@caption> or C<@shortcaption> 6776have the float tree element stored in I<float>. 6777 6778=item C<@float> 6779 6780=item C<@anchor> 6781 6782@-commands that are targets for cross-references have a I<normalized> 6783key for the normalized label, built as specified in the Texinfo manual 6784in the B<HTML Xref> node. There is also a I<node_content> key for 6785an array holding the corresponding content. 6786 6787C<@anchor> also has I<region> set to the special region name if 6788in a special region (C<@copying>, C<@titlepage>). 6789 6790=item C<@ref> 6791 6792=item C<@xref> 6793 6794=item C<@pxref> 6795 6796=item C<@inforef> 6797 6798The I<node_argument> entry holds a parsed node entry, like 6799the one appearing in the I<nodes_manuals> array for C<@node>. 6800 6801=item C<@abbr> 6802 6803=item C<@acronym> 6804 6805The first argument normalized is in I<normalized>. 6806 6807=item definition command 6808 6809I<def_command> holds the command name, without x if it is 6810an x form of a definition command. 6811I<original_def_cmdname> is the original def command. 6812 6813If it is an x form, it has I<not_after_command> set if not 6814appearing after the definition command without x. 6815 6816=item def_line 6817 6818For each element in a def_line, the key I<def_role> holds a string 6819describing the meaning of the element. It is one of 6820I<category>, I<name>, I<class>, I<type>, I<arg>, I<typearg>, 6821I<spaces> or I<delimiter>, depending on the definition. 6822 6823The I<def_parsed_hash> hash reference has these strings as keys, 6824and the values are the corresponding elements. 6825 6826=item C<@multitable> 6827 6828The key I<max_columns> holds the maximal number of columns. If there 6829are prototypes on the line they are in the array associated with 6830I<prototypes>. If there is a C<@columnfractions> as argument, then the 6831I<columnfractions> key is associated with the element for the 6832@columnfractions command. 6833 6834=item C<@enumerate> 6835 6836The extra key I<enumerate_specification> contains the enumerate 6837argument. 6838 6839=item C<@itemize> 6840 6841=item C<@table> 6842 6843=item C<@vtable> 6844 6845=item C<@ftable> 6846 6847The I<command_as_argument> extra key points to the @-command on 6848as argument on the @-command line. 6849 6850=item paragraph 6851 6852The I<indent> or I<noindent> key value is set if the corresponding 6853@-commands are associated with that paragraph. 6854 6855=item C<@item> in C<@enumerate> or C<@itemize> 6856 6857The I<item_number> extra key holds the number of this item. 6858 6859=item C<@item> and C<@tab> in C<@multitable> 6860 6861The I<cell_number> index key holds the index of the column of 6862the cell. 6863 6864=item row 6865 6866The I<row_number> index key holds the index of the row in 6867the C<@multitable>. 6868 6869=item C<@author> 6870 6871If in a C<@titlepage>, the titlepage is in I<titlepage>, if in 6872C<@quotation> or C<@smallquotation>, the corresponding tree element 6873is in I<quotation>. 6874 6875The author tree element is in the I<author> array of the C<@titlepage> 6876or the C<@quotation> or C<@smallquotation> it is associated with. 6877 6878=item C<@ifclear> 6879 6880=item C<@ifset> 6881 6882The original line is in I<line>. 6883 6884=item C<@end> 6885 6886The textual argument is in I<command_argument>. 6887The corresponding @-command is in I<command>. 6888 6889=item C<@documentencoding> 6890 6891The argument, normalized is in I<input_encoding_name> if it is recognized. 6892The corresponding perl encoding name is in I<input_perl_encoding>. 6893 6894=item C<@click> 6895 6896In I<clickstyle> there is the current clickstyle command. 6897 6898=item C<@kbd> 6899 6900I<code> is set depending on the context and C<@kbdinputstyle>. 6901 6902=item definfoenclose defined commands 6903 6904I<begin> holds the string beginning the definfoenclose, 6905I<end> holds the string ending the definfoenclose. 6906 6907=item menu_entry 6908 6909The I<menu_entry_description> and I<menu_entry_name> keys 6910are associated with the corresponding tree elements. The 6911I<menu_entry_node> value is a hash with information about the parsed 6912node entry; its keys are the same as those appearing in the 6913elements of the I<nodes_manuals> array for C<@node>. 6914 6915=item empty_line_after_command 6916 6917The corresponding command is in I<command>. 6918 6919=item C<@inlinefmt> 6920 6921=item C<@inlineraw> 6922 6923=item C<@inlinefmtifelse> 6924 6925=item C<@inlineifclear> 6926 6927=item C<@inlineifset> 6928 6929The first argument is in I<format>. If an argument has been determined 6930as being expanded by the Parser, the index of this argument is in 6931I<expand_index>. Index numbering begins at 0, but the first argument is 6932always the format or flag name, so, if set, it should be 1 or 2 for 6933C<@inlinefmtifelse>, and 1 for other commands. 6934 6935=back 6936 6937=head2 Other information set by the parser 6938 6939The parser creates an array of nodes and stores this in the 6940I<nodes> key of the parser object. 6941 6942Each element in the tree corresponding to a node contaning a menu 6943has a I<menus> key which refers to an array of references to menu 6944elements occuring in the node. 6945 6946These are both used by the C<Texinfo::Structuring> module. 6947 6948 6949 6950=head1 SEE ALSO 6951 6952L<Texinfo manual|http://www.gnu.org/s/texinfo/manual/texinfo/> 6953 6954=head1 AUTHOR 6955 6956Patrice Dumas, E<lt>pertusus@free.frE<gt> 6957 6958=cut 6959