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