[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
branch master updated: * tp/Texinfo/ParserNonXS.pm (_parse_texi, _proces
From: |
Patrice Dumas |
Subject: |
branch master updated: * tp/Texinfo/ParserNonXS.pm (_parse_texi, _process_remaining_on_line): add _process_remaining_on_line to match better with the XS parser. |
Date: |
Sat, 10 Sep 2022 07:33:15 -0400 |
This is an automated email from the git hooks/post-receive script.
pertusus pushed a commit to branch master
in repository texinfo.
The following commit(s) were added to refs/heads/master by this push:
new 46bfa18bb0 * tp/Texinfo/ParserNonXS.pm (_parse_texi,
_process_remaining_on_line): add _process_remaining_on_line to match better
with the XS parser.
46bfa18bb0 is described below
commit 46bfa18bb02d1523d5d50038ddf039e4e8c6543f
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sat Sep 10 13:33:05 2022 +0200
* tp/Texinfo/ParserNonXS.pm (_parse_texi, _process_remaining_on_line):
add _process_remaining_on_line to match better with the XS parser.
---
ChangeLog | 5 +
tp/Texinfo/ParserNonXS.pm | 3591 +++++++++++++++++++-------------------
tp/Texinfo/XS/parsetexi/parser.c | 5 +-
3 files changed, 1828 insertions(+), 1773 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ed2c824e34..38eb1b22a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2022-09-10 Patrice Dumas <pertusus@free.fr>
+
+ * tp/Texinfo/ParserNonXS.pm (_parse_texi, _process_remaining_on_line):
+ add _process_remaining_on_line to match better with the XS parser.
+
2022-09-10 Patrice Dumas <pertusus@free.fr>
Remove last_raw_newline
diff --git a/tp/Texinfo/ParserNonXS.pm b/tp/Texinfo/ParserNonXS.pm
index 170d2ee230..422ca1b51c 100644
--- a/tp/Texinfo/ParserNonXS.pm
+++ b/tp/Texinfo/ParserNonXS.pm
@@ -3277,7 +3277,7 @@ sub _end_line($$$)
my $line = $text;
if ($line =~ s/^([[:alnum:]][[:alnum:]-]+)//) {
$end_command = $1;
-
+
if (!exists $block_commands{$end_command}) {
$self->_command_warn($current, $source_info,
__("unknown \@end %s"), $end_command);
@@ -3903,1898 +3903,1945 @@ sub _setup_document_root_and_before_node_section()
return ($document_root, $before_node_section);
}
-# the main subroutine
-sub _parse_texi($$$)
-{
- my ($self, $root, $current) = @_;
-
- my $source_info;
-
- NEXT_LINE:
- while (1) {
- my $line;
- ($line, $source_info) = _next_text($self, $source_info);
- last if (!defined($line));
-
- if ($self->{'DEBUG'}) {
- my $line_text = '';
- $line_text = "$source_info->{'line_nr'}.$source_info->{'macro'}"
- if ($source_info);
- print STDERR "NEW LINE("
- .join('|', $self->_get_context_stack())
- .":@{$self->{'conditionals_stack'}}:$line_text): $line";
- #print STDERR "CONTEXT_STACK
".join('|',$self->_get_context_stack())."\n";
- #print STDERR " $current:
".Texinfo::Common::debug_print_element_short($current)."\n";
- }
+my $STILL_MORE_TO_PROCESS = 0;
+my $GET_A_NEW_LINE = 1;
+my $FINISHED_TOTALLY = -1;
- if (not
- # all the format handled early that have specific containers
- # 'raw' command or ignored conditional or verb or ignored raw format
- (($current->{'cmdname'}
- and $block_commands{$current->{'cmdname'}}
- and ($block_commands{$current->{'cmdname'}} eq 'raw'
- or $block_commands{$current->{'cmdname'}} eq 'conditional'))
- or
- ($current->{'parent'} and $current->{'parent'}->{'cmdname'}
- and $current->{'parent'}->{'cmdname'} eq 'verb')
- or
- ($current->{'cmdname'}
- and $format_raw_commands{$current->{'cmdname'}}
- and not $self->{'expanded_formats_hash'}->{$current->{'cmdname'}})
- )
- # not def line
- and $self->_top_context() ne 'ct_def') {
- next NEXT_LINE if _check_line_directive ($self, $line, $source_info);
- print STDERR "BEGIN LINE\n" if ($self->{'DEBUG'});
+# return values:
+# $STILL_MORE_TO_PROCESS: when there is more to process on the line
+# $GET_A_NEW_LINE: when we need to read a new line
+# $FINISHED_TOTALLY: found @bye, end of processing
+sub _process_remaining_on_line($$$$)
+{
+ my $self = shift;
+ my $current = shift;
+ my $line = shift;
+ my $source_info = shift;
- if ($current->{'contents'}
- and $current->{'contents'}->[-1]
- and $current->{'contents'}->[-1]->{'type'}
- and $current->{'contents'}->[-1]->{'type'}
- eq 'empty_spaces_before_argument') {
- # Empty spaces after brace or comma till the end of line.
- # Remove this element and update 'extra' values.
- _abort_empty_line($self, $current);
+ my $retval = $STILL_MORE_TO_PROCESS;
+
+ # in a 'raw' (verbatim, ignore, (r)macro)
+ if ($current->{'cmdname'}
+ and $block_commands{$current->{'cmdname'}}
+ and ($block_commands{$current->{'cmdname'}} eq 'raw')) {
+ # r?macro may be nested
+ if (($current->{'cmdname'} eq 'macro'
+ or $current->{'cmdname'} eq 'rmacro')
+ and $line =~ /^\s*\@r?macro\s+/) {
+ $line =~ s/\s*\@(r?macro)//;
+ push @{$current->{'contents'}}, { 'cmdname' => $1,
+ 'parent' => $current,
+ 'contents' => [],
+ 'extra' => {'arg_line' => $line }};
+ $current = $current->{'contents'}->[-1];
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ } elsif ($line =~ /^(\s*?)\@end\s+([a-zA-Z][\w-]*)/
+ and ($2 eq $current->{'cmdname'})) {
+ if ($line =~ s/^(\s+)//) {
+ push @{$current->{'contents'}},
+ { 'text' => $1,
+ 'type' => 'raw', 'parent' => $current };
+ $self->_line_warn(sprintf(
+ __("\@end %s should only appear at the beginning of a line"),
+ $current->{'cmdname'}), $source_info);
}
- $line =~ s/^([^\S\r\n]*)//;
- push @{$current->{'contents'}}, { 'type' => 'empty_line',
- 'text' => $1,
- 'parent' => $current };
- }
-
- while (1) {
- # in a 'raw' (verbatim, ignore, (r)macro)
- if ($current->{'cmdname'}
- and $block_commands{$current->{'cmdname'}}
- and ($block_commands{$current->{'cmdname'}} eq 'raw')) {
- # r?macro may be nested
- if (($current->{'cmdname'} eq 'macro'
- or $current->{'cmdname'} eq 'rmacro')
- and $line =~ /^\s*\@r?macro\s+/) {
- $line =~ s/\s*\@(r?macro)//;
- push @{$current->{'contents'}}, { 'cmdname' => $1,
- 'parent' => $current,
- 'contents' => [],
- 'extra' => {'arg_line' => $line }};
- $current = $current->{'contents'}->[-1];
- last;
- } elsif ($line =~ /^(\s*?)\@end\s+([a-zA-Z][\w-]*)/
- and ($2 eq $current->{'cmdname'})) {
- if ($line =~ s/^(\s+)//) {
- push @{$current->{'contents'}},
- { 'text' => $1,
- 'type' => 'raw', 'parent' => $current };
- $self->_line_warn(sprintf(
- __("\@end %s should only appear at the beginning of a line"),
- $current->{'cmdname'}), $source_info);
- }
- # store toplevel macro specification
- if (($current->{'cmdname'} eq 'macro' or $current->{'cmdname'} eq
'rmacro')
- and (! $current->{'parent'}
- or !$current->{'parent'}->{'cmdname'}
- or ($current->{'parent'}->{'cmdname'} ne 'macro'
- and $current->{'parent'}->{'cmdname'} ne 'rmacro'))) {
- my $macrobody =
- Texinfo::Convert::Texinfo::convert_to_texinfo(
- { 'contents' => $current->{'contents'} });
- if ($current->{'args'} and $current->{'args'}->[0]) {
- my $name = $current->{'args'}->[0]->{'text'};
- if (exists($self->{'macros'}->{$name})) {
- $self->_line_warn(sprintf(__("macro `%s' previously defined"),
- $name), $current->{'source_info'});
- $self->_line_warn(sprintf(__(
- "here is the previous definition of `%s'"),
- $name),
$self->{'macros'}->{$name}->{'element'}->{'source_info'});
- }
- if ($all_commands{$name}
- or ($name eq 'txiinternalvalue'
- and $self->{'accept_internalvalue'})) {
- $self->_line_warn(sprintf(__(
- "redefining Texinfo language command: \@%s"),
- $name), $current->{'source_info'});
- }
- if (!$current->{'extra'}->{'invalid_syntax'}) {
- $self->{'macros'}->{$name} = {
- 'element' => $current,
- 'macrobody' => $macrobody
- };
- }
- }
- }
- print STDERR "CLOSED raw $current->{'cmdname'}\n" if
($self->{'DEBUG'});
- # start a new line for the @end line (without the first spaces on
- # the line that have already been put in a raw container).
- # This is normally done at the beginning of a line, but not here,
- # as we directly got the line. As the @end is processed just below,
- # an empty line will not appear in the output, but it is needed to
- # avoid a duplicate warning on @end not appearing at the beginning
- # of the line
- push @{$current->{'contents'}}, { 'type' => 'empty_line',
- 'text' => '',
- 'parent' => $current };
- } else {
- push @{$current->{'contents'}},
- { 'text' => $line, 'type' => 'raw', 'parent' => $current };
- last;
- }
- # in ignored conditional block command
- } elsif ($current->{'cmdname'}
- and $block_commands{$current->{'cmdname'}}
- and ($block_commands{$current->{'cmdname'}} eq 'conditional')) {
- # check for nested @ifset (so that @end ifset doesn't end the
- # outermost @ifset). It is discarded when the outermost is.
- if (($current->{'cmdname'} eq 'ifclear'
- or $current->{'cmdname'} eq 'ifset'
- or $current->{'cmdname'} eq 'ifcommanddefined'
- or $current->{'cmdname'} eq 'ifcommandnotdefined')
- and $line =~ /^\s*\@$current->{'cmdname'}/) {
- push @{$current->{'contents'}}, { 'cmdname' => $current->{'cmdname'},
- 'parent' => $current,
- 'contents' => [],
- };
- $current = $current->{'contents'}->[-1];
- } elsif ($line =~ /^(\s*?)\@end\s+([a-zA-Z][\w-]*)/
- and ($2 eq $current->{'cmdname'})) {
- my $end_command = $current->{'cmdname'};
- $line =~ s/^(\s*?)\@end\s+$end_command//;
- if ($1 ne '') {
- $self->_line_warn(sprintf(
- __("\@end %s should only appear at the beginning of a line"),
- $end_command), $source_info);
- }
- $self->_line_warn(sprintf(
- __("superfluous argument to \@%s %s: %s"), 'end', $end_command,
- $line), $source_info)
- if ($line =~ /\S/ and $line !~ /^\s*\@c(omment)?\b/);
- $current = $current->{'parent'};
- # don't store ignored @if*
- my $conditional = pop @{$current->{'contents'}};
- if (!defined($conditional->{'cmdname'}
- or $conditional->{'cmdname'} ne $end_command)) {
- $self->_bug_message(
- "Ignored command is not the conditional $end_command",
- $source_info, $conditional);
- die;
- }
- print STDERR "CLOSED conditional $end_command\n" if
($self->{'DEBUG'});
- # Ignore until end of line
- # FIXME this is not the same as for other commands. Change?
- if ($line !~ /\n/) {
- ($line, $source_info) = _new_line($self, $source_info);
- print STDERR "IGNORE CLOSE line: $line" if ($self->{'DEBUG'});
+ # store toplevel macro specification
+ if (($current->{'cmdname'} eq 'macro' or $current->{'cmdname'} eq
'rmacro')
+ and (! $current->{'parent'}
+ or !$current->{'parent'}->{'cmdname'}
+ or ($current->{'parent'}->{'cmdname'} ne 'macro'
+ and $current->{'parent'}->{'cmdname'} ne 'rmacro'))) {
+ my $macrobody =
+ Texinfo::Convert::Texinfo::convert_to_texinfo(
+ { 'contents' => $current->{'contents'} });
+ if ($current->{'args'} and $current->{'args'}->[0]) {
+ my $name = $current->{'args'}->[0]->{'text'};
+ if (exists($self->{'macros'}->{$name})) {
+ $self->_line_warn(sprintf(__("macro `%s' previously defined"),
+ $name), $current->{'source_info'});
+ $self->_line_warn(sprintf(__(
+ "here is the previous definition of `%s'"),
+ $name), $self->{'macros'}->{$name}->{'element'}->{'source_info'});
}
- }
- # anything remaining on the line and any other line is ignored here
- last;
- # in @verb. type should be 'brace_command_arg'
- } elsif ($current->{'parent'} and $current->{'parent'}->{'cmdname'}
- and $current->{'parent'}->{'cmdname'} eq 'verb') {
- # collect the first character if not already done
- if (!defined($current->{'parent'}->{'extra'}->{'delimiter'})) {
- if ($line =~ /^$/) {
- $current->{'parent'}->{'extra'}->{'delimiter'} = '';
- $self->_line_error(sprintf(
- __("\@%s without associated character"), 'verb'),
$source_info);
- } else {
- $line =~ s/^(.)//;
- $current->{'parent'}->{'extra'}->{'delimiter'} = $1;
+ if ($all_commands{$name}
+ or ($name eq 'txiinternalvalue'
+ and $self->{'accept_internalvalue'})) {
+ $self->_line_warn(sprintf(__(
+ "redefining Texinfo language command: \@%s"),
+ $name), $current->{'source_info'});
}
- }
- my $char = quotemeta($current->{'parent'}->{'extra'}->{'delimiter'});
- if ($line =~ s/^(.*?)$char\}/\}/) {
- push @{$current->{'contents'}},
- { 'text' => $1, 'type' => 'raw', 'parent' => $current }
- if ($1 ne '');
- print STDERR "END VERB\n" if ($self->{'DEBUG'});
- } else {
- push @{$current->{'contents'}},
- { 'text' => $line, 'type' => 'raw', 'parent' => $current };
- print STDERR "LINE VERB: $line" if ($self->{'DEBUG'});
- last;
- }
- } elsif ($current->{'cmdname'}
- and $format_raw_commands{$current->{'cmdname'}}
- and not
$self->{'expanded_formats_hash'}->{$current->{'cmdname'}}) {
- push @{$current->{'contents'}}, { 'type' => 'elided_block',
- 'contents' => [],
- 'parent' => $current };
- while (not $line =~ /^\s*\@end\s+$current->{'cmdname'}/) {
- ($line, $source_info) = _new_line($self, $source_info);
- if (!$line) {
- # unclosed block
- $line = '';
- last;
+ if (!$current->{'extra'}->{'invalid_syntax'}) {
+ $self->{'macros'}->{$name} = {
+ 'element' => $current,
+ 'macrobody' => $macrobody
+ };
}
}
- # start a new line for the @end line, this is normally done
- # at the beginning of a line, but not here, as we directly
- # got the lines.
- $line =~ s/^([^\S\r\n]*)//;
- push @{$current->{'contents'}}, { 'type' => 'empty_line',
- 'text' => $1,
- 'parent' => $current };
- # It is important to let the processing continue from here, such that
- # the @end is catched and handled below, as the condition has not
changed
}
- # this mostly happens in the following cases:
- # after expansion of user defined macro that doesn't end with EOL
- # after a protection of @\n in @def* line
- # at the end of an expanded Texinfo fragment
- while ($line eq '') {
- print STDERR "EMPTY TEXT\n"
- if ($self->{'DEBUG'});
- ($line, $source_info) = _next_text($self, $source_info);
- if (!defined($line)) {
- # end of the file or of a text fragment.
- $current = _end_line($self, $current, $source_info);
- # It may happen that there is an @include file on the line, it
- # will be picked up at NEXT_LINE, beginning a new line
- next NEXT_LINE;
- }
+ print STDERR "CLOSED raw $current->{'cmdname'}\n" if ($self->{'DEBUG'});
+ # start a new line for the @end line (without the first spaces on
+ # the line that have already been put in a raw container).
+ # This is normally done at the beginning of a line, but not here,
+ # as we directly got the line. As the @end is processed just below,
+ # an empty line will not appear in the output, but it is needed to
+ # avoid a duplicate warning on @end not appearing at the beginning
+ # of the line
+ push @{$current->{'contents'}}, { 'type' => 'empty_line',
+ 'text' => '',
+ 'parent' => $current };
+ } else {
+ push @{$current->{'contents'}},
+ { 'text' => $line, 'type' => 'raw', 'parent' => $current };
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
+ # in ignored conditional block command
+ } elsif ($current->{'cmdname'}
+ and $block_commands{$current->{'cmdname'}}
+ and ($block_commands{$current->{'cmdname'}} eq 'conditional')) {
+ # check for nested @ifset (so that @end ifset doesn't end the
+ # outermost @ifset). It is discarded when the outermost is.
+ if (($current->{'cmdname'} eq 'ifclear'
+ or $current->{'cmdname'} eq 'ifset'
+ or $current->{'cmdname'} eq 'ifcommanddefined'
+ or $current->{'cmdname'} eq 'ifcommandnotdefined')
+ and $line =~ /^\s*\@$current->{'cmdname'}/) {
+ push @{$current->{'contents'}}, { 'cmdname' => $current->{'cmdname'},
+ 'parent' => $current,
+ 'contents' => [],
+ };
+ $current = $current->{'contents'}->[-1];
+ } elsif ($line =~ /^(\s*?)\@end\s+([a-zA-Z][\w-]*)/
+ and ($2 eq $current->{'cmdname'})) {
+ my $end_command = $current->{'cmdname'};
+ $line =~ s/^(\s*?)\@end\s+$end_command//;
+ if ($1 ne '') {
+ $self->_line_warn(sprintf(
+ __("\@end %s should only appear at the beginning of a line"),
+ $end_command), $source_info);
}
+ $self->_line_warn(sprintf(
+ __("superfluous argument to \@%s %s: %s"), 'end', $end_command,
+ $line), $source_info)
+ if ($line =~ /\S/ and $line !~ /^\s*\@c(omment)?\b/);
+ $current = $current->{'parent'};
+ # don't store ignored @if*
+ my $conditional = pop @{$current->{'contents'}};
+ if (!defined($conditional->{'cmdname'}
+ or $conditional->{'cmdname'} ne $end_command)) {
+ $self->_bug_message(
+ "Ignored command is not the conditional $end_command",
+ $source_info, $conditional);
+ die;
+ }
+ print STDERR "CLOSED conditional $end_command\n" if ($self->{'DEBUG'});
+ # Ignore until end of line
+ # FIXME this is not the same as for other commands. Change?
+ if ($line !~ /\n/) {
+ ($line, $source_info) = _new_line($self, $source_info);
+ print STDERR "IGNORE CLOSE line: $line" if ($self->{'DEBUG'});
+ }
+ }
+ # anything remaining on the line and any other line is ignored here
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ # in @verb. type should be 'brace_command_arg'
+ } elsif ($current->{'parent'} and $current->{'parent'}->{'cmdname'}
+ and $current->{'parent'}->{'cmdname'} eq 'verb') {
+ # collect the first character if not already done
+ if (!defined($current->{'parent'}->{'extra'}->{'delimiter'})) {
+ if ($line =~ /^$/) {
+ $current->{'parent'}->{'extra'}->{'delimiter'} = '';
+ $self->_line_error(sprintf(
+ __("\@%s without associated character"), 'verb'), $source_info);
+ } else {
+ $line =~ s/^(.)//;
+ $current->{'parent'}->{'extra'}->{'delimiter'} = $1;
+ }
+ }
+ my $char = quotemeta($current->{'parent'}->{'extra'}->{'delimiter'});
+ if ($line =~ s/^(.*?)$char\}/\}/) {
+ push @{$current->{'contents'}},
+ { 'text' => $1, 'type' => 'raw', 'parent' => $current }
+ if ($1 ne '');
+ print STDERR "END VERB\n" if ($self->{'DEBUG'});
+ } else {
+ push @{$current->{'contents'}},
+ { 'text' => $line, 'type' => 'raw', 'parent' => $current };
+ print STDERR "LINE VERB: $line" if ($self->{'DEBUG'});
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
+ } elsif ($current->{'cmdname'}
+ and $format_raw_commands{$current->{'cmdname'}}
+ and not $self->{'expanded_formats_hash'}->{$current->{'cmdname'}}) {
+ push @{$current->{'contents'}}, { 'type' => 'elided_block',
+ 'contents' => [],
+ 'parent' => $current };
+ while (not $line =~ /^\s*\@end\s+$current->{'cmdname'}/) {
+ ($line, $source_info) = _new_line($self, $source_info);
+ if (!$line) {
+ # unclosed block
+ $line = '';
+ last;
+ }
+ }
+ # start a new line for the @end line, this is normally done
+ # at the beginning of a line, but not here, as we directly
+ # got the lines.
+ $line =~ s/^([^\S\r\n]*)//;
+ push @{$current->{'contents'}}, { 'type' => 'empty_line',
+ 'text' => $1,
+ 'parent' => $current };
+ # It is important to let the processing continue from here, such that
+ # the @end is catched and handled below, as the condition has not changed
+ }
+ # this mostly happens in the following cases:
+ # after expansion of user defined macro that doesn't end with EOL
+ # after a protection of @\n in @def* line
+ # at the end of an expanded Texinfo fragment
+ while ($line eq '') {
+ print STDERR "EMPTY TEXT\n"
+ if ($self->{'DEBUG'});
+ ($line, $source_info) = _next_text($self, $source_info);
+ if (!defined($line)) {
+ # end of the file or of a text fragment.
+ $current = _end_line($self, $current, $source_info);
+ # It may happen that there is an @include file on the line, it
+ # will be picked up at NEXT_LINE, beginning a new line
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
+ }
- my $at_command_length;
- my @line_parsing = _parse_texi_regex($line);
- my ($at_command, $open_brace, $asterisk, $single_letter_command,
- $separator_match, $misc_text) = @line_parsing;
- print STDERR "PARSED: ".join(', ', map {!defined($_) ? 'UNDEF' : "'$_'"}
@line_parsing)."\n"
- if ($self->{'DEBUG'} and $self->{'DEBUG'} > 3);
-
- my $command;
- if ($single_letter_command) {
- $command = $single_letter_command;
- } elsif ($at_command) {
- $at_command_length = length($at_command) + 1;
- $command = $at_command;
-
- my $alias_command;
- if (exists($self->{'aliases'}->{$command})) {
- $alias_command = $command;
- $command = $self->{'aliases'}->{$command};
- }
-
+ my $at_command_length;
+ my @line_parsing = _parse_texi_regex($line);
+ my ($at_command, $open_brace, $asterisk, $single_letter_command,
+ $separator_match, $misc_text) = @line_parsing;
+ print STDERR "PARSED: ".join(', ', map {!defined($_) ? 'UNDEF' : "'$_'"}
@line_parsing)."\n"
+ if ($self->{'DEBUG'} and $self->{'DEBUG'} > 3);
+
+ my $command;
+ if ($single_letter_command) {
+ $command = $single_letter_command;
+ } elsif ($at_command) {
+ $at_command_length = length($at_command) + 1;
+ $command = $at_command;
+
+ my $alias_command;
+ if (exists($self->{'aliases'}->{$command})) {
+ $alias_command = $command;
+ $command = $self->{'aliases'}->{$command};
+ }
- # handle user defined macros before anything else since
- # their expansion may lead to changes in the line
- if ($self->{'macros'}->{$command}) {
- substr($line, 0, $at_command_length) = '';
-
- my $expanded_macro = $self->{'macros'}->{$command}->{'element'};
- my $args_number = scalar(@{$expanded_macro->{'args'}}) -1;
- my $arguments = [];
- if ($line =~ s/^\s*{\s*//) { # macro with args
- ($arguments, $line, $source_info)
- = _expand_macro_arguments($self, $expanded_macro, $line,
$source_info);
- } elsif (($args_number >= 2) or ($args_number <1)) {
- # as agreed on the bug-texinfo mailing list, no warn when zero
- # arg and not called with {}.
- $self->_line_warn(sprintf(__(
- "\@%s defined with zero or more than one argument should be invoked with
{}"),
- $command), $source_info)
- if ($args_number >= 2);
- } else {
- if ($line !~ /\n/) {
- ($line, $source_info) = _new_line($self, $source_info);
- $line = '' if (!defined($line));
- }
- $line =~ s/^\s*// if ($line =~ /\S/);
- my $has_end_of_line = chomp $line;
- $arguments = [$line];
- $line = "\n" if ($has_end_of_line);
- }
- my $expanded = _expand_macro_body($self,
- $self->{'macros'}->{$command},
- $arguments, $source_info);
- print STDERR "MACROBODY: $expanded".'||||||'."\n"
- if ($self->{'DEBUG'});
- # empty result. It is ignored here.
- if ($expanded eq '') {
- next;
- }
- if ($self->{'MAX_MACRO_CALL_NESTING'}
- and scalar(@{$self->{'macro_stack'}}) >
$self->{'MAX_MACRO_CALL_NESTING'}) {
- $self->_line_warn(sprintf(__(
- "macro call nested too deeply (set MAX_NESTED_MACROS to override; current
value %d)"),
- $self->{'MAX_MACRO_CALL_NESTING'}),
$source_info);
- next;
- }
- if ($expanded_macro->{'cmdname'} eq 'macro') {
- my $found = 0;
- foreach my $macro (@{$self->{'macro_stack'}}) {
- if ($macro->{'args'}->[0]->{'text'} eq $command) {
- $self->_line_error(sprintf(__(
- "recursive call of macro %s is not allowed; use \@rmacro if
needed"),
- $command), $source_info);
- $found = 1;
- last;
- }
- }
- next if ($found);
- }
- my $expanded_lines = _text_to_lines($expanded);
- next if (!@$expanded_lines);
- chomp ($expanded_lines->[-1]);
- pop @$expanded_lines if ($expanded_lines->[-1] eq '');
- print STDERR "MACRO EXPANSION LINES: ".join('|', @$expanded_lines)
- ."|\nEND LINES MACRO EXPANSION\n" if
($self->{'DEBUG'});
- next if (!@$expanded_lines);
- unshift @{$self->{'macro_stack'}}, $expanded_macro;
- print STDERR "UNSHIFT MACRO_STACK:
$expanded_macro->{'args'}->[0]->{'text'}\n"
- if ($self->{'DEBUG'});
- my $new_lines = _complete_line_nr($expanded_lines,
- $source_info->{'line_nr'},
$source_info->{'file_name'},
- $expanded_macro->{'args'}->[0]->{'text'}, 1);
- $source_info->{'end_macro'} = 1;
- # first put the line that was interrupted by the macro call
- # on the input pending text with information stack
- unshift @{$self->{'input'}->[0]->{'pending'}}, [$line, $source_info];
- # current line is the first from macro expansion
- my $new_text = shift @$new_lines;
- ($line, $source_info) = ($new_text->[0], $new_text->[1]);
- # then put the following macro expansion lines with information on
the
- # pending text with information stack
- unshift @{$self->{'input'}->[0]->{'pending'}}, @$new_lines;
- next;
+ # handle user defined macros before anything else since
+ # their expansion may lead to changes in the line
+ if ($self->{'macros'}->{$command}) {
+ substr($line, 0, $at_command_length) = '';
+
+ my $expanded_macro = $self->{'macros'}->{$command}->{'element'};
+ my $args_number = scalar(@{$expanded_macro->{'args'}}) -1;
+ my $arguments = [];
+ if ($line =~ s/^\s*{\s*//) { # macro with args
+ ($arguments, $line, $source_info)
+ = _expand_macro_arguments($self, $expanded_macro, $line,
$source_info);
+ } elsif (($args_number >= 2) or ($args_number <1)) {
+ # as agreed on the bug-texinfo mailing list, no warn when zero
+ # arg and not called with {}.
+ $self->_line_warn(sprintf(__(
+ "\@%s defined with zero or more than one argument should be invoked with {}"),
+ $command), $source_info)
+ if ($args_number >= 2);
+ } else {
+ if ($line !~ /\n/) {
+ ($line, $source_info) = _new_line($self, $source_info);
+ $line = '' if (!defined($line));
}
- # expand value if it can change the line. It considered again
- # together with other commands below for all the other cases
- # which may need a well formed tree, which is not needed here, and
- # early value expansion may be needed to provide with an argument.
- if ($command eq 'value') {
- my $expanded_line = $line;
- substr($expanded_line, 0, $at_command_length) = '';
- $expanded_line =~ s/^\s*//
- if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'});
- # REVALUE
- if ($expanded_line =~ s/^{([\w\-][^\s{\\}~`\^+"<>|@]*)}//) {
- my $value = $1;
- if (exists($self->{'values'}->{$value})) {
- $line = $self->{'values'}->{$value} . $expanded_line;
- next;
- }
+ $line =~ s/^\s*// if ($line =~ /\S/);
+ my $has_end_of_line = chomp $line;
+ $arguments = [$line];
+ $line = "\n" if ($has_end_of_line);
+ }
+ my $expanded = _expand_macro_body($self,
+ $self->{'macros'}->{$command},
+ $arguments, $source_info);
+ print STDERR "MACROBODY: $expanded".'||||||'."\n"
+ if ($self->{'DEBUG'});
+ # empty result. It is ignored here.
+ if ($expanded eq '') {
+ goto funexit;
+ }
+ if ($self->{'MAX_MACRO_CALL_NESTING'}
+ and scalar(@{$self->{'macro_stack'}}) >
$self->{'MAX_MACRO_CALL_NESTING'}) {
+ $self->_line_warn(sprintf(__(
+ "macro call nested too deeply (set MAX_NESTED_MACROS to override; current
value %d)"),
+ $self->{'MAX_MACRO_CALL_NESTING'}),
$source_info);
+ goto funexit;
+ }
+ if ($expanded_macro->{'cmdname'} eq 'macro') {
+ my $found = 0;
+ foreach my $macro (@{$self->{'macro_stack'}}) {
+ if ($macro->{'args'}->[0]->{'text'} eq $command) {
+ $self->_line_error(sprintf(__(
+ "recursive call of macro %s is not allowed; use \@rmacro if
needed"),
+ $command), $source_info);
+ $found = 1;
+ last;
}
}
- #substr($line, 0, $at_command_length) = '';
+ goto funexit if ($found);
}
- # special case for @-command as argument of @itemize or @*table.
- # The normal case for those are to be identifier only, not a true command
- # with argument, so can be followed by anything. If followed by
- # braces, will be handled as a normal brace command.
- #
- # Need to be done as early as possible such that no other condition
- # prevail and lead to a missed command
- if ($current->{'cmdname'}
- and defined($brace_commands{$current->{'cmdname'}})
- and !$open_brace
- and _command_with_command_as_argument($current->{'parent'})) {
- print STDERR "FOR PARENT
\@$current->{'parent'}->{'parent'}->{'cmdname'} ".
- "command_as_argument $current->{'cmdname'}\n" if
($self->{'DEBUG'});
- $current->{'type'} = 'command_as_argument' if (!$current->{'type'});
- $current->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'}
- = $current;
- if ($current->{'cmdname'} eq 'kbd'
- and _kbd_formatted_as_code($self,
$current->{'parent'}->{'parent'})) {
-
$current->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument_kbd_code'} =
1;
+ my $expanded_lines = _text_to_lines($expanded);
+ goto funexit if (!@$expanded_lines);
+ chomp ($expanded_lines->[-1]);
+ pop @$expanded_lines if ($expanded_lines->[-1] eq '');
+ print STDERR "MACRO EXPANSION LINES: ".join('|', @$expanded_lines)
+ ."|\nEND LINES MACRO EXPANSION\n" if
($self->{'DEBUG'});
+ goto funexit if (!@$expanded_lines);
+ unshift @{$self->{'macro_stack'}}, $expanded_macro;
+ print STDERR "UNSHIFT MACRO_STACK:
$expanded_macro->{'args'}->[0]->{'text'}\n"
+ if ($self->{'DEBUG'});
+ my $new_lines = _complete_line_nr($expanded_lines,
+ $source_info->{'line_nr'}, $source_info->{'file_name'},
+ $expanded_macro->{'args'}->[0]->{'text'}, 1);
+ $source_info->{'end_macro'} = 1;
+ # first put the line that was interrupted by the macro call
+ # on the input pending text with information stack
+ unshift @{$self->{'input'}->[0]->{'pending'}}, [$line, $source_info];
+ # current line is the first from macro expansion
+ my $new_text = shift @$new_lines;
+ ($line, $source_info) = ($new_text->[0], $new_text->[1]);
+ # then put the following macro expansion lines with information on the
+ # pending text with information stack
+ unshift @{$self->{'input'}->[0]->{'pending'}}, @$new_lines;
+ goto funexit;
+ }
+ # expand value if it can change the line. It considered again
+ # together with other commands below for all the other cases
+ # which may need a well formed tree, which is not needed here, and
+ # early value expansion may be needed to provide with an argument.
+ if ($command eq 'value') {
+ my $expanded_line = $line;
+ substr($expanded_line, 0, $at_command_length) = '';
+ $expanded_line =~ s/^\s*//
+ if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'});
+ # REVALUE
+ if ($expanded_line =~ s/^{([\w\-][^\s{\\}~`\^+"<>|@]*)}//) {
+ my $value = $1;
+ if (exists($self->{'values'}->{$value})) {
+ $line = $self->{'values'}->{$value} . $expanded_line;
+ goto funexit;
}
- $current = $current->{'parent'};
}
+ }
+ #substr($line, 0, $at_command_length) = '';
+ }
+
+ # special case for @-command as argument of @itemize or @*table.
+ # The normal case for those are to be identifier only, not a true command
+ # with argument, so can be followed by anything. If followed by
+ # braces, will be handled as a normal brace command.
+ #
+ # Need to be done as early as possible such that no other condition
+ # prevail and lead to a missed command
+ if ($current->{'cmdname'}
+ and defined($brace_commands{$current->{'cmdname'}})
+ and !$open_brace
+ and _command_with_command_as_argument($current->{'parent'})) {
+ print STDERR "FOR PARENT \@$current->{'parent'}->{'parent'}->{'cmdname'} ".
+ "command_as_argument $current->{'cmdname'}\n" if ($self->{'DEBUG'});
+ $current->{'type'} = 'command_as_argument' if (!$current->{'type'});
+ $current->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'}
+ = $current;
+ if ($current->{'cmdname'} eq 'kbd'
+ and _kbd_formatted_as_code($self, $current->{'parent'}->{'parent'})) {
+
$current->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument_kbd_code'} =
1;
+ }
+ $current = $current->{'parent'};
+ }
+
+ # command but before an opening brace, otherwise $current
+ # would be an argument type and not the command, and a new
+ # @-command was found. This means that the $current->{'cmdname'}
+ # argument (an opening brace, or a character after spaces for
+ # accent commands) was not found and there is already a new command.
+ #
+ # It would have been nice to allow for comments, but there is no
+ # container in the tree to put them when after command and before brace
+ # or argument for accent commands.
+ if ($command
+ and $current->{'cmdname'}
+ and defined($brace_commands{$current->{'cmdname'}})) {
+ $self->_line_error(sprintf(__("\@%s expected braces"),
+ $current->{'cmdname'}), $source_info);
+ $current = $current->{'parent'};
+ }
- # command but before an opening brace, otherwise $current
- # would be an argument type and not the command, and a new
- # @-command was found. This means that the $current->{'cmdname'}
- # argument (an opening brace, or a character after spaces for
- # accent commands) was not found and there is already a new command.
- #
- # It would have been nice to allow for comments, but there is no
- # container in the tree to put them when after command and before brace
- # or argument for accent commands.
- if ($command
- and $current->{'cmdname'}
- and defined($brace_commands{$current->{'cmdname'}})) {
+ # handle unknown @-command
+ if ($command and !$all_commands{$command}
+ and !$self->{'definfoenclose'}->{$command}
+ and !$self->{'command_index'}->{$command}
+ # @txiinternalvalue is invalid unless accept_internalvalue is set
+ and !($command eq 'txiinternalvalue'
+ and $self->{'accept_internalvalue'})) {
+ $self->_line_error(sprintf(__("unknown command `%s'"),
+ $command), $source_info);
+ substr($line, 0, $at_command_length) = '';
+ _abort_empty_line($self, $current);
+ my $paragraph = _begin_paragraph($self, $current, $source_info);
+ $current = $paragraph if ($paragraph);
+ goto funexit;
+ }
+
+ # this situation arises when after the $current->{'cmdname'}
+ # Brace commands not followed immediately by a brace
+ # opening. In particular cases that may lead to "command closing"
+ # or following character association with an @-command, for accent
+ # commands.
+
+ # This condition can only happen immediately after the command opening,
+ # otherwise the current element is in the 'args' and not right in the
+ # command container.
+ if ($current->{'cmdname'}
+ and defined($brace_commands{$current->{'cmdname'}})
+ and !$open_brace) {
+ print STDERR "BRACE CMD: no brace after \@$current->{'cmdname'}: $line"
+ if $self->{'DEBUG'};
+ # Note that non ascii spaces do not count as spaces
+ if ($line =~ /^(\s+)/
+ and ($accent_commands{$current->{'cmdname'}}
+ or $self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'})) {
+ my $added_space = $1;
+ my $additional_newline;
+ if ($added_space =~ /\n/) {
+ $self->_line_warn(sprintf(
+ __("command `\@%s' must not be followed by new line"),
+ $current->{'cmdname'}), $source_info);
+ $additional_newline = 1;
+ }
+ if (!defined($current->{'extra'}->{'spaces'})) {
+ $line =~ s/^(\s+)//;
+ $current->{'extra'}->{'spaces'} = $added_space;
+ print STDERR "BRACE CMD before brace init spaces '$added_space'\n"
+ if $self->{'DEBUG'};
+ # only ignore spaces and one newline, two newlines lead to
+ # an empty line before the brace or argument which is incorrect.
+ } elsif ($additional_newline
+ and $current->{'extra'}->{'spaces'} =~ /\n/) {
+ print STDERR "BRACE CMD before brace second newline stops spaces\n"
+ if $self->{'DEBUG'};
$self->_line_error(sprintf(__("\@%s expected braces"),
$current->{'cmdname'}), $source_info);
$current = $current->{'parent'};
+ } else {
+ $line =~ s/^(\s+)//;
+ $current->{'extra'}->{'spaces'} .= $added_space;
+ print STDERR "BRACE CMD before brace add spaces '$added_space'\n"
+ if $self->{'DEBUG'};
}
-
- # handle unknown @-command
- if ($command and !$all_commands{$command}
- and !$self->{'definfoenclose'}->{$command}
- and !$self->{'command_index'}->{$command}
- # @txiinternalvalue is invalid unless accept_internalvalue is set
- and !($command eq 'txiinternalvalue'
- and $self->{'accept_internalvalue'})) {
- $self->_line_error(sprintf(__("unknown command `%s'"),
- $command), $source_info);
- substr($line, 0, $at_command_length) = '';
- _abort_empty_line($self, $current);
- my $paragraph = _begin_paragraph($self, $current, $source_info);
- $current = $paragraph if ($paragraph);
- next;
+ # special case for accent commands, use following character except @
+ # as argument. Note that since we checked before that there isn't
+ # an @-command opening, there should not be an @ anyway. The line
+ # may possibly be empty in some specific case, without end of line.
+ } elsif ($accent_commands{$current->{'cmdname'}}
+ and $line =~ s/^([^@])//) {
+ print STDERR "ACCENT following_arg \@$current->{'cmdname'}\n"
+ if ($self->{'DEBUG'});
+ my $following_arg = {'type' => 'following_arg',
+ 'parent' => $current};
+ $following_arg->{'contents'} = [{ 'text' => $1,
+ 'parent' => $following_arg } ];
+ $current->{'args'} = [ $following_arg ];
+ if ($current->{'cmdname'} eq 'dotless' and $1 ne 'i' and $1 ne 'j') {
+ $self->_line_error(sprintf(
+ __("%c%s expects `i' or `j' as argument, not `%s'"),
+ ord('@'), $current->{'cmdname'}, $1),
+ $source_info);
}
-
- # this situation arises when after the $current->{'cmdname'}
- # Brace commands not followed immediately by a brace
- # opening. In particular cases that may lead to "command closing"
- # or following character association with an @-command, for accent
- # commands.
-
- # This condition can only happen immediately after the command opening,
- # otherwise the current element is in the 'args' and not right in the
- # command container.
- if ($current->{'cmdname'}
- and defined($brace_commands{$current->{'cmdname'}})
- and !$open_brace) {
- print STDERR "BRACE CMD: no brace after \@$current->{'cmdname'}: $line"
- if $self->{'DEBUG'};
- # Note that non ascii spaces do not count as spaces
- if ($line =~ /^(\s+)/
- and ($accent_commands{$current->{'cmdname'}}
- or $self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'})) {
- my $added_space = $1;
- my $additional_newline;
- if ($added_space =~ /\n/) {
- $self->_line_warn(sprintf(
- __("command `\@%s' must not be followed by new line"),
- $current->{'cmdname'}), $source_info);
- $additional_newline = 1;
- }
- if (!defined($current->{'extra'}->{'spaces'})) {
- $line =~ s/^(\s+)//;
- $current->{'extra'}->{'spaces'} = $added_space;
- print STDERR "BRACE CMD before brace init spaces '$added_space'\n"
- if $self->{'DEBUG'};
- # only ignore spaces and one newline, two newlines lead to
- # an empty line before the brace or argument which is incorrect.
- } elsif ($additional_newline
- and $current->{'extra'}->{'spaces'} =~ /\n/) {
- print STDERR "BRACE CMD before brace second newline stops spaces\n"
- if $self->{'DEBUG'};
- $self->_line_error(sprintf(__("\@%s expected braces"),
- $current->{'cmdname'}), $source_info);
- $current = $current->{'parent'};
- } else {
- $line =~ s/^(\s+)//;
- $current->{'extra'}->{'spaces'} .= $added_space;
- print STDERR "BRACE CMD before brace add spaces '$added_space'\n"
- if $self->{'DEBUG'};
- }
- # special case for accent commands, use following character except @
- # as argument. Note that since we checked before that there isn't
- # an @-command opening, there should not be an @ anyway. The line
- # may possibly be empty in some specific case, without end of line.
- } elsif ($accent_commands{$current->{'cmdname'}}
- and $line =~ s/^([^@])//) {
- print STDERR "ACCENT following_arg \@$current->{'cmdname'}\n"
- if ($self->{'DEBUG'});
- my $following_arg = {'type' => 'following_arg',
- 'parent' => $current};
- $following_arg->{'contents'} = [{ 'text' => $1,
- 'parent' => $following_arg } ];
- $current->{'args'} = [ $following_arg ];
- if ($current->{'cmdname'} eq 'dotless' and $1 ne 'i' and $1 ne 'j') {
- $self->_line_error(sprintf(
- __("%c%s expects `i' or `j' as argument, not `%s'"),
- ord('@'), $current->{'cmdname'}, $1),
- $source_info);
- }
- $current = $current->{'parent'};
- } else {
- $self->_line_error(sprintf(__("\@%s expected braces"),
- $current->{'cmdname'}), $source_info);
- $current = $current->{'parent'};
- }
- # maybe a menu entry beginning: a * at the beginning of a menu line
- } elsif ($current->{'type'}
- and $current->{'type'} eq 'preformatted'
- and $current->{'parent'}->{'type'}
- and ($current->{'parent'}->{'type'} eq 'menu_comment'
- or $current->{'parent'}->{'type'} eq
'menu_entry_description')
- and $asterisk
- and @{$current->{'contents'}}
- and $current->{'contents'}->[-1]->{'type'}
- and $current->{'contents'}->[-1]->{'type'} eq 'empty_line'
- and $current->{'contents'}->[-1]->{'text'} eq '') {
- print STDERR "MENU STAR\n" if ($self->{'DEBUG'});
- _abort_empty_line($self, $current);
- $line =~ s/^\*//;
- push @{$current->{'contents'}}, { 'parent' => $current,
- 'type' => 'menu_star',
- 'text' => '*' };
- # a space after a * at the beginning of a menu line
- } elsif ($current->{'contents'} and @{$current->{'contents'}}
- and $current->{'contents'}->[-1]->{'type'}
- and $current->{'contents'}->[-1]->{'type'} eq 'menu_star') {
- if ($line !~ /^\s+/) {
- print STDERR "ABORT MENU STAR ($line)\n" if ($self->{'DEBUG'});
- delete $current->{'contents'}->[-1]->{'type'};
- } else {
- print STDERR "MENU ENTRY (certainly)\n" if ($self->{'DEBUG'});
- # this is the menu star collected previously
- pop @{$current->{'contents'}};
- $line =~ s/^(\s+)//;
- my $leading_text = '*' . $1;
- if ($current->{'type'} eq 'preformatted'
- and $current->{'parent'}->{'type'}
- and $current->{'parent'}->{'type'} eq 'menu_comment') {
- my $menu = $current->{'parent'}->{'parent'};
- if (!@{$current->{'contents'}}) {
- pop @{$current->{'parent'}->{'contents'}};
- if (!scalar(@{$current->{'parent'}->{'contents'}})) {
- pop @{$menu->{'contents'}};
- }
- }
- $current = $menu;
- } else {
- # first parent preformatted, third is menu_entry
- if ($current->{'type'} ne 'preformatted'
- or $current->{'parent'}->{'type'} ne 'menu_entry_description'
- or $current->{'parent'}->{'parent'}->{'type'} ne 'menu_entry'
- or
!$menu_commands{$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'}}) {
- $self->_bug_message("Not in menu comment nor description",
- $source_info, $current);
- }
- $current = $current->{'parent'}->{'parent'}->{'parent'};
+ $current = $current->{'parent'};
+ } else {
+ $self->_line_error(sprintf(__("\@%s expected braces"),
+ $current->{'cmdname'}), $source_info);
+ $current = $current->{'parent'};
+ }
+ # maybe a menu entry beginning: a * at the beginning of a menu line
+ } elsif ($current->{'type'}
+ and $current->{'type'} eq 'preformatted'
+ and $current->{'parent'}->{'type'}
+ and ($current->{'parent'}->{'type'} eq 'menu_comment'
+ or $current->{'parent'}->{'type'} eq 'menu_entry_description')
+ and $asterisk
+ and @{$current->{'contents'}}
+ and $current->{'contents'}->[-1]->{'type'}
+ and $current->{'contents'}->[-1]->{'type'} eq 'empty_line'
+ and $current->{'contents'}->[-1]->{'text'} eq '') {
+ print STDERR "MENU STAR\n" if ($self->{'DEBUG'});
+ _abort_empty_line($self, $current);
+ $line =~ s/^\*//;
+ push @{$current->{'contents'}}, { 'parent' => $current,
+ 'type' => 'menu_star',
+ 'text' => '*' };
+ # a space after a * at the beginning of a menu line
+ } elsif ($current->{'contents'} and @{$current->{'contents'}}
+ and $current->{'contents'}->[-1]->{'type'}
+ and $current->{'contents'}->[-1]->{'type'} eq 'menu_star') {
+ if ($line !~ /^\s+/) {
+ print STDERR "ABORT MENU STAR ($line)\n" if ($self->{'DEBUG'});
+ delete $current->{'contents'}->[-1]->{'type'};
+ } else {
+ print STDERR "MENU ENTRY (certainly)\n" if ($self->{'DEBUG'});
+ # this is the menu star collected previously
+ pop @{$current->{'contents'}};
+ $line =~ s/^(\s+)//;
+ my $leading_text = '*' . $1;
+ if ($current->{'type'} eq 'preformatted'
+ and $current->{'parent'}->{'type'}
+ and $current->{'parent'}->{'type'} eq 'menu_comment') {
+ my $menu = $current->{'parent'}->{'parent'};
+ if (!@{$current->{'contents'}}) {
+ pop @{$current->{'parent'}->{'contents'}};
+ if (!scalar(@{$current->{'parent'}->{'contents'}})) {
+ pop @{$menu->{'contents'}};
}
- push @{$current->{'contents'}}, { 'type' => 'menu_entry',
- 'parent' => $current,
- };
- $current = $current->{'contents'}->[-1];
- $current->{'args'} = [ { 'type' => 'menu_entry_leading_text',
- 'text' => $leading_text,
- 'parent' => $current },
- { 'type' => 'menu_entry_name',
- 'contents' => [],
- 'parent' => $current } ];
- $current = $current->{'args'}->[-1];
- }
- # after a separator in menu
- } elsif ($current->{'args'} and @{$current->{'args'}}
- and $current->{'args'}->[-1]->{'type'}
- and $current->{'args'}->[-1]->{'type'} eq
'menu_entry_separator') {
- print STDERR "AFTER menu_entry_separator\n" if ($self->{'DEBUG'});
- my $separator = $current->{'args'}->[-1]->{'text'};
- # separator is ::, we concatenate and let the while restart
- # in order to collect spaces below
- if ($separator eq ':' and $line =~ s/^(:)//) {
- $current->{'args'}->[-1]->{'text'} .= $1;
- # a . not followed by a space. Not a separator.
- } elsif ($separator eq '.' and $line =~ /^\S/) {
- pop @{$current->{'args'}};
- $current = $current->{'args'}->[-1];
- $current = _merge_text($self, $current, $separator);
- # here we collect spaces following separators.
- } elsif ($line =~ s/^([^\S\r\n]+)//) {
- # FIXME a trailing end of line could be considered to be part
- # of the separator. Right now it is part of the description,
- # since it is catched (in the next while) as one of the case below
- $current->{'args'}->[-1]->{'text'} .= $1;
- # now handle the menu part that was closed
- } elsif ($separator =~ /^::/) {
- print STDERR "MENU NODE no entry $separator\n" if ($self->{'DEBUG'});
- # it was previously registered as menu_entry_name, it is
- # changed to node
- $current->{'args'}->[-2]->{'type'} = 'menu_entry_node';
- $current = _enter_menu_entry_node($self, $current, $source_info);
- # end of the menu entry name
- } elsif ($separator =~ /^:/) {
- print STDERR "MENU ENTRY $separator\n" if ($self->{'DEBUG'});
- push @{$current->{'args'}}, { 'type' => 'menu_entry_node',
- 'contents' => [],
- 'parent' => $current };
- $current = $current->{'args'}->[-1];
- # anything else is the end of the menu node following a menu_entry_name
- } else {
- print STDERR "MENU NODE $separator\n" if ($self->{'DEBUG'});
- $current = _enter_menu_entry_node($self, $current, $source_info);
}
- # Any other @-command.
- } elsif ($command) {
- if (!$at_command) {
- substr($line, 0, 2) = '';
- } else {
- substr($line, 0, $at_command_length) = '';
+ $current = $menu;
+ } else {
+ # first parent preformatted, third is menu_entry
+ if ($current->{'type'} ne 'preformatted'
+ or $current->{'parent'}->{'type'} ne 'menu_entry_description'
+ or $current->{'parent'}->{'parent'}->{'type'} ne 'menu_entry'
+ or
!$menu_commands{$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'}}) {
+ $self->_bug_message("Not in menu comment nor description",
+ $source_info, $current);
}
+ $current = $current->{'parent'}->{'parent'}->{'parent'};
+ }
+ push @{$current->{'contents'}}, { 'type' => 'menu_entry',
+ 'parent' => $current,
+ };
+ $current = $current->{'contents'}->[-1];
+ $current->{'args'} = [ { 'type' => 'menu_entry_leading_text',
+ 'text' => $leading_text,
+ 'parent' => $current },
+ { 'type' => 'menu_entry_name',
+ 'contents' => [],
+ 'parent' => $current } ];
+ $current = $current->{'args'}->[-1];
+ }
+ # after a separator in menu
+ } elsif ($current->{'args'} and @{$current->{'args'}}
+ and $current->{'args'}->[-1]->{'type'}
+ and $current->{'args'}->[-1]->{'type'} eq 'menu_entry_separator') {
+ print STDERR "AFTER menu_entry_separator\n" if ($self->{'DEBUG'});
+ my $separator = $current->{'args'}->[-1]->{'text'};
+ # separator is ::, we concatenate and let the while restart
+ # in order to collect spaces below
+ if ($separator eq ':' and $line =~ s/^(:)//) {
+ $current->{'args'}->[-1]->{'text'} .= $1;
+ # a . not followed by a space. Not a separator.
+ } elsif ($separator eq '.' and $line =~ /^\S/) {
+ pop @{$current->{'args'}};
+ $current = $current->{'args'}->[-1];
+ $current = _merge_text($self, $current, $separator);
+ # here we collect spaces following separators.
+ } elsif ($line =~ s/^([^\S\r\n]+)//) {
+ # FIXME a trailing end of line could be considered to be part
+ # of the separator. Right now it is part of the description,
+ # since it is catched (in the next while) as one of the case below
+ $current->{'args'}->[-1]->{'text'} .= $1;
+ # now handle the menu part that was closed
+ } elsif ($separator =~ /^::/) {
+ print STDERR "MENU NODE no entry $separator\n" if ($self->{'DEBUG'});
+ # it was previously registered as menu_entry_name, it is
+ # changed to node
+ $current->{'args'}->[-2]->{'type'} = 'menu_entry_node';
+ $current = _enter_menu_entry_node($self, $current, $source_info);
+ # end of the menu entry name
+ } elsif ($separator =~ /^:/) {
+ print STDERR "MENU ENTRY $separator\n" if ($self->{'DEBUG'});
+ push @{$current->{'args'}}, { 'type' => 'menu_entry_node',
+ 'contents' => [],
+ 'parent' => $current };
+ $current = $current->{'args'}->[-1];
+ # anything else is the end of the menu node following a menu_entry_name
+ } else {
+ print STDERR "MENU NODE $separator\n" if ($self->{'DEBUG'});
+ $current = _enter_menu_entry_node($self, $current, $source_info);
+ }
+ # Any other @-command.
+ } elsif ($command) {
+ if (!$at_command) {
+ substr($line, 0, 2) = '';
+ } else {
+ substr($line, 0, $at_command_length) = '';
+ }
- print STDERR "COMMAND $command\n" if ($self->{'DEBUG'});
+ print STDERR "COMMAND $command\n" if ($self->{'DEBUG'});
- # @value not expanded (expansion is done above), and @txiinternalvalue
- if ($command eq 'value' or $command eq 'txiinternalvalue') {
- $line =~ s/^\s*//
- if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'});
- # REVALUE
- if ($line =~ s/^{([\w\-][^\s{\\}~`\^+"<>|@]*)}//) {
- my $value = $1;
- if ($command eq 'value') {
- if (not exists($self->{'values'}->{$value})) {
- _abort_empty_line($self, $current);
- # caller should expand something along
- # gdt('@{No value for `{value}\'@}', {'value' => $value},
{'keep_texi'=> 1});
- push @{$current->{'contents'}}, { 'cmdname' => $command,
- 'type' => $value,
- 'contents' => [],
- 'parent' => $current };
- $self->_line_warn(
- sprintf(__("undefined flag: %s"), $value), $source_info);
- # expansion of value already done above
- #} else {
- }
- } else {
- # txiinternalvalue
- _abort_empty_line($self, $current);
- my $new_element = { 'cmdname' => $command,
- 'args' => [],
- 'parent' => $current };
- # type misc_arg?
- push @{$new_element->{'args'}}, {'text' => $value,
- 'parent' => $new_element};
- push @{$current->{'contents'}}, $new_element;
- }
- } else {
- $self->_line_error(sprintf(__("bad syntax for %c%s"), ord('@'),
- $command), $source_info);
- }
- next;
- }
-
- if (defined($deprecated_commands{$command})) {
- if ($deprecated_commands{$command} eq '') {
- $self->_line_warn(sprintf(__("%c%s is obsolete"),
- ord('@'), $command), $source_info);
- } else {
- $self->_line_warn(sprintf(__("%c%s is obsolete; %s"),
- ord('@'), $command,
- __($deprecated_commands{$command})),
- $source_info);
+ # @value not expanded (expansion is done above), and @txiinternalvalue
+ if ($command eq 'value' or $command eq 'txiinternalvalue') {
+ $line =~ s/^\s*//
+ if ($self->{'IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME'});
+ # REVALUE
+ if ($line =~ s/^{([\w\-][^\s{\\}~`\^+"<>|@]*)}//) {
+ my $value = $1;
+ if ($command eq 'value') {
+ if (not exists($self->{'values'}->{$value})) {
+ _abort_empty_line($self, $current);
+ # caller should expand something along
+ # gdt('@{No value for `{value}\'@}', {'value' => $value},
{'keep_texi'=> 1});
+ push @{$current->{'contents'}}, { 'cmdname' => $command,
+ 'type' => $value,
+ 'contents' => [],
+ 'parent' => $current };
+ $self->_line_warn(
+ sprintf(__("undefined flag: %s"), $value), $source_info);
+ # expansion of value already done above
+ #} else {
}
+ } else {
+ # txiinternalvalue
+ _abort_empty_line($self, $current);
+ my $new_element = { 'cmdname' => $command,
+ 'args' => [],
+ 'parent' => $current };
+ # type misc_arg?
+ push @{$new_element->{'args'}}, {'text' => $value,
+ 'parent' => $new_element};
+ push @{$current->{'contents'}}, $new_element;
}
+ } else {
+ $self->_line_error(sprintf(__("bad syntax for %c%s"), ord('@'),
+ $command), $source_info);
+ }
+ goto funexit;
+ }
- # special case with @ followed by a newline protecting end of lines
- # in @def*
- my $def_line_continuation
- = ($self->_top_context() eq 'ct_def' and $command eq "\n");
-
- if (not $def_line_continuation
- and not _abort_empty_line($self, $current)
- and $begin_line_commands{$command}) {
- $self->_line_warn(
- sprintf(__("\@%s should only appear at the beginning of a line"),
- $command), $source_info);
- }
+ if (defined($deprecated_commands{$command})) {
+ if ($deprecated_commands{$command} eq '') {
+ $self->_line_warn(sprintf(__("%c%s is obsolete"),
+ ord('@'), $command), $source_info);
+ } else {
+ $self->_line_warn(sprintf(__("%c%s is obsolete; %s"),
+ ord('@'), $command,
+ __($deprecated_commands{$command})),
+ $source_info);
+ }
+ }
- _check_valid_nesting ($self, $current, $command, $source_info);
+ # special case with @ followed by a newline protecting end of lines
+ # in @def*
+ my $def_line_continuation
+ = ($self->_top_context() eq 'ct_def' and $command eq "\n");
+
+ if (not $def_line_continuation
+ and not _abort_empty_line($self, $current)
+ and $begin_line_commands{$command}) {
+ $self->_line_warn(
+ sprintf(__("\@%s should only appear at the beginning of a line"),
+ $command), $source_info);
+ }
- last if ($def_line_continuation);
+ _check_valid_nesting ($self, $current, $command, $source_info);
- unless ($self->{'no_paragraph_commands'}->{$command}) {
- my $paragraph = _begin_paragraph($self, $current, $source_info);
- $current = $paragraph if ($paragraph);
- }
+ if ($def_line_continuation) {
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
- if ($self->{'close_paragraph_commands'}->{$command}) {
- $current = _end_paragraph($self, $current, $source_info);
- }
- if ($self->{'close_preformatted_commands'}->{$command}) {
- $current = _end_preformatted($self, $current, $source_info);
+ unless ($self->{'no_paragraph_commands'}->{$command}) {
+ my $paragraph = _begin_paragraph($self, $current, $source_info);
+ $current = $paragraph if ($paragraph);
+ }
+
+ if ($self->{'close_paragraph_commands'}->{$command}) {
+ $current = _end_paragraph($self, $current, $source_info);
+ }
+ if ($self->{'close_preformatted_commands'}->{$command}) {
+ $current = _end_preformatted($self, $current, $source_info);
+ }
+
+ if ($in_index_commands{$command}
+ and $current->{'contents'}
+ and $current->{'contents'}->[-1]
+ and $current->{'contents'}->[-1]->{'text'}
+ # it is important to check if in an index command, as otherwise
+ # the internal space type is not processed and remains as is in
+ # the final tree.
+ and _is_index_element($self, $current->{'parent'})) {
+ $current->{'contents'}->[-1]->{'text'} =~ s/(\s+)$//;
+ # an internal and temporary space type that is converted to
+ # a normal space without type if followed by text or a
+ # "spaces_at_end" if followed by spaces only when the
+ # index or subentry command is done.
+ my $space_type = 'spaces_before_brace_in_index';
+ if ($command eq 'subentry') {
+ $space_type = 'spaces_at_end';
+ }
+ if ($1 ne '') {
+ if ($current->{'contents'}->[-1]->{'text'} eq '') {
+ $current->{'contents'}->[-1]->{'text'} = $1;
+ $current->{'contents'}->[-1]->{'type'} = $space_type;
+ } else {
+ my $new_spaces = { 'text' => $1, 'parent' => $current,
+ 'type' => $space_type };
+ push @{$current->{'contents'}}, $new_spaces;
}
+ }
+ }
- if ($in_index_commands{$command}
- and $current->{'contents'}
- and $current->{'contents'}->[-1]
- and $current->{'contents'}->[-1]->{'text'}
- # it is important to check if in an index command, as otherwise
- # the internal space type is not processed and remains as is in
- # the final tree.
- and _is_index_element($self, $current->{'parent'})) {
- $current->{'contents'}->[-1]->{'text'} =~ s/(\s+)$//;
- # an internal and temporary space type that is converted to
- # a normal space without type if followed by text or a
- # "spaces_at_end" if followed by spaces only when the
- # index or subentry command is done.
- my $space_type = 'spaces_before_brace_in_index';
- if ($command eq 'subentry') {
- $space_type = 'spaces_at_end';
- }
- if ($1 ne '') {
- if ($current->{'contents'}->[-1]->{'text'} eq '') {
- $current->{'contents'}->[-1]->{'text'} = $1;
- $current->{'contents'}->[-1]->{'type'} = $space_type;
- } else {
- my $new_spaces = { 'text' => $1, 'parent' => $current,
- 'type' => $space_type };
- push @{$current->{'contents'}}, $new_spaces;
- }
+ if (defined($other_commands{$command})
+ and ($command ne 'item' or !_item_line_parent($current))) {
+ # noarg skipspace
+ my $arg_spec = $other_commands{$command};
+ my $misc;
+
+ if ($arg_spec eq 'noarg') {
+ if ($in_heading_commands{$command}) {
+ # TODO use a more generic system for check of @-command nesting
+ # in command on context stack
+ my $top_context_command = $self->_top_context_command();
+ if (not defined($top_context_command)
+ or not $headings_specification_commands{$top_context_command}) {
+ $self->_line_error(
+ sprintf(__("\@%s should only appear in heading or footing"),
+ $command), $source_info);
}
}
-
- if (defined($other_commands{$command})
- and ($command ne 'item' or !_item_line_parent($current))) {
- # noarg skipspace
- my $arg_spec = $other_commands{$command};
- my $misc;
-
- if ($arg_spec eq 'noarg') {
- if ($in_heading_commands{$command}) {
- # TODO use a more generic system for check of @-command nesting
- # in command on context stack
- my $top_context_command = $self->_top_context_command();
- if (not defined($top_context_command)
- or not
$headings_specification_commands{$top_context_command}) {
- $self->_line_error(
- sprintf(__("\@%s should only appear in heading or footing"),
- $command), $source_info);
- }
+ $misc = {'cmdname' => $command, 'parent' => $current};
+ push @{$current->{'contents'}}, $misc;
+ _register_global_command($self, $misc, $source_info);
+ $current = _begin_preformatted($self, $current)
+ if ($close_preformatted_commands{$command});
+ } else {
+ if ($command eq 'item'
+ or $command eq 'headitem' or $command eq 'tab') {
+ my $parent;
+ # @itemize or @enumerate
+ if ($parent = _item_container_parent($current)) {
+ if ($command eq 'item') {
+ print STDERR "ITEM_CONTAINER\n" if ($self->{'DEBUG'});
+ $parent->{'items_count'}++;
+ $misc = { 'cmdname' => $command, 'parent' => $parent,
+ 'contents' => [],
+ 'extra' =>
+ {'item_number' => $parent->{'items_count'}} };
+ push @{$parent->{'contents'}}, $misc;
+ $current = $parent->{'contents'}->[-1];
+ } else {
+ $self->_line_error(sprintf(__(
+ "\@%s not meaningful inside `\@%s' block"),
+ $command, $parent->{'cmdname'}), $source_info);
}
- $misc = {'cmdname' => $command, 'parent' => $current};
- push @{$current->{'contents'}}, $misc;
- _register_global_command($self, $misc, $source_info);
- $current = _begin_preformatted($self, $current)
- if ($close_preformatted_commands{$command});
- } else {
- if ($command eq 'item'
- or $command eq 'headitem' or $command eq 'tab') {
- my $parent;
- # @itemize or @enumerate
- if ($parent = _item_container_parent($current)) {
- if ($command eq 'item') {
- print STDERR "ITEM_CONTAINER\n" if ($self->{'DEBUG'});
- $parent->{'items_count'}++;
- $misc = { 'cmdname' => $command, 'parent' => $parent,
- 'contents' => [],
- 'extra' =>
- {'item_number' => $parent->{'items_count'}} };
- push @{$parent->{'contents'}}, $misc;
- $current = $parent->{'contents'}->[-1];
- } else {
- $self->_line_error(sprintf(__(
- "\@%s not meaningful inside `\@%s' block"),
- $command, $parent->{'cmdname'}),
$source_info);
- }
- $current = _begin_preformatted($self, $current);
- # @*table
- } elsif ($parent = _item_line_parent($current)) {
- # @item and _item_line_parent is explicitely avoided in the if
above
+ $current = _begin_preformatted($self, $current);
+ # @*table
+ } elsif ($parent = _item_line_parent($current)) {
+ # @item and _item_line_parent is explicitely avoided in the if
above
+ $self->_line_error(sprintf(__(
+ "\@%s not meaningful inside `\@%s' block"),
+ $command, $parent->{'cmdname'}), $source_info);
+ $current = _begin_preformatted($self, $current);
+ # @multitable
+ } elsif ($parent = _item_multitable_parent($current)) {
+ if (!$parent->{'extra'}->{'max_columns'}) {
+ $self->_line_warn(
+ sprintf(__("\@%s in empty multitable"),
+ $command), $source_info);
+ } elsif ($command eq 'tab') {
+ my $row = $parent->{'contents'}->[-1];
+ die if (!$row->{'type'});
+ if ($row->{'type'} eq 'before_item') {
+ $self->_line_error(__("\@tab before \@item"), $source_info);
+ } elsif ($row->{'cells_count'} >=
$parent->{'extra'}->{'max_columns'}) {
$self->_line_error(sprintf(__(
- "\@%s not meaningful inside `\@%s' block"),
- $command, $parent->{'cmdname'}), $source_info);
- $current = _begin_preformatted($self, $current);
- # @multitable
- } elsif ($parent = _item_multitable_parent($current)) {
- if (!$parent->{'extra'}->{'max_columns'}) {
- $self->_line_warn(
- sprintf(__("\@%s in empty multitable"),
- $command), $source_info);
- } elsif ($command eq 'tab') {
- my $row = $parent->{'contents'}->[-1];
- die if (!$row->{'type'});
- if ($row->{'type'} eq 'before_item') {
- $self->_line_error(__("\@tab before \@item"),
$source_info);
- } elsif ($row->{'cells_count'} >=
$parent->{'extra'}->{'max_columns'}) {
- $self->_line_error(sprintf(__(
- "too many columns in multitable item (max %d)"),
- $parent->{'extra'}->{'max_columns'}), $source_info);
- } else {
- $row->{'cells_count'}++;
- $misc = { 'cmdname' => $command,
- 'parent' => $row,
- 'contents' => [],
- 'extra' =>
- {'cell_number' => $row->{'cells_count'}} };
- push @{$row->{'contents'}}, $misc;
- $current = $row->{'contents'}->[-1];
- print STDERR "TAB\n" if ($self->{'DEBUG'});
- }
- } else {
- print STDERR "ROW\n" if ($self->{'DEBUG'});
- $parent->{'rows_count'}++;
- my $row = { 'type' => 'row', 'contents' => [],
- 'cells_count' => 1,
- 'extra' => {'row_number' =>
$parent->{'rows_count'} },
- 'parent' => $parent };
- push @{$parent->{'contents'}}, $row;
- $misc = { 'cmdname' => $command,
- 'parent' => $row,
- 'contents' => [],
- 'extra' => {'cell_number' => 1}};
- push @{$row->{'contents'}}, $misc;
- $current = $row->{'contents'}->[-1];
- }
- $current = _begin_preformatted($self, $current);
- } elsif ($command eq 'tab') {
- $self->_line_error(__(
- "ignoring \@tab outside of multitable"),
$source_info);
- $current = _begin_preformatted($self, $current);
+ "too many columns in multitable item (max %d)"),
+ $parent->{'extra'}->{'max_columns'}), $source_info);
} else {
- $self->_line_error(sprintf(__(
- "\@%s outside of table or list"), $command), $source_info);
- $current = _begin_preformatted($self, $current);
+ $row->{'cells_count'}++;
+ $misc = { 'cmdname' => $command,
+ 'parent' => $row,
+ 'contents' => [],
+ 'extra' =>
+ {'cell_number' => $row->{'cells_count'}} };
+ push @{$row->{'contents'}}, $misc;
+ $current = $row->{'contents'}->[-1];
+ print STDERR "TAB\n" if ($self->{'DEBUG'});
}
- $misc->{'source_info'} = $source_info if (defined($misc));
} else {
- $misc = { 'cmdname' => $command, 'parent' => $current,
- 'source_info' => $source_info };
- push @{$current->{'contents'}}, $misc;
+ print STDERR "ROW\n" if ($self->{'DEBUG'});
+ $parent->{'rows_count'}++;
+ my $row = { 'type' => 'row', 'contents' => [],
+ 'cells_count' => 1,
+ 'extra' => {'row_number' => $parent->{'rows_count'}
},
+ 'parent' => $parent };
+ push @{$parent->{'contents'}}, $row;
+ $misc = { 'cmdname' => $command,
+ 'parent' => $row,
+ 'contents' => [],
+ 'extra' => {'cell_number' => 1}};
+ push @{$row->{'contents'}}, $misc;
+ $current = $row->{'contents'}->[-1];
}
- $line = _start_empty_line_after_command($line, $current, $misc,
$command);
+ $current = _begin_preformatted($self, $current);
+ } elsif ($command eq 'tab') {
+ $self->_line_error(__(
+ "ignoring \@tab outside of multitable"), $source_info);
+ $current = _begin_preformatted($self, $current);
+ } else {
+ $self->_line_error(sprintf(__(
+ "\@%s outside of table or list"), $command), $source_info);
+ $current = _begin_preformatted($self, $current);
}
- # line commands
- } elsif (defined($self->{'line_commands'}->{$command})) {
- if ($root_commands{$command} or $command eq 'bye') {
- $current = _close_commands($self, $current, $source_info, undef,
- $command);
- if (!defined($current->{'parent'})) {
- # if parse_texi_line is called on a line with a node/section then
- # it will directly be in the root_line, otherwise it is not
directly
- # in the root, but in another container
- #
- # FIXME warn/error with a root command in parse_texi_line?
- if ($current->{'type'} ne 'root_line') {
- $self->_bug_message("no parent element", $source_info,
$current);
- die;
- }
- } else {
- $current = $current->{'parent'};
- }
+ $misc->{'source_info'} = $source_info if (defined($misc));
+ } else {
+ $misc = { 'cmdname' => $command, 'parent' => $current,
+ 'source_info' => $source_info };
+ push @{$current->{'contents'}}, $misc;
+ }
+ $line = _start_empty_line_after_command($line, $current, $misc,
$command);
+ }
+ # line commands
+ } elsif (defined($self->{'line_commands'}->{$command})) {
+ if ($root_commands{$command} or $command eq 'bye') {
+ $current = _close_commands($self, $current, $source_info, undef,
+ $command);
+ if (!defined($current->{'parent'})) {
+ # if parse_texi_line is called on a line with a node/section then
+ # it will directly be in the root_line, otherwise it is not directly
+ # in the root, but in another container
+ #
+ # FIXME warn/error with a root command in parse_texi_line?
+ if ($current->{'type'} ne 'root_line') {
+ $self->_bug_message("no parent element", $source_info, $current);
+ die;
}
+ } else {
+ $current = $current->{'parent'};
+ }
+ }
- # skipline text line lineraw /^\d$/
- my $arg_spec = $self->{'line_commands'}->{$command};
- my $misc;
-
- # all the cases using the raw line
- if ($arg_spec eq 'skipline' or $arg_spec eq 'lineraw'
- or $arg_spec eq 'special') {
- my $ignored = 0;
- if ($command eq 'insertcopying') {
- my $parent = $current;
- while ($parent) {
- if ($parent->{'cmdname'} and $parent->{'cmdname'} eq
'copying') {
- $self->_line_error(
- sprintf(__("\@%s not allowed inside `\@%s' block"),
- $command, $parent->{'cmdname'}), $source_info);
- $ignored = 1;
- last;
- }
- $parent = $parent->{'parent'};
- }
+ # skipline text line lineraw /^\d$/
+ my $arg_spec = $self->{'line_commands'}->{$command};
+ my $misc;
+
+ # all the cases using the raw line
+ if ($arg_spec eq 'skipline' or $arg_spec eq 'lineraw'
+ or $arg_spec eq 'special') {
+ my $ignored = 0;
+ if ($command eq 'insertcopying') {
+ my $parent = $current;
+ while ($parent) {
+ if ($parent->{'cmdname'} and $parent->{'cmdname'} eq 'copying') {
+ $self->_line_error(
+ sprintf(__("\@%s not allowed inside `\@%s' block"),
+ $command, $parent->{'cmdname'}), $source_info);
+ $ignored = 1;
+ last;
}
+ $parent = $parent->{'parent'};
+ }
+ }
- # complete the line if there was a user macro expansion
- if ($line !~ /\n/) {
- my ($new_line, $new_line_source_info)
- = _new_line($self, $source_info);
- $line .= $new_line if (defined($new_line));
- }
- $misc = {'cmdname' => $command,
- 'parent' => $current};
- my $args = [];
- my $has_comment;
- if ($arg_spec eq 'lineraw' or $arg_spec eq 'skipline') {
- $args = [ $line ];
- } elsif ($arg_spec eq 'special') {
- ($args, $has_comment)
- = _parse_special_misc_command($self, $line, $command,
$source_info);
- $misc->{'extra'}->{'arg_line'} = $line;
- }
+ # complete the line if there was a user macro expansion
+ if ($line !~ /\n/) {
+ my ($new_line, $new_line_source_info)
+ = _new_line($self, $source_info);
+ $line .= $new_line if (defined($new_line));
+ }
+ $misc = {'cmdname' => $command,
+ 'parent' => $current};
+ my $args = [];
+ my $has_comment;
+ if ($arg_spec eq 'lineraw' or $arg_spec eq 'skipline') {
+ $args = [ $line ];
+ } elsif ($arg_spec eq 'special') {
+ ($args, $has_comment)
+ = _parse_special_misc_command($self, $line, $command, $source_info);
+ $misc->{'extra'}->{'arg_line'} = $line;
+ }
- # if using the @set txi* instead of a proper @-command, replace
- # by the tree obtained with the @-command. Even though
- # _end_line is called below, as $current is not line_arg
- # there should not be anything done in addition than what is
- # done for @clear or @set.
- if (($command eq 'set' or $command eq 'clear')
- and scalar(@$args) >= 1
- and $set_flag_command_equivalent{$args->[0]}) {
- my $arg;
- if ($command eq 'set') {
- $arg = 'on';
- } else {
- $arg = 'off';
- }
- $command = $set_flag_command_equivalent{$args->[0]};
- $misc = {'cmdname' => $command,
- 'parent' => $current,
- 'source_info' => $source_info,
- 'extra' => {'misc_args' => [$arg]}};
- my $misc_line_args = {'type' => 'line_arg',
- 'parent' => $misc};
- $misc->{'args'} = [$misc_line_args];
- $misc->{'extra'}->{'spaces_before_argument'} = ' ';
- $misc_line_args->{'contents'} = [
- { 'text' => $arg,
- 'parent' => $misc_line_args, },
- { 'text' => "\n",
- 'parent' => $misc_line_args,
- 'type' => 'spaces_at_end', } ];
- push @{$current->{'contents'}}, $misc;
- } else {
- if (!$ignored) {
- push @{$current->{'contents'}}, $misc;
- foreach my $arg (@$args) {
- push @{$misc->{'args'}},
- { 'type' => 'misc_arg', 'text' => $arg,
- 'parent' => $current->{'contents'}->[-1] };
- }
- $misc->{'extra'}->{'misc_args'} = $args
- if (scalar(@$args) and $arg_spec ne 'skipline');
- } else {
- $misc = undef;
- }
- }
- if ($command eq 'raisesections') {
- $self->{'sections_level'}++;
- } elsif ($command eq 'lowersections') {
- $self->{'sections_level'}--;
- }
- _register_global_command($self, $misc, $source_info)
- if $misc;
- # the end of line is ignored for special commands
- if ($arg_spec ne 'special' or !$has_comment) {
- $current = _end_line($self, $current, $source_info);
+ # if using the @set txi* instead of a proper @-command, replace
+ # by the tree obtained with the @-command. Even though
+ # _end_line is called below, as $current is not line_arg
+ # there should not be anything done in addition than what is
+ # done for @clear or @set.
+ if (($command eq 'set' or $command eq 'clear')
+ and scalar(@$args) >= 1
+ and $set_flag_command_equivalent{$args->[0]}) {
+ my $arg;
+ if ($command eq 'set') {
+ $arg = 'on';
+ } else {
+ $arg = 'off';
+ }
+ $command = $set_flag_command_equivalent{$args->[0]};
+ $misc = {'cmdname' => $command,
+ 'parent' => $current,
+ 'source_info' => $source_info,
+ 'extra' => {'misc_args' => [$arg]}};
+ my $misc_line_args = {'type' => 'line_arg',
+ 'parent' => $misc};
+ $misc->{'args'} = [$misc_line_args];
+ $misc->{'extra'}->{'spaces_before_argument'} = ' ';
+ $misc_line_args->{'contents'} = [
+ { 'text' => $arg,
+ 'parent' => $misc_line_args, },
+ { 'text' => "\n",
+ 'parent' => $misc_line_args,
+ 'type' => 'spaces_at_end', } ];
+ push @{$current->{'contents'}}, $misc;
+ } else {
+ if (!$ignored) {
+ push @{$current->{'contents'}}, $misc;
+ foreach my $arg (@$args) {
+ push @{$misc->{'args'}},
+ { 'type' => 'misc_arg', 'text' => $arg,
+ 'parent' => $current->{'contents'}->[-1] };
}
+ $misc->{'extra'}->{'misc_args'} = $args
+ if (scalar(@$args) and $arg_spec ne 'skipline');
+ } else {
+ $misc = undef;
+ }
+ }
+ if ($command eq 'raisesections') {
+ $self->{'sections_level'}++;
+ } elsif ($command eq 'lowersections') {
+ $self->{'sections_level'}--;
+ }
+ _register_global_command($self, $misc, $source_info)
+ if $misc;
+ # the end of line is ignored for special commands
+ if ($arg_spec ne 'special' or !$has_comment) {
+ $current = _end_line($self, $current, $source_info);
+ }
- last NEXT_LINE if ($command eq 'bye');
- # Even if _end_line is called, it is not done since there is
- # no line_arg
- $current = _begin_preformatted($self, $current)
- if ($close_preformatted_commands{$command});
- last;
+ if ($command eq 'bye') {
+ $retval = $FINISHED_TOTALLY;
+ goto funexit;
+ }
+ # Even if _end_line is called, it is not done since there is
+ # no line_arg
+ $current = _begin_preformatted($self, $current)
+ if ($close_preformatted_commands{$command});
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ } else {
+ # $arg_spec is text, line or a number
+ # @item or @itemx in @table
+ if ($command eq 'item' or $command eq 'itemx') {
+ my $parent;
+ print STDERR "ITEM_LINE\n" if ($self->{'DEBUG'});
+ if ($parent = _item_line_parent($current)) {
+ $current = $parent;
+ _gather_previous_item($self, $current, $command, $source_info);
} else {
- # $arg_spec is text, line or a number
- # @item or @itemx in @table
- if ($command eq 'item' or $command eq 'itemx') {
- my $parent;
- print STDERR "ITEM_LINE\n" if ($self->{'DEBUG'});
- if ($parent = _item_line_parent($current)) {
- $current = $parent;
- _gather_previous_item($self, $current, $command, $source_info);
- } else {
- $self->_line_error(sprintf(__(
- "\@%s outside of table or list"), $command), $source_info);
- $current = _begin_preformatted($self, $current);
- }
- $misc = { 'cmdname' => $command, 'parent' => $current };
- push @{$current->{'contents'}}, $misc;
- $misc->{'source_info'} = $source_info;
- } else {
- $misc = { 'cmdname' => $command, 'source_info' => $source_info };
- if ($command eq 'subentry') {
- my $parent = $current->{'parent'};
- if (!_is_index_element($self, $parent)) {
- $self->_line_warn(
- sprintf(__("\@%s should only appear in an index entry"),
- $command), $source_info);
- }
- $parent->{'extra'}->{'subentry'} = $misc;
- my $subentry_level = 1;
- if ($parent->{'cmdname'} eq 'subentry') {
- $subentry_level = $parent->{'extra'}->{'level'} + 1;
- }
- $misc->{'extra'}->{'level'} = $subentry_level;
- if ($subentry_level > 2) {
- $self->_line_error(__(
- "no more than two levels of index subentry are allowed"),
- $source_info);
- }
- # Do not make the @subentry element a child of the index
- # command. This means that spaces are preserved properly
- # when converting back to Texinfo.
- $current = _end_line($self, $current, $source_info);
- }
- push @{$current->{'contents'}}, $misc;
- $misc->{'parent'} = $current;
- if ($sectioning_heading_commands{$command}) {
- if ($self->{'sections_level'}) {
- $current->{'contents'}->[-1]->{'extra'}->{'sections_level'}
- = $self->{'sections_level'};
- }
- }
- if ($root_commands{$command}) {
- $misc->{'contents'} = [];
- }
- # def*x
- if ($def_commands{$command}) {
- my $base_command = $command;
- $base_command =~ s/x$//;
- # check that the def*x is first after @def*, no paragraph
- # in-between.
- my $after_paragraph = _check_no_text($current);
- $self->_push_context('ct_def', $command);
- $current->{'contents'}->[-1]->{'type'} = 'def_line';
- $current->{'contents'}->[-1]->{'extra'}
- = {'def_command' => $base_command,
- 'original_def_cmdname' => $command};
- if (defined($self->{'values'}->{'txidefnamenospace'})) {
- $current->{'contents'}->[-1]{'extra'}
- ->{'omit_def_name_space'} = 1;
- }
- if ($current->{'cmdname'}
- and $current->{'cmdname'} eq $base_command) {
- pop @{$current->{'contents'}};
- _gather_def_item($current, $command);
- push @{$current->{'contents'}}, $misc;
- }
- if (!$current->{'cmdname'}
- or $current->{'cmdname'} ne $base_command
- or $after_paragraph) {
- $self->_line_error(sprintf(__(
- "must be after `\@%s' to use `\@%s'"),
- $base_command, $command),
$source_info);
-
$current->{'contents'}->[-1]->{'extra'}->{'not_after_command'} = 1;
- }
- }
+ $self->_line_error(sprintf(__(
+ "\@%s outside of table or list"), $command), $source_info);
+ $current = _begin_preformatted($self, $current);
+ }
+ $misc = { 'cmdname' => $command, 'parent' => $current };
+ push @{$current->{'contents'}}, $misc;
+ $misc->{'source_info'} = $source_info;
+ } else {
+ $misc = { 'cmdname' => $command, 'source_info' => $source_info };
+ if ($command eq 'subentry') {
+ my $parent = $current->{'parent'};
+ if (!_is_index_element($self, $parent)) {
+ $self->_line_warn(
+ sprintf(__("\@%s should only appear in an index entry"),
+ $command), $source_info);
}
- $current = $current->{'contents'}->[-1];
- $current->{'args'} = [{ 'type' => 'line_arg',
- 'contents' => [],
- 'parent' => $current }];
- # @node is the only misc command with args separated with comma
- # FIXME a 3 lingering here deep into the code may not
- # be very wise... However having a hash only for one @-command
- # is not very appealing either...
- if ($command eq 'node') {
- $current->{'remaining_args'} = 3;
- } elsif ($command eq 'author') {
- my $parent = $current;
- my $found;
- while ($parent->{'parent'}) {
- $parent = $parent->{'parent'};
- last if ($parent->{'type'}
- and $parent->{'type'} eq 'brace_command_context');
- if ($parent->{'cmdname'}) {
- if ($parent->{'cmdname'} eq 'titlepage') {
- $current->{'extra'}->{'titlepage'} = $parent;
- $found = 1;
- } elsif ($parent->{'cmdname'} eq 'quotation' or
- $parent->{'cmdname'} eq 'smallquotation') {
- push @{$parent->{'extra'}->{'authors'}}, $current;
- $current->{'extra'}->{'quotation'} = $parent;
- $found = 1;
- }
- last if ($found);
- }
- }
- if (!$found) {
- $self->_line_warn(sprintf(__(
- "\@%s not meaningful outside `\@titlepage' and `\@quotation'
environments"),
- $command), $current->{'source_info'});
- }
- } elsif ($command eq 'dircategory' and $self->{'current_node'}) {
- $self->_line_warn(__("\@dircategory after first node"),
- $source_info);
- } elsif ($command eq 'printindex') {
- # Record that @printindex occurs in this node so we know it
- # is an index node.
- if ($self->{'current_node'}) {
- $self->{'current_node'}->{'extra'}->{'isindex'} = 1;
- }
+ $parent->{'extra'}->{'subentry'} = $misc;
+ my $subentry_level = 1;
+ if ($parent->{'cmdname'} eq 'subentry') {
+ $subentry_level = $parent->{'extra'}->{'level'} + 1;
}
-
- $current = $current->{'args'}->[-1];
- $self->_push_context('ct_line', $command)
- unless ($def_commands{$command});
- $line = _start_empty_line_after_command($line, $current, $misc,
- $command);
+ $misc->{'extra'}->{'level'} = $subentry_level;
+ if ($subentry_level > 2) {
+ $self->_line_error(__(
+ "no more than two levels of index subentry are allowed"),
+ $source_info);
+ }
+ # Do not make the @subentry element a child of the index
+ # command. This means that spaces are preserved properly
+ # when converting back to Texinfo.
+ $current = _end_line($self, $current, $source_info);
}
- _register_global_command($self, $misc, $source_info)
- if $misc;
- if ($command eq 'dircategory') {
- push @{$self->{'info'}->{'dircategory_direntry'}}, $misc;
+ push @{$current->{'contents'}}, $misc;
+ $misc->{'parent'} = $current;
+ if ($sectioning_heading_commands{$command}) {
+ if ($self->{'sections_level'}) {
+ $current->{'contents'}->[-1]->{'extra'}->{'sections_level'}
+ = $self->{'sections_level'};
+ }
}
- # @-command with matching @end opening
- } elsif (exists($block_commands{$command})) {
- if ($command eq 'macro' or $command eq 'rmacro') {
- my $macro = _parse_macro_command_line($self, $command, $line,
- $current, $source_info);
- push @{$current->{'contents'}}, $macro;
- $current = $current->{'contents'}->[-1];
- last;
- } elsif ($block_commands{$command} eq 'conditional') {
- my $ifvalue_true = 0;
- if ($command eq 'ifclear' or $command eq 'ifset') {
- # REVALUE
- if ($line =~
/^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) {
- my $name = $1;
- if ((exists($self->{'values'}->{$name}) and $command eq
'ifset')
- or (!exists($self->{'values'}->{$name})
- and $command eq 'ifclear')) {
- $ifvalue_true = 1;
- }
- print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n"
- if
($self->{'DEBUG'});
- } elsif ($line !~ /\S/) {
- $self->_line_error(sprintf(
- __("%c%s requires a name"), ord('@'), $command),
$source_info);
- } else {
- $self->_line_error(sprintf(
- __("bad name for \@%s"), $command), $source_info);
- }
- } elsif ($command eq 'ifcommanddefined'
- or $command eq 'ifcommandnotdefined') {
- # REMACRO
- if ($line =~
/^\s+([[:alnum:]][[:alnum:]\-]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) {
- my $name = $1;
- my $command_is_defined = (
- exists($Texinfo::Common::all_commands{$name})
- or $self->{'macros'}->{$name}
- or $self->{'definfoenclose'}->{$name}
- or $self->{'aliases'}->{$name}
- or $self->{'command_index'}->{$name}
- );
- if (($command_is_defined
- and $command eq 'ifcommanddefined')
- or (! $command_is_defined
- and $command eq 'ifcommandnotdefined')) {
- $ifvalue_true = 1;
- }
- print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n"
- if
($self->{'DEBUG'});
- } elsif ($line !~ /\S/) {
- $self->_line_error(sprintf(
- __("%c%s requires a name"), ord('@'), $command),
$source_info);
- } else {
- $self->_line_error(sprintf(
- __("bad name for \@%s"), $command), $source_info);
- }
- } elsif ($command =~ /^ifnot(.*)/) {
- $ifvalue_true = 1 if !($self->{'expanded_formats_hash'}->{$1}
- # exception as explained in the texinfo manual
- or ($1 eq 'info'
- and $self->{'expanded_formats_hash'}->{'plaintext'}));
- print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n"
- if
($self->{'DEBUG'});
- } else {
- die unless ($command =~ /^if(.*)/);
- $ifvalue_true = 1 if ($self->{'expanded_formats_hash'}->{$1}
- or ($1 eq 'info'
- and
$self->{'expanded_formats_hash'}->{'plaintext'}));
- print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n"
- if
($self->{'DEBUG'});
+ if ($root_commands{$command}) {
+ $misc->{'contents'} = [];
+ }
+ # def*x
+ if ($def_commands{$command}) {
+ my $base_command = $command;
+ $base_command =~ s/x$//;
+ # check that the def*x is first after @def*, no paragraph
+ # in-between.
+ my $after_paragraph = _check_no_text($current);
+ $self->_push_context('ct_def', $command);
+ $current->{'contents'}->[-1]->{'type'} = 'def_line';
+ $current->{'contents'}->[-1]->{'extra'}
+ = {'def_command' => $base_command,
+ 'original_def_cmdname' => $command};
+ if (defined($self->{'values'}->{'txidefnamenospace'})) {
+ $current->{'contents'}->[-1]{'extra'}
+ ->{'omit_def_name_space'} = 1;
}
- if ($ifvalue_true) {
- push @{$self->{'conditionals_stack'}}, $command;
- } else {
- push @{$current->{'contents'}}, { 'cmdname' => $command,
- 'parent' => $current,
- 'contents' => [] };
- $current = $current->{'contents'}->[-1];
+ if ($current->{'cmdname'}
+ and $current->{'cmdname'} eq $base_command) {
+ pop @{$current->{'contents'}};
+ _gather_def_item($current, $command);
+ push @{$current->{'contents'}}, $misc;
}
- # FIXME(Karl) ignore what is remaining on the line, to eat
- # the end of line?
- last;
- } else {
- my $block;
- # a menu command closes a menu_comment, but not the other
- # block commands. This won't catch menu commands buried in
- # other formats (that are incorrect anyway).
- if ($menu_commands{$command} and $current->{'type'}
- and ($current->{'type'} eq 'menu_comment'
- or $current->{'type'} eq 'menu_entry_description')) {
-
- my $menu;
-
- $menu = $current->{'parent'};
- pop @{$menu->{'contents'}}
- if (!@{$current->{'contents'}});
-
- if ($menu->{'type'} and $menu->{'type'} eq 'menu_entry') {
- $menu = $menu->{'parent'};
- }
-
- $current = $menu;
+ if (!$current->{'cmdname'}
+ or $current->{'cmdname'} ne $base_command
+ or $after_paragraph) {
+ $self->_line_error(sprintf(__(
+ "must be after `\@%s' to use `\@%s'"),
+ $base_command, $command), $source_info);
+ $current->{'contents'}->[-1]->{'extra'}->{'not_after_command'} =
1;
}
- # the def command holds a line_def* which corresponds with the
- # definition line. This allows to have a treatement similar
- # with def*x.
- if ($def_commands{$command}) {
- $self->_push_context('ct_def', $command);
- $block = { 'parent' => $current,
- 'cmdname' => $command,
- 'contents' => [] };
- push @{$current->{'contents'}}, $block;
- $current = $current->{'contents'}->[-1];
- push @{$current->{'contents'}}, {
- 'type' => 'def_line',
- 'parent' => $current,
- 'source_info' => $source_info,
- 'extra' =>
- {'def_command' => $command,
- 'original_def_cmdname' =>
$command}
- };
- if (defined($self->{'values'}->{'txidefnamenospace'})) {
- $current->{'contents'}->[-1]->{'extra'}
- ->{'omit_def_name_space'} = 1;
+ }
+ }
+ $current = $current->{'contents'}->[-1];
+ $current->{'args'} = [{ 'type' => 'line_arg',
+ 'contents' => [],
+ 'parent' => $current }];
+ # @node is the only misc command with args separated with comma
+ # FIXME a 3 lingering here deep into the code may not
+ # be very wise... However having a hash only for one @-command
+ # is not very appealing either...
+ if ($command eq 'node') {
+ $current->{'remaining_args'} = 3;
+ } elsif ($command eq 'author') {
+ my $parent = $current;
+ my $found;
+ while ($parent->{'parent'}) {
+ $parent = $parent->{'parent'};
+ last if ($parent->{'type'}
+ and $parent->{'type'} eq 'brace_command_context');
+ if ($parent->{'cmdname'}) {
+ if ($parent->{'cmdname'} eq 'titlepage') {
+ $current->{'extra'}->{'titlepage'} = $parent;
+ $found = 1;
+ } elsif ($parent->{'cmdname'} eq 'quotation' or
+ $parent->{'cmdname'} eq 'smallquotation') {
+ push @{$parent->{'extra'}->{'authors'}}, $current;
+ $current->{'extra'}->{'quotation'} = $parent;
+ $found = 1;
}
- } else {
- $block = { 'cmdname' => $command,
- 'parent' => $current,
- 'contents' => [] };
- push @{$current->{'contents'}}, $block;
+ last if ($found);
}
- $current = $current->{'contents'}->[-1];
+ }
+ if (!$found) {
+ $self->_line_warn(sprintf(__(
+ "\@%s not meaningful outside `\@titlepage' and `\@quotation'
environments"),
+ $command), $current->{'source_info'});
+ }
+ } elsif ($command eq 'dircategory' and $self->{'current_node'}) {
+ $self->_line_warn(__("\@dircategory after first node"),
+ $source_info);
+ } elsif ($command eq 'printindex') {
+ # Record that @printindex occurs in this node so we know it
+ # is an index node.
+ if ($self->{'current_node'}) {
+ $self->{'current_node'}->{'extra'}->{'isindex'} = 1;
+ }
+ }
- if ($preformatted_commands{$command}) {
- $self->_push_context('ct_preformatted', $command);
- } elsif ($math_commands{$command}) {
- $self->_push_context('ct_math', $command);
- } elsif ($format_raw_commands{$command}) {
- $self->_push_context('ct_rawpreformatted', $command);
- }
- if ($region_commands{$command}) {
- if (@{$self->{'regions_stack'}}) {
- $self->_line_error(
- sprintf(__("region %s inside region %s is not allowed"),
- $command, $self->{'regions_stack'}->[-1]->{'cmdname'}),
- $source_info);
- }
- push @{$self->{'regions_stack'}}, $block;
- }
- if ($menu_commands{$command}) {
- $self->_push_context('ct_preformatted', $command);
- push @{$self->{'info'}->{'dircategory_direntry'}}, $block
- if ($command eq 'direntry');
- if ($self->{'current_node'}) {
- if ($command eq 'direntry') {
- if ($self->{'FORMAT_MENU'} eq 'menu') {
- $self->_line_warn(__("\@direntry after first node"),
- $source_info);
- }
- } elsif ($command eq 'menu') {
- if (!(defined $current->{'parent'}->{'cmdname'})
- or $root_commands{$current->{'parent'}->{'cmdname'}}) {
- push @{$self->{'current_node'}->{'extra'}->{'menus'}},
$current;
- } else {
- $self->_line_warn(__("\@menu in invalid context"),
- $source_info);
- }
- }
- }
+ $current = $current->{'args'}->[-1];
+ $self->_push_context('ct_line', $command)
+ unless ($def_commands{$command});
+ $line = _start_empty_line_after_command($line, $current, $misc,
+ $command);
+ }
+ _register_global_command($self, $misc, $source_info)
+ if $misc;
+ if ($command eq 'dircategory') {
+ push @{$self->{'info'}->{'dircategory_direntry'}}, $misc;
+ }
+ # @-command with matching @end opening
+ } elsif (exists($block_commands{$command})) {
+ if ($command eq 'macro' or $command eq 'rmacro') {
+ my $macro = _parse_macro_command_line($self, $command, $line,
+ $current, $source_info);
+ push @{$current->{'contents'}}, $macro;
+ $current = $current->{'contents'}->[-1];
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ } elsif ($block_commands{$command} eq 'conditional') {
+ my $ifvalue_true = 0;
+ if ($command eq 'ifclear' or $command eq 'ifset') {
+ # REVALUE
+ if ($line =~
/^\s+([\w\-][^\s{\\}~`\^+"<>|@]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) {
+ my $name = $1;
+ if ((exists($self->{'values'}->{$name}) and $command eq 'ifset')
+ or (!exists($self->{'values'}->{$name})
+ and $command eq 'ifclear')) {
+ $ifvalue_true = 1;
}
- $current->{'args'} = [ {
- 'type' => 'block_line_arg',
- 'contents' => [],
- 'parent' => $current } ];
-
- if ($block_commands{$command} =~ /^\d+$/
- and $block_commands{$command} - 1 > 0) {
- $current->{'remaining_args'} = $block_commands{$command} - 1;
- } elsif ($block_commands{$command} eq 'variadic') {
- $current->{'remaining_args'} = -1; # unlimited args
+ print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n"
+ if ($self->{'DEBUG'});
+ } elsif ($line !~ /\S/) {
+ $self->_line_error(sprintf(
+ __("%c%s requires a name"), ord('@'), $command), $source_info);
+ } else {
+ $self->_line_error(sprintf(
+ __("bad name for \@%s"), $command), $source_info);
+ }
+ } elsif ($command eq 'ifcommanddefined'
+ or $command eq 'ifcommandnotdefined') {
+ # REMACRO
+ if ($line =~
/^\s+([[:alnum:]][[:alnum:]\-]*)\s*(\@(c|comment)((\@|\s+).*)?)?$/) {
+ my $name = $1;
+ my $command_is_defined = (
+ exists($Texinfo::Common::all_commands{$name})
+ or $self->{'macros'}->{$name}
+ or $self->{'definfoenclose'}->{$name}
+ or $self->{'aliases'}->{$name}
+ or $self->{'command_index'}->{$name}
+ );
+ if (($command_is_defined
+ and $command eq 'ifcommanddefined')
+ or (! $command_is_defined
+ and $command eq 'ifcommandnotdefined')) {
+ $ifvalue_true = 1;
}
- $current = $current->{'args'}->[-1];
- $self->_push_context('ct_line', $command)
- unless ($def_commands{$command});
- $block->{'source_info'} = $source_info;
- _register_global_command($self, $block, $source_info);
- $line = _start_empty_line_after_command($line, $current, $block,
- $command);
+ print STDERR "CONDITIONAL \@$command $name: $ifvalue_true\n"
+ if ($self->{'DEBUG'});
+ } elsif ($line !~ /\S/) {
+ $self->_line_error(sprintf(
+ __("%c%s requires a name"), ord('@'), $command), $source_info);
+ } else {
+ $self->_line_error(sprintf(
+ __("bad name for \@%s"), $command), $source_info);
}
- } elsif (defined($brace_commands{$command})) {
+ } elsif ($command =~ /^ifnot(.*)/) {
+ $ifvalue_true = 1 if !($self->{'expanded_formats_hash'}->{$1}
+ # exception as explained in the texinfo manual
+ or ($1 eq 'info'
+ and $self->{'expanded_formats_hash'}->{'plaintext'}));
+ print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n"
+ if ($self->{'DEBUG'});
+ } else {
+ die unless ($command =~ /^if(.*)/);
+ $ifvalue_true = 1 if ($self->{'expanded_formats_hash'}->{$1}
+ or ($1 eq 'info'
+ and $self->{'expanded_formats_hash'}->{'plaintext'}));
+ print STDERR "CONDITIONAL \@$command format $1: $ifvalue_true\n"
+ if ($self->{'DEBUG'});
+ }
+ if ($ifvalue_true) {
+ push @{$self->{'conditionals_stack'}}, $command;
+ } else {
push @{$current->{'contents'}}, { 'cmdname' => $command,
'parent' => $current,
'contents' => [] };
- $current->{'contents'}->[-1]->{'source_info'} = $source_info
- if ($keep_line_nr_brace_commands{$command}
- and !$self->{'definfoenclose'}->{$command});
- if ($in_index_commands{$command}
- and !_is_index_element($self, $current->{'parent'})) {
- $self->_line_warn(
- sprintf(__("\@%s should only appear in an index entry"),
- $command), $source_info);
- }
-
$current = $current->{'contents'}->[-1];
- if ($command eq 'click') {
- $current->{'extra'}->{'clickstyle'} = $self->{'clickstyle'};
- } elsif ($command eq 'kbd'
- and _kbd_formatted_as_code($self, $current)) {
- $current->{'extra'}->{'code'} = 1;
- }
- if ($self->{'definfoenclose'}->{$command}) {
- $current->{'type'} = 'definfoenclose_command';
- $current->{'extra'}->{'begin'}
- = $self->{'definfoenclose'}->{$command}->[0];
- $current->{'extra'}->{'end'}
- = $self->{'definfoenclose'}->{$command}->[1];
+ }
+ # FIXME(Karl) ignore what is remaining on the line, to eat
+ # the end of line?
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ } else {
+ my $block;
+ # a menu command closes a menu_comment, but not the other
+ # block commands. This won't catch menu commands buried in
+ # other formats (that are incorrect anyway).
+ if ($menu_commands{$command} and $current->{'type'}
+ and ($current->{'type'} eq 'menu_comment'
+ or $current->{'type'} eq 'menu_entry_description')) {
+
+ my $menu;
+
+ $menu = $current->{'parent'};
+ pop @{$menu->{'contents'}}
+ if (!@{$current->{'contents'}});
+
+ if ($menu->{'type'} and $menu->{'type'} eq 'menu_entry') {
+ $menu = $menu->{'parent'};
}
- } elsif (exists ($no_brace_commands{$command})) {
- push @{$current->{'contents'}},
- { 'cmdname' => $command, 'parent' => $current };
- # FIXME generalize?
- if ($command eq '\\' and $self->_top_context() ne 'ct_math') {
- $self->_line_warn(sprintf(
- __("\@%s should only appear in math context"),
- $command), $source_info);
+
+ $current = $menu;
+ }
+ # the def command holds a line_def* which corresponds with the
+ # definition line. This allows to have a treatement similar
+ # with def*x.
+ if ($def_commands{$command}) {
+ $self->_push_context('ct_def', $command);
+ $block = { 'parent' => $current,
+ 'cmdname' => $command,
+ 'contents' => [] };
+ push @{$current->{'contents'}}, $block;
+ $current = $current->{'contents'}->[-1];
+ push @{$current->{'contents'}}, {
+ 'type' => 'def_line',
+ 'parent' => $current,
+ 'source_info' => $source_info,
+ 'extra' =>
+ {'def_command' => $command,
+ 'original_def_cmdname' =>
$command}
+ };
+ if (defined($self->{'values'}->{'txidefnamenospace'})) {
+ $current->{'contents'}->[-1]->{'extra'}
+ ->{'omit_def_name_space'} = 1;
}
- if ($command eq "\n") {
- $current = _end_line($self, $current, $source_info);
- last;
+ } else {
+ $block = { 'cmdname' => $command,
+ 'parent' => $current,
+ 'contents' => [] };
+ push @{$current->{'contents'}}, $block;
+ }
+ $current = $current->{'contents'}->[-1];
+
+ if ($preformatted_commands{$command}) {
+ $self->_push_context('ct_preformatted', $command);
+ } elsif ($math_commands{$command}) {
+ $self->_push_context('ct_math', $command);
+ } elsif ($format_raw_commands{$command}) {
+ $self->_push_context('ct_rawpreformatted', $command);
+ }
+ if ($region_commands{$command}) {
+ if (@{$self->{'regions_stack'}}) {
+ $self->_line_error(
+ sprintf(__("region %s inside region %s is not allowed"),
+ $command, $self->{'regions_stack'}->[-1]->{'cmdname'}),
+ $source_info);
}
+ push @{$self->{'regions_stack'}}, $block;
}
- } elsif ($separator_match) {
- my $separator = $separator_match;
- substr ($line, 0, 1) = '';
- print STDERR "SEPARATOR: $separator\n" if ($self->{'DEBUG'});
- if ($separator eq '@') {
- # this may happen with a @ at the very end of a file, therefore
- # not followed by anything.
- $self->_line_error(__("unexpected \@"), $source_info);
- } elsif ($separator eq '{') {
- _abort_empty_line($self, $current);
- if ($current->{'cmdname'}
- and defined($brace_commands{$current->{'cmdname'}})) {
- my $command = $current->{'cmdname'};
- $current->{'args'} = [ { 'parent' => $current,
- 'contents' => [] } ];
-
- if ($brace_commands{$command}
- and $brace_commands{$command} =~ /^\d$/
- and $brace_commands{$command} > 1) {
- $current->{'remaining_args'} = $brace_commands{$command} - 1;
+ if ($menu_commands{$command}) {
+ $self->_push_context('ct_preformatted', $command);
+ push @{$self->{'info'}->{'dircategory_direntry'}}, $block
+ if ($command eq 'direntry');
+ if ($self->{'current_node'}) {
+ if ($command eq 'direntry') {
+ if ($self->{'FORMAT_MENU'} eq 'menu') {
+ $self->_line_warn(__("\@direntry after first node"),
+ $source_info);
+ }
+ } elsif ($command eq 'menu') {
+ if (!(defined $current->{'parent'}->{'cmdname'})
+ or $root_commands{$current->{'parent'}->{'cmdname'}}) {
+ push @{$self->{'current_node'}->{'extra'}->{'menus'}},
$current;
+ } else {
+ $self->_line_warn(__("\@menu in invalid context"),
+ $source_info);
+ }
}
+ }
+ }
+ $current->{'args'} = [ {
+ 'type' => 'block_line_arg',
+ 'contents' => [],
+ 'parent' => $current } ];
+
+ if ($block_commands{$command} =~ /^\d+$/
+ and $block_commands{$command} - 1 > 0) {
+ $current->{'remaining_args'} = $block_commands{$command} - 1;
+ } elsif ($block_commands{$command} eq 'variadic') {
+ $current->{'remaining_args'} = -1; # unlimited args
+ }
+ $current = $current->{'args'}->[-1];
+ $self->_push_context('ct_line', $command)
+ unless ($def_commands{$command});
+ $block->{'source_info'} = $source_info;
+ _register_global_command($self, $block, $source_info);
+ $line = _start_empty_line_after_command($line, $current, $block,
+ $command);
+ }
+ } elsif (defined($brace_commands{$command})) {
+ push @{$current->{'contents'}}, { 'cmdname' => $command,
+ 'parent' => $current,
+ 'contents' => [] };
+ $current->{'contents'}->[-1]->{'source_info'} = $source_info
+ if ($keep_line_nr_brace_commands{$command}
+ and !$self->{'definfoenclose'}->{$command});
+ if ($in_index_commands{$command}
+ and !_is_index_element($self, $current->{'parent'})) {
+ $self->_line_warn(
+ sprintf(__("\@%s should only appear in an index entry"),
+ $command), $source_info);
+ }
+ $current = $current->{'contents'}->[-1];
+ if ($command eq 'click') {
+ $current->{'extra'}->{'clickstyle'} = $self->{'clickstyle'};
+ } elsif ($command eq 'kbd'
+ and _kbd_formatted_as_code($self, $current)) {
+ $current->{'extra'}->{'code'} = 1;
+ }
+ if ($self->{'definfoenclose'}->{$command}) {
+ $current->{'type'} = 'definfoenclose_command';
+ $current->{'extra'}->{'begin'}
+ = $self->{'definfoenclose'}->{$command}->[0];
+ $current->{'extra'}->{'end'}
+ = $self->{'definfoenclose'}->{$command}->[1];
+ }
+ } elsif (exists ($no_brace_commands{$command})) {
+ push @{$current->{'contents'}},
+ { 'cmdname' => $command, 'parent' => $current };
+ # FIXME generalize?
+ if ($command eq '\\' and $self->_top_context() ne 'ct_math') {
+ $self->_line_warn(sprintf(
+ __("\@%s should only appear in math context"),
+ $command), $source_info);
+ }
+ if ($command eq "\n") {
+ $current = _end_line($self, $current, $source_info);
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
+ }
+ } elsif ($separator_match) {
+ my $separator = $separator_match;
+ substr ($line, 0, 1) = '';
+ print STDERR "SEPARATOR: $separator\n" if ($self->{'DEBUG'});
+ if ($separator eq '@') {
+ # this may happen with a @ at the very end of a file, therefore
+ # not followed by anything.
+ $self->_line_error(__("unexpected \@"), $source_info);
+ } elsif ($separator eq '{') {
+ _abort_empty_line($self, $current);
+ if ($current->{'cmdname'}
+ and defined($brace_commands{$current->{'cmdname'}})) {
+ my $command = $current->{'cmdname'};
+ $current->{'args'} = [ { 'parent' => $current,
+ 'contents' => [] } ];
+
+ if ($brace_commands{$command}
+ and $brace_commands{$command} =~ /^\d$/
+ and $brace_commands{$command} > 1) {
+ $current->{'remaining_args'} = $brace_commands{$command} - 1;
+ }
- $current = $current->{'args'}->[-1];
- if ($context_brace_commands{$command}) {
- if ($command eq 'caption' or $command eq 'shortcaption') {
- my $float;
- if (!$current->{'parent'}->{'parent'}
- or !$current->{'parent'}->{'parent'}->{'cmdname'}
- or $current->{'parent'}->{'parent'}->{'cmdname'} ne
'float') {
- $float = $current->{'parent'};
- while ($float->{'parent'} and !($float->{'cmdname'}
- and $float->{'cmdname'} eq
'float')) {
- $float = $float->{'parent'};
- }
- if (!($float->{'cmdname'} and $float->{'cmdname'} eq
'float')) {
- $self->_line_error(sprintf(__(
- "\@%s is not meaningful outside `\@float' environment"),
- $command), $source_info);
- $float = undef;
- } else {
- $self->_line_warn(sprintf(__(
- "\@%s should be right below `\@float'"),
- $command), $source_info);
- }
- } else {
- $float = $current->{'parent'}->{'parent'};
- }
- if ($float) {
- if ($float->{'extra'}->{$command}) {
- $self->_line_warn(sprintf(__("ignoring multiple \@%s"),
- $command), $source_info);
- } else {
- $current->{'parent'}->{'extra'}->{'float'} = $float;
- $float->{'extra'}->{$command} = $current->{'parent'};
- }
- }
+ $current = $current->{'args'}->[-1];
+ if ($context_brace_commands{$command}) {
+ if ($command eq 'caption' or $command eq 'shortcaption') {
+ my $float;
+ if (!$current->{'parent'}->{'parent'}
+ or !$current->{'parent'}->{'parent'}->{'cmdname'}
+ or $current->{'parent'}->{'parent'}->{'cmdname'} ne 'float') {
+ $float = $current->{'parent'};
+ while ($float->{'parent'} and !($float->{'cmdname'}
+ and $float->{'cmdname'} eq
'float')) {
+ $float = $float->{'parent'};
}
- if ($math_commands{$command}) {
- $self->_push_context('ct_math', $command);
+ if (!($float->{'cmdname'} and $float->{'cmdname'} eq 'float')) {
+ $self->_line_error(sprintf(__(
+ "\@%s is not meaningful outside `\@float' environment"),
+ $command), $source_info);
+ $float = undef;
} else {
- $self->_push_context('ct_brace_command', $command);
+ $self->_line_warn(sprintf(__(
+ "\@%s should be right below `\@float'"),
+ $command), $source_info);
}
- $line =~ s/([^\S\f\n]*)//;
- $current->{'type'} = 'brace_command_context';
- # empty_spaces_before_argument is a transient internal type,
- # which should end up in extra spaces_before_argument.
- push @{$current->{'contents'}}, {
- 'type' => 'empty_spaces_before_argument',
- 'text' => $1,
- 'parent' => $current,
- 'extra' => {'spaces_associated_command' =>
$current->{'parent'}}
- };
} else {
- $current->{'type'} = 'brace_command_arg';
- # only put spaces in spaces_before_argument if the @-command
- # has an explicit positive number of arguments.
- if ($brace_commands{$command}
- and $brace_commands{$command} =~ /^\d$/
- and $brace_commands{$command} > 0) {
- # empty_spaces_before_argument is a transient internal type,
- # which should end up in extra spaces_before_argument.
- push @{$current->{'contents'}}, {
- 'type' => 'empty_spaces_before_argument',
- 'text' => '',
- 'parent' => $current,
- 'extra' => {'spaces_associated_command' =>
$current}
- };
+ $float = $current->{'parent'}->{'parent'};
+ }
+ if ($float) {
+ if ($float->{'extra'}->{$command}) {
+ $self->_line_warn(sprintf(__("ignoring multiple \@%s"),
+ $command), $source_info);
+ } else {
+ $current->{'parent'}->{'extra'}->{'float'} = $float;
+ $float->{'extra'}->{$command} = $current->{'parent'};
}
- $self->_push_context('ct_inlineraw', $command)
- if ($command eq 'inlineraw');
}
- print STDERR "OPENED \@$current->{'parent'}->{'cmdname'},
remaining: "
- .(defined($current->{'parent'}->{'remaining_args'}) ?
"remaining: $current->{'parent'}->{'remaining_args'}, " : '')
- .($current->{'type'} ? "type: $current->{'type'}" : '')."\n"
- if ($self->{'DEBUG'});
- } elsif ($current->{'parent'}
- and (($current->{'parent'}->{'cmdname'}
- and $current->{'parent'}->{'cmdname'} eq
'multitable')
- or ($current->{'parent'}->{'type'}
- and $current->{'parent'}->{'type'} eq
'def_line'))) {
- push @{$current->{'contents'}},
- { 'type' => 'bracketed', 'contents' => [],
- 'parent' => $current };
- $current = $current->{'contents'}->[-1];
- # we need the line number here in case @ protects end of line
- $current->{'source_info'} = $source_info
- if ($current->{'parent'}->{'parent'}->{'type'}
- and $current->{'parent'}->{'parent'}->{'type'} eq
'def_line');
+ }
+ if ($math_commands{$command}) {
+ $self->_push_context('ct_math', $command);
+ } else {
+ $self->_push_context('ct_brace_command', $command);
+ }
+ $line =~ s/([^\S\f\n]*)//;
+ $current->{'type'} = 'brace_command_context';
+ # empty_spaces_before_argument is a transient internal type,
+ # which should end up in extra spaces_before_argument.
+ push @{$current->{'contents'}}, {
+ 'type' => 'empty_spaces_before_argument',
+ 'text' => $1,
+ 'parent' => $current,
+ 'extra' => {'spaces_associated_command' => $current->{'parent'}}
+ };
+ } else {
+ $current->{'type'} = 'brace_command_arg';
+ # only put spaces in spaces_before_argument if the @-command
+ # has an explicit positive number of arguments.
+ if ($brace_commands{$command}
+ and $brace_commands{$command} =~ /^\d$/
+ and $brace_commands{$command} > 0) {
# empty_spaces_before_argument is a transient internal type,
# which should end up in extra spaces_before_argument.
- push @{$current->{'contents'}},
- {'type' => 'empty_spaces_before_argument',
- 'text' => '',
- 'parent' => $current,
- 'extra' => {'spaces_associated_command' => $current}
- };
- print STDERR "BRACKETED in def/multitable\n" if ($self->{'DEBUG'});
- # lone braces accepted right in a rawpreformatted
- } elsif ($current->{'type'}
- and $current->{'type'} eq 'rawpreformatted') {
- push @{$current->{'contents'}}, {'text' => '{',
- 'parent' => $current };
- # matching braces accepted in a rawpreformatted or math or ignored
- # code
- } elsif ($self->_top_context() eq 'ct_math'
- or $self->_top_context() eq 'ct_rawpreformatted'
- or $self->_top_context() eq 'ct_inlineraw') {
- push @{$current->{'contents'}},
- { 'type' => 'bracketed', 'contents' => [],
- 'parent' => $current, 'source_info' => $source_info };
- $current = $current->{'contents'}->[-1];
- print STDERR "BRACKETED in math/rawpreformatted/inlineraw\n"
- if ($self->{'DEBUG'});
- } else {
- $self->_line_error(sprintf(__("misplaced %c"),
- ord('{')), $source_info);
+ push @{$current->{'contents'}}, {
+ 'type' => 'empty_spaces_before_argument',
+ 'text' => '',
+ 'parent' => $current,
+ 'extra' => {'spaces_associated_command' => $current}
+ };
}
+ $self->_push_context('ct_inlineraw', $command)
+ if ($command eq 'inlineraw');
+ }
+ print STDERR "OPENED \@$current->{'parent'}->{'cmdname'}, remaining: "
+ .(defined($current->{'parent'}->{'remaining_args'}) ? "remaining:
$current->{'parent'}->{'remaining_args'}, " : '')
+ .($current->{'type'} ? "type: $current->{'type'}" : '')."\n"
+ if ($self->{'DEBUG'});
+ } elsif ($current->{'parent'}
+ and (($current->{'parent'}->{'cmdname'}
+ and $current->{'parent'}->{'cmdname'} eq 'multitable')
+ or ($current->{'parent'}->{'type'}
+ and $current->{'parent'}->{'type'} eq 'def_line'))) {
+ push @{$current->{'contents'}},
+ { 'type' => 'bracketed', 'contents' => [],
+ 'parent' => $current };
+ $current = $current->{'contents'}->[-1];
+ # we need the line number here in case @ protects end of line
+ $current->{'source_info'} = $source_info
+ if ($current->{'parent'}->{'parent'}->{'type'}
+ and $current->{'parent'}->{'parent'}->{'type'} eq 'def_line');
+ # empty_spaces_before_argument is a transient internal type,
+ # which should end up in extra spaces_before_argument.
+ push @{$current->{'contents'}},
+ {'type' => 'empty_spaces_before_argument',
+ 'text' => '',
+ 'parent' => $current,
+ 'extra' => {'spaces_associated_command' => $current}
+ };
+ print STDERR "BRACKETED in def/multitable\n" if ($self->{'DEBUG'});
+ # lone braces accepted right in a rawpreformatted
+ } elsif ($current->{'type'}
+ and $current->{'type'} eq 'rawpreformatted') {
+ push @{$current->{'contents'}}, {'text' => '{',
+ 'parent' => $current };
+ # matching braces accepted in a rawpreformatted or math or ignored
+ # code
+ } elsif ($self->_top_context() eq 'ct_math'
+ or $self->_top_context() eq 'ct_rawpreformatted'
+ or $self->_top_context() eq 'ct_inlineraw') {
+ push @{$current->{'contents'}},
+ { 'type' => 'bracketed', 'contents' => [],
+ 'parent' => $current, 'source_info' => $source_info };
+ $current = $current->{'contents'}->[-1];
+ print STDERR "BRACKETED in math/rawpreformatted/inlineraw\n"
+ if ($self->{'DEBUG'});
+ } else {
+ $self->_line_error(sprintf(__("misplaced %c"),
+ ord('{')), $source_info);
+ }
- } elsif ($separator eq '}') {
- _abort_empty_line($self, $current);
- if ($current->{'type'} and ($current->{'type'} eq 'bracketed')) {
- $current = $current->{'parent'};
- # the following will not happen for footnote if there is
- # a paragraph withing the footnote
- } elsif ($current->{'parent'}
- and $current->{'parent'}->{'cmdname'}
- and exists $brace_commands{$current->{'parent'}->{'cmdname'}}) {
- # for math and footnote out of paragraph
- if ($context_brace_commands{$current->{'parent'}->{'cmdname'}}) {
- my $command_context = 'ct_brace_command';
- if ($math_commands{$current->{'parent'}->{'cmdname'}}) {
- $command_context = 'ct_math';
- }
- my ($error) = $self->_pop_context([$command_context],
- $source_info, $current,
- "for brace command $current->{'parent'}->{'cmdname'}");
- die if ($error);
+ } elsif ($separator eq '}') {
+ _abort_empty_line($self, $current);
+ if ($current->{'type'} and ($current->{'type'} eq 'bracketed')) {
+ $current = $current->{'parent'};
+ # the following will not happen for footnote if there is
+ # a paragraph withing the footnote
+ } elsif ($current->{'parent'}
+ and $current->{'parent'}->{'cmdname'}
+ and exists $brace_commands{$current->{'parent'}->{'cmdname'}}) {
+ # for math and footnote out of paragraph
+ if ($context_brace_commands{$current->{'parent'}->{'cmdname'}}) {
+ my $command_context = 'ct_brace_command';
+ if ($math_commands{$current->{'parent'}->{'cmdname'}}) {
+ $command_context = 'ct_math';
+ }
+ my ($error) = $self->_pop_context([$command_context],
+ $source_info, $current,
+ "for brace command $current->{'parent'}->{'cmdname'}");
+ die if ($error);
+ }
+ # first is the arg.
+ if ($brace_commands{$current->{'parent'}->{'cmdname'}}
+ and $brace_commands{$current->{'parent'}{'cmdname'}} =~ /^\d$/
+ and $brace_commands{$current->{'parent'}->{'cmdname'}} > 0
+ and $current->{'parent'}->{'cmdname'} ne 'math') {
+ # @inline* always have end spaces considered as normal text
+ _isolate_last_space($self, $current)
+ unless ($inline_commands{$current->{'parent'}->{'cmdname'}});
+ }
+ my $closed_command = $current->{'parent'}->{'cmdname'};
+ print STDERR "CLOSING(brace) \@$current->{'parent'}->{'cmdname'}\n"
+ if ($self->{'DEBUG'});
+ delete $current->{'parent'}->{'remaining_args'};
+ if (defined($brace_commands{$closed_command})
+ and $brace_commands{$closed_command} eq '0'
+ and @{$current->{'contents'}}) {
+ $self->_line_warn(sprintf(__(
+ "command \@%s does not accept arguments"),
+ $closed_command), $source_info);
+ }
+ if ($current->{'parent'}->{'cmdname'} eq 'anchor') {
+ $current->{'parent'}->{'source_info'} = $source_info;
+ my $parsed_anchor = _parse_node_manual($current);
+ if (_check_node_label($self, $parsed_anchor,
+ $current->{'parent'}->{'cmdname'}, $source_info)) {
+ _register_label($self->{'targets'}, $current->{'parent'},
+ $parsed_anchor);
+ if (@{$self->{'regions_stack'}}) {
+ $current->{'extra'}->{'region'} = $self->{'regions_stack'}->[-1];
}
- # first is the arg.
-
- if ($brace_commands{$current->{'parent'}->{'cmdname'}}
- and $brace_commands{$current->{'parent'}{'cmdname'}} =~ /^\d$/
- and $brace_commands{$current->{'parent'}->{'cmdname'}} > 0
- and $current->{'parent'}->{'cmdname'} ne 'math') {
- # @inline* always have end spaces considered as normal text
- _isolate_last_space($self, $current)
- unless ($inline_commands{$current->{'parent'}->{'cmdname'}});
+ }
+ } elsif ($ref_commands{$current->{'parent'}->{'cmdname'}}) {
+ my $ref = $current->{'parent'};
+ if (@{$ref->{'args'}}) {
+ my @args;
+ for $a (@{$ref->{'args'}}) {
+ if (@{$a->{'contents'}}) {
+ push @args, $a->{'contents'};
+ } else {
+ push @args, undef;
+ }
}
- my $closed_command = $current->{'parent'}->{'cmdname'};
- print STDERR "CLOSING(brace) \@$current->{'parent'}->{'cmdname'}\n"
- if ($self->{'DEBUG'});
- delete $current->{'parent'}->{'remaining_args'};
- if (defined($brace_commands{$closed_command})
- and $brace_commands{$closed_command} eq '0'
- and @{$current->{'contents'}}) {
+ if (($closed_command eq 'inforef'
+ and !defined($args[0]) and !defined($args[2]))
+ or ($closed_command ne 'inforef'
+ and !defined($args[0]) and !defined($args[3])
+ and !defined($args[4]))) {
$self->_line_warn(sprintf(__(
- "command \@%s does not accept arguments"),
- $closed_command), $source_info);
- }
- if ($current->{'parent'}->{'cmdname'} eq 'anchor') {
- $current->{'parent'}->{'source_info'} = $source_info;
- my $parsed_anchor = _parse_node_manual($current);
- if (_check_node_label($self, $parsed_anchor,
- $current->{'parent'}->{'cmdname'},
$source_info)) {
- _register_label($self->{'targets'}, $current->{'parent'},
- $parsed_anchor);
- if (@{$self->{'regions_stack'}}) {
- $current->{'extra'}->{'region'} =
$self->{'regions_stack'}->[-1];
- }
- }
- } elsif ($ref_commands{$current->{'parent'}->{'cmdname'}}) {
- my $ref = $current->{'parent'};
- if (@{$ref->{'args'}}) {
- my @args;
- for $a (@{$ref->{'args'}}) {
- if (@{$a->{'contents'}}) {
- push @args, $a->{'contents'};
- } else {
- push @args, undef;
- }
- }
- if (($closed_command eq 'inforef'
- and !defined($args[0]) and !defined($args[2]))
- or ($closed_command ne 'inforef'
- and !defined($args[0]) and !defined($args[3])
- and !defined($args[4]))) {
- $self->_line_warn(sprintf(__(
- "command \@%s missing a node or external manual
argument"),
- $closed_command), $source_info);
- } else {
- my $parsed_ref_node =
_parse_node_manual($ref->{'args'}->[0]);
- if (defined $parsed_ref_node) {
- if ($closed_command ne 'inforef'
- and !defined($args[3]) and !defined($args[4])
- and !$parsed_ref_node->{'manual_content'}) {
- push @{$self->{'internal_references'}}, $ref;
- }
- $ref->{'extra'}->{'node_argument'} = $parsed_ref_node
- }
- }
- if (defined($args[1])) {
- if (_check_empty_expansion($args[1])) {
- $self->_line_warn(sprintf(__(
- "in \@%s empty cross reference name after expansion `%s'"),
- $closed_command,
- Texinfo::Convert::Texinfo::convert_to_texinfo(
- {'contents' => $args[1]})),
- $source_info);
- }
- }
- if ($closed_command ne 'inforef' and defined($args[2])) {
- if (_check_empty_expansion($args[2])) {
- $self->_line_warn(sprintf(__(
- "in \@%s empty cross reference title after expansion
`%s'"),
- $closed_command,
- Texinfo::Convert::Texinfo::convert_to_texinfo(
- {'contents' => $args[2]})),
- $source_info);
- }
- }
- }
- } elsif ($current->{'parent'}->{'cmdname'} eq 'image') {
- my $image = $current->{'parent'};
- if (!@{$image->{'args'}}
- or !defined($image->{'args'}->[0])
- or scalar(@{$image->{'args'}->[0]->{'contents'}}) == 0) {
- $self->_line_error(
- __("\@image missing filename argument"), $source_info);
- }
- $image->{'extra'}->{'input_perl_encoding'}
- = $self->{'info'}->{'input_perl_encoding'}
- if defined $self->{'info'}->{'input_perl_encoding'};
- } elsif($current->{'parent'}->{'cmdname'} eq 'dotless') {
- my $dotless = $current->{'parent'};
- if (@{$current->{'contents'}}) {
- my $text = $current->{'contents'}->[0]->{'text'};
- if (!defined ($text)
- or ($text ne 'i' and $text ne 'j')) {
- $self->_line_error(sprintf(
- __("%c%s expects `i' or `j' as argument, not `%s'"),
- ord('@'), $dotless->{'cmdname'},
-
Texinfo::Convert::Texinfo::convert_to_texinfo($current)),
- $source_info);
- }
- }
- } elsif ($explained_commands{$current->{'parent'}->{'cmdname'}}
- or $inline_commands{$current->{'parent'}->{'cmdname'}}) {
- my $current_command = $current->{'parent'};
- if ($inline_commands{$current_command->{'cmdname'}}) {
- if ($current_command->{'cmdname'} eq 'inlineraw') {
- my ($error) = $self->_pop_context(['ct_inlineraw'],
- $source_info, $current, ' inlineraw');
- die if ($error);
+ "command \@%s missing a node or external manual argument"),
+ $closed_command), $source_info);
+ } else {
+ my $parsed_ref_node = _parse_node_manual($ref->{'args'}->[0]);
+ if (defined $parsed_ref_node) {
+ if ($closed_command ne 'inforef'
+ and !defined($args[3]) and !defined($args[4])
+ and !$parsed_ref_node->{'manual_content'}) {
+ push @{$self->{'internal_references'}}, $ref;
}
+ $ref->{'extra'}->{'node_argument'} = $parsed_ref_node
}
- if (!@{$current_command->{'args'}}
- or !defined($current_command->{'args'}->[0])
- or scalar(@{$current_command->{'args'}->[0]->{'contents'}})
== 0) {
- $self->_line_warn(
- sprintf(__("\@%s missing first argument"),
- $current_command->{'cmdname'}), $source_info);
+ }
+ if (defined($args[1])) {
+ if (_check_empty_expansion($args[1])) {
+ $self->_line_warn(sprintf(__(
+ "in \@%s empty cross reference name after expansion `%s'"),
+ $closed_command,
+ Texinfo::Convert::Texinfo::convert_to_texinfo(
+ {'contents' => $args[1]})),
+ $source_info);
}
- } elsif ($current->{'parent'}->{'cmdname'} eq 'errormsg') {
- my $error_message_text = $current->{'contents'}->[0]->{'text'};
- $self->_line_error($error_message_text, $source_info)
- if $error_message_text;
- } elsif ($current->{'parent'}->{'cmdname'} eq 'U') {
- my $arg;
- if ($current->{'contents'}->[0]) {
- $arg = $current->{'contents'}->[0]->{'text'};
+ }
+ if ($closed_command ne 'inforef' and defined($args[2])) {
+ if (_check_empty_expansion($args[2])) {
+ $self->_line_warn(sprintf(__(
+ "in \@%s empty cross reference title after expansion `%s'"),
+ $closed_command,
+ Texinfo::Convert::Texinfo::convert_to_texinfo(
+ {'contents' => $args[2]})),
+ $source_info);
}
- if (!defined($arg) || !$arg) {
- $self->_line_warn(__("no argument specified for \@U"),
+ }
+ }
+ } elsif ($current->{'parent'}->{'cmdname'} eq 'image') {
+ my $image = $current->{'parent'};
+ if (!@{$image->{'args'}}
+ or !defined($image->{'args'}->[0])
+ or scalar(@{$image->{'args'}->[0]->{'contents'}}) == 0) {
+ $self->_line_error(
+ __("\@image missing filename argument"), $source_info);
+ }
+ $image->{'extra'}->{'input_perl_encoding'}
+ = $self->{'info'}->{'input_perl_encoding'}
+ if defined $self->{'info'}->{'input_perl_encoding'};
+ } elsif($current->{'parent'}->{'cmdname'} eq 'dotless') {
+ my $dotless = $current->{'parent'};
+ if (@{$current->{'contents'}}) {
+ my $text = $current->{'contents'}->[0]->{'text'};
+ if (!defined ($text)
+ or ($text ne 'i' and $text ne 'j')) {
+ $self->_line_error(sprintf(
+ __("%c%s expects `i' or `j' as argument, not `%s'"),
+ ord('@'), $dotless->{'cmdname'},
+ Texinfo::Convert::Texinfo::convert_to_texinfo($current)),
$source_info);
+ }
+ }
+ } elsif ($explained_commands{$current->{'parent'}->{'cmdname'}}
+ or $inline_commands{$current->{'parent'}->{'cmdname'}}) {
+ my $current_command = $current->{'parent'};
+ if ($inline_commands{$current_command->{'cmdname'}}) {
+ if ($current_command->{'cmdname'} eq 'inlineraw') {
+ my ($error) = $self->_pop_context(['ct_inlineraw'],
+ $source_info, $current, ' inlineraw');
+ die if ($error);
+ }
+ }
+ if (!@{$current_command->{'args'}}
+ or !defined($current_command->{'args'}->[0])
+ or scalar(@{$current_command->{'args'}->[0]->{'contents'}}) ==
0) {
+ $self->_line_warn(
+ sprintf(__("\@%s missing first argument"),
+ $current_command->{'cmdname'}), $source_info);
+ }
+ } elsif ($current->{'parent'}->{'cmdname'} eq 'errormsg') {
+ my $error_message_text = $current->{'contents'}->[0]->{'text'};
+ $self->_line_error($error_message_text, $source_info)
+ if $error_message_text;
+ } elsif ($current->{'parent'}->{'cmdname'} eq 'U') {
+ my $arg;
+ if ($current->{'contents'}->[0]) {
+ $arg = $current->{'contents'}->[0]->{'text'};
+ }
+ if (!defined($arg) || !$arg) {
+ $self->_line_warn(__("no argument specified for \@U"),
+ $source_info);
- } elsif ($arg !~ /^[0-9A-Fa-f]+$/) {
- $self->_line_error(
- sprintf(__("non-hex digits in argument for \@U: %s"), $arg),
- $source_info);
+ } elsif ($arg !~ /^[0-9A-Fa-f]+$/) {
+ $self->_line_error(
+ sprintf(__("non-hex digits in argument for \@U: %s"), $arg),
+ $source_info);
- } elsif (length ($arg) < 4) {
- # Perl doesn't mind, but too much trouble to do in TeX.
- $self->_line_warn(sprintf(__(
- "fewer than four hex digits in argument for \@U: %s"), $arg),
- $source_info);
+ } elsif (length ($arg) < 4) {
+ # Perl doesn't mind, but too much trouble to do in TeX.
+ $self->_line_warn(sprintf(__(
+ "fewer than four hex digits in argument for \@U: %s"), $arg),
+ $source_info);
- } else {
- # we don't want to call hex at all if the value isn't
- # going to fit; so first use eval to check.
- # Since integer overflow is only a warning, have to make
- # warnings fatal for the eval to be effective.
- eval qq!use warnings FATAL => qw(all); hex("$arg")!;
- if ($@) {
- # leave clue in case something else went wrong.
- warn "\@U hex($arg) eval failed: $@\n" if ($self->{'DEBUG'});
- # argument likely exceeds size of integer
- }
- # ok, value can be given to hex(), so try it.
- if ($@ or hex($arg) > 0x10FFFF) {
- $self->_line_error(sprintf(__(
- "argument for \@U exceeds Unicode maximum 0x10FFFF: %s"),
- $arg),
- $source_info);
- }
- }
+ } else {
+ # we don't want to call hex at all if the value isn't
+ # going to fit; so first use eval to check.
+ # Since integer overflow is only a warning, have to make
+ # warnings fatal for the eval to be effective.
+ eval qq!use warnings FATAL => qw(all); hex("$arg")!;
+ if ($@) {
+ # leave clue in case something else went wrong.
+ warn "\@U hex($arg) eval failed: $@\n" if ($self->{'DEBUG'});
+ # argument likely exceeds size of integer
+ }
+ # ok, value can be given to hex(), so try it.
+ if ($@ or hex($arg) > 0x10FFFF) {
+ $self->_line_error(sprintf(__(
+ "argument for \@U exceeds Unicode maximum 0x10FFFF: %s"),
+ $arg),
+ $source_info);
+ }
+ }
- } elsif
(_command_with_command_as_argument($current->{'parent'}->{'parent'})
- and scalar(@{$current->{'contents'}}) == 0) {
- print STDERR "FOR PARENT
\@$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'} command_as_argument
braces $current->{'parent'}->{'cmdname'}\n" if ($self->{'DEBUG'});
- $current->{'parent'}->{'type'} = 'command_as_argument'
- if (!$current->{'parent'}->{'type'});
-
$current->{'parent'}->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'}
- = $current->{'parent'};
- if ($current->{'parent'}->{'cmdname'} eq 'kbd'
- and _kbd_formatted_as_code($self,
-
$current->{'parent'}->{'parent'}->{'parent'})) {
-
$current->{'parent'}->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument_kbd_code'}
= 1;
- }
- } elsif ($in_index_commands{$current->{'parent'}->{'cmdname'}}) {
- my $command = $current->{'parent'}->{'cmdname'};
-
- my $index_element = $current->{'parent'}->{'parent'}->{'parent'};
- if ($index_element
- and _is_index_element($self, $index_element)) {
- if ($command eq 'sortas') {
- my ($arg, $superfluous_arg) = _convert_to_text($current);
- if (defined($arg)) {
- $index_element->{'extra'}->{$command} = $arg;
- }
- } else {
- $index_element->{'extra'}->{$command} = $current->{'parent'};
- }
+ } elsif
(_command_with_command_as_argument($current->{'parent'}->{'parent'})
+ and scalar(@{$current->{'contents'}}) == 0) {
+ print STDERR "FOR PARENT
\@$current->{'parent'}->{'parent'}->{'parent'}->{'cmdname'} command_as_argument
braces $current->{'parent'}->{'cmdname'}\n" if ($self->{'DEBUG'});
+ $current->{'parent'}->{'type'} = 'command_as_argument'
+ if (!$current->{'parent'}->{'type'});
+
$current->{'parent'}->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument'}
+ = $current->{'parent'};
+ if ($current->{'parent'}->{'cmdname'} eq 'kbd'
+ and _kbd_formatted_as_code($self,
+
$current->{'parent'}->{'parent'}->{'parent'})) {
+
$current->{'parent'}->{'parent'}->{'parent'}->{'extra'}->{'command_as_argument_kbd_code'}
= 1;
+ }
+ } elsif ($in_index_commands{$current->{'parent'}->{'cmdname'}}) {
+ my $command = $current->{'parent'}->{'cmdname'};
+
+ my $index_element = $current->{'parent'}->{'parent'}->{'parent'};
+ if ($index_element
+ and _is_index_element($self, $index_element)) {
+ if ($command eq 'sortas') {
+ my ($arg, $superfluous_arg) = _convert_to_text($current);
+ if (defined($arg)) {
+ $index_element->{'extra'}->{$command} = $arg;
}
+ } else {
+ $index_element->{'extra'}->{$command} = $current->{'parent'};
}
- _register_global_command($self, $current->{'parent'},
$source_info);
- if
($command_ignore_space_after{$current->{'parent'}->{'cmdname'}}) {
- push @{$current->{'parent'}->{'parent'}->{'contents'}},
- {'type' => 'empty_spaces_after_close_brace',
- 'text' => '',
- 'parent' => $current->{'parent'}->{'parent'}
- };
- }
- $current = $current->{'parent'}->{'parent'};
- $current = _begin_preformatted($self, $current)
- if ($close_preformatted_commands{$closed_command});
- # lone braces accepted right in a rawpreformatted
- } elsif ($current->{'type'}
- and $current->{'type'} eq 'rawpreformatted') {
- push @{$current->{'contents'}}, {'text' => '}',
- 'parent' => $current };
- # footnote caption closing, when there is a paragraph inside.
- } elsif ($self->_top_context() eq 'ct_brace_command') {
- # closing the context under broader situations
- $current = _end_paragraph($self, $current, $source_info);
- if ($current->{'parent'}
- and $current->{'parent'}->{'cmdname'}
- and
$context_brace_commands{$current->{'parent'}->{'cmdname'}}) {
- my ($error) = $self->_pop_context(['ct_brace_command'],
- $source_info, $current,
- "for brace isolated $current->{'parent'}->{'cmdname'}");
- die if ($error);
- print STDERR "CLOSING(context command)
\@$current->{'parent'}->{'cmdname'}\n"
- if ($self->{'DEBUG'});
- my $closed_command = $current->{'parent'}->{'cmdname'};
- _register_global_command($self, $current->{'parent'},
$source_info);
- $current = $current->{'parent'}->{'parent'};
- $current = _begin_preformatted($self, $current)
- if ($close_preformatted_commands{$closed_command});
+ }
+ }
+ _register_global_command($self, $current->{'parent'}, $source_info);
+ if ($command_ignore_space_after{$current->{'parent'}->{'cmdname'}}) {
+ push @{$current->{'parent'}->{'parent'}->{'contents'}},
+ {'type' => 'empty_spaces_after_close_brace',
+ 'text' => '',
+ 'parent' => $current->{'parent'}->{'parent'}
+ };
+ }
+ $current = $current->{'parent'}->{'parent'};
+ $current = _begin_preformatted($self, $current)
+ if ($close_preformatted_commands{$closed_command});
+ # lone braces accepted right in a rawpreformatted
+ } elsif ($current->{'type'}
+ and $current->{'type'} eq 'rawpreformatted') {
+ push @{$current->{'contents'}}, {'text' => '}',
+ 'parent' => $current };
+ # footnote caption closing, when there is a paragraph inside.
+ } elsif ($self->_top_context() eq 'ct_brace_command') {
+ # closing the context under broader situations
+ $current = _end_paragraph($self, $current, $source_info);
+ if ($current->{'parent'}
+ and $current->{'parent'}->{'cmdname'}
+ and $context_brace_commands{$current->{'parent'}->{'cmdname'}}) {
+ my ($error) = $self->_pop_context(['ct_brace_command'],
+ $source_info, $current,
+ "for brace isolated $current->{'parent'}->{'cmdname'}");
+ die if ($error);
+ print STDERR "CLOSING(context command)
\@$current->{'parent'}->{'cmdname'}\n"
+ if ($self->{'DEBUG'});
+ my $closed_command = $current->{'parent'}->{'cmdname'};
+ _register_global_command($self, $current->{'parent'}, $source_info);
+ $current = $current->{'parent'}->{'parent'};
+ $current = _begin_preformatted($self, $current)
+ if ($close_preformatted_commands{$closed_command});
+ }
+ } else {
+ $self->_line_error(sprintf(__("misplaced %c"),
+ ord('}')), $source_info);
+ }
+ } elsif ($separator eq ','
+ and $current->{'parent'}->{'remaining_args'}) {
+ _abort_empty_line ($self, $current);
+ _isolate_last_space($self, $current);
+ my $type = $current->{'type'};
+ $current = $current->{'parent'};
+ if ($inline_commands{$current->{'cmdname'}}) {
+ my $expandp = 0;
+ if (! $current->{'extra'}->{'format'}) {
+ my $inline_type;
+ if (defined $current->{'args'}->[0]
+ and @{$current->{'args'}->[0]->{'contents'}}) {
+ $inline_type =
$current->{'args'}->[0]->{'contents'}->[0]->{'text'};
+ }
+
+ if (!$inline_type) {
+ # condition is missing for some reason
+ print STDERR "INLINE COND MISSING\n"
+ if ($self->{'DEBUG'});
+ } elsif ($inline_format_commands{$current->{'cmdname'}}) {
+ if ($self->{'expanded_formats_hash'}->{$inline_type}) {
+ $expandp = 1;
+ $current->{'extra'}->{'expand_index'} = 1;
+ } else {
+ $expandp = 0;
}
+ } elsif (($current->{'cmdname'} eq 'inlineifset'
+ and exists($self->{'values'}->{$inline_type}))
+ or ($current->{'cmdname'} eq 'inlineifclear'
+ and ! exists($self->{'values'}->{$inline_type}))) {
+ $expandp = 1;
+ $current->{'extra'}->{'expand_index'} = 1;
} else {
- $self->_line_error(sprintf(__("misplaced %c"),
- ord('}')), $source_info);
+ $expandp = 0;
}
- } elsif ($separator eq ','
- and $current->{'parent'}->{'remaining_args'}) {
- _abort_empty_line ($self, $current);
- _isolate_last_space($self, $current);
- my $type = $current->{'type'};
- $current = $current->{'parent'};
- if ($inline_commands{$current->{'cmdname'}}) {
- my $expandp = 0;
- if (! $current->{'extra'}->{'format'}) {
- my $inline_type;
- if (defined $current->{'args'}->[0]
- and @{$current->{'args'}->[0]->{'contents'}}) {
- $inline_type =
$current->{'args'}->[0]->{'contents'}->[0]->{'text'};
- }
-
- if (!$inline_type) {
- # condition is missing for some reason
- print STDERR "INLINE COND MISSING\n"
- if ($self->{'DEBUG'});
- } elsif ($inline_format_commands{$current->{'cmdname'}}) {
- if ($self->{'expanded_formats_hash'}->{$inline_type}) {
- $expandp = 1;
- $current->{'extra'}->{'expand_index'} = 1;
- } else {
- $expandp = 0;
+ $current->{'extra'}->{'format'} = $inline_type;
+
+ # Skip first argument for a false @inlinefmtifelse
+ if (!$expandp and $current->{'cmdname'} eq 'inlinefmtifelse') {
+ $current->{'extra'}->{'expand_index'} = 2;
+
+ # Add a dummy argument for the first argument.
+ push @{$current->{'args'}}, {'type' => 'elided',
+ 'parent' => $current,
+ 'contents' => []};
+
+ # Scan forward to get the next argument.
+ my $brace_count = 1;
+ while ($brace_count > 0) {
+ # Forward to next comma or brace
+ if ($line =~ s/[^{,}]*([,{}])//) {
+ if ($1 eq ',' and $brace_count == 1) {
+ last;
+ } elsif ($1 eq '{') {
+ $brace_count++;
+ } elsif ($1 eq '}') {
+ $brace_count--;
}
- } elsif (($current->{'cmdname'} eq 'inlineifset'
- and exists($self->{'values'}->{$inline_type}))
- or ($current->{'cmdname'} eq 'inlineifclear'
- and ! exists($self->{'values'}->{$inline_type}))) {
- $expandp = 1;
- $current->{'extra'}->{'expand_index'} = 1;
} else {
- $expandp = 0;
- }
- $current->{'extra'}->{'format'} = $inline_type;
-
- # Skip first argument for a false @inlinefmtifelse
- if (!$expandp and $current->{'cmdname'} eq 'inlinefmtifelse') {
- $current->{'extra'}->{'expand_index'} = 2;
-
- # Add a dummy argument for the first argument.
- push @{$current->{'args'}}, {'type' => 'elided',
- 'parent' => $current,
- 'contents' => []};
-
- # Scan forward to get the next argument.
- my $brace_count = 1;
- while ($brace_count > 0) {
- # Forward to next comma or brace
- if ($line =~ s/[^{,}]*([,{}])//) {
- if ($1 eq ',' and $brace_count == 1) {
- last;
- } elsif ($1 eq '{') {
- $brace_count++;
- } elsif ($1 eq '}') {
- $brace_count--;
- }
- } else {
- my $new_text;
- ($new_text, $source_info) = _next_text($self,
$source_info);
- if (!$new_text) {
- next NEXT_LINE; # error - unbalanced brace
- }
- $line .= $new_text;
- }
- }
- if ($brace_count == 0) {
- # second arg missing
- $line = '}' . $line;
+ my $new_text;
+ ($new_text, $source_info) = _next_text($self, $source_info);
+ if (!$new_text) {
+ $retval = $GET_A_NEW_LINE; # error - unbalanced brace
+ goto funexit;
}
- $current->{'remaining_args'}--;
- $expandp = 1;
+ $line .= $new_text;
}
- } elsif ($current->{'cmdname'} eq 'inlinefmtifelse') {
- # Second arg of @inlinefmtifelse when condition is true.
- # Discard second argument.
- $expandp = 0;
}
- # If this command is not being expanded, add a dummy argument,
- # and scan forward to the closing brace.
- if (!$expandp) {
- push @{$current->{'args'}}, {'type' => 'elided',
- 'parent' => $current,
- 'contents' => []};
- my $brace_count = 1;
- while ($brace_count > 0) {
- if ($line =~ s/[^{}]*([{}])//) {
- if ($1 eq '{') {
- $brace_count++;
- } else {
- $brace_count--;
- }
- } else {
- my $new_text;
- ($new_text, $source_info) = _next_text($self, $source_info);
- if (!$new_text) {
- next NEXT_LINE; # error - unbalanced brace
- }
- $line .= $new_text;
- }
- }
- $current = $current->{'args'}->[-1];
+ if ($brace_count == 0) {
+ # second arg missing
$line = '}' . $line;
- next;
}
+ $current->{'remaining_args'}--;
+ $expandp = 1;
}
- $current->{'remaining_args'}--;
- push @{$current->{'args'}},
- { 'type' => $type, 'parent' => $current, 'contents' => [] };
- $current = $current->{'args'}->[-1];
- # empty_spaces_before_argument is a transient internal type,
- # which should end up in extra spaces_before_argument.
- push @{$current->{'contents'}},
- {'type' => 'empty_spaces_before_argument',
- 'text' => '',
- 'parent' => $current,
- 'extra' => {'spaces_associated_command' => $current}
- };
- } elsif ($separator eq ',' and $current->{'type'}
- and $current->{'type'} eq 'line_arg'
- and $current->{'parent'}->{'cmdname'}
- and $current->{'parent'}->{'cmdname'} eq 'node') {
- $self->_line_warn(__("superfluous arguments for node"),
$source_info);
- # end of menu node (. must be followed by a space to stop the node).
- } elsif (($separator =~ /[,\t.]/ and $current->{'type'}
- and $current->{'type'} eq 'menu_entry_node')
- or ($separator eq ':' and $current->{'type'}
- and $current->{'type'} eq 'menu_entry_name')) {
- $current = $current->{'parent'};
- push @{$current->{'args'}}, { 'type' => 'menu_entry_separator',
- 'text' => $separator,
- 'parent' => $current };
- } elsif ($separator eq "\f" and $current->{'type'}
- and $current->{'type'} eq 'paragraph') {
- # form feed stops and restart a paragraph.
- $current = $self->_end_paragraph($current);
- push @{$current->{'contents'}}, {'text' => $separator,
- 'type' => 'empty_line',
- 'parent' => $current };
- push @{$current->{'contents'}}, { 'type' => 'empty_line',
- 'text' => '',
- 'parent' => $current };
- } else {
- $current = _merge_text($self, $current, $separator);
+ } elsif ($current->{'cmdname'} eq 'inlinefmtifelse') {
+ # Second arg of @inlinefmtifelse when condition is true.
+ # Discard second argument.
+ $expandp = 0;
}
- # Misc text except end of line
- } elsif (defined $misc_text) {
- print STDERR "MISC TEXT: $misc_text\n" if ($self->{'DEBUG'});
- my $new_text = $misc_text;
- substr ($line, 0, length ($misc_text)) = '';
- $current = _merge_text($self, $current, $new_text);
- # end of line
- } else {
- print STDERR "END LINE: ". _print_current($current)."\n"
- if ($self->{'DEBUG'});
- if ($line =~ s/^(\n)//) {
- $current = _merge_text($self, $current, $1);
- } else {
- if (scalar(@{$self->{'input'}})) {
- $self->_bug_message("Text remaining without normal text but
`$line'",
- $source_info, $current);
- die;
+ # If this command is not being expanded, add a dummy argument,
+ # and scan forward to the closing brace.
+ if (!$expandp) {
+ push @{$current->{'args'}}, {'type' => 'elided',
+ 'parent' => $current,
+ 'contents' => []};
+ my $brace_count = 1;
+ while ($brace_count > 0) {
+ if ($line =~ s/[^{}]*([{}])//) {
+ if ($1 eq '{') {
+ $brace_count++;
+ } else {
+ $brace_count--;
+ }
+ } else {
+ my $new_text;
+ ($new_text, $source_info) = _next_text($self, $source_info);
+ if (!$new_text) {
+ $retval = $GET_A_NEW_LINE; # error - unbalanced brace
+ goto funexit;
+ }
+ $line .= $new_text;
+ }
}
+ $current = $current->{'args'}->[-1];
+ $line = '}' . $line;
+ goto funexit;
}
- $current = _end_line($self, $current, $source_info);
+ }
+ $current->{'remaining_args'}--;
+ push @{$current->{'args'}},
+ { 'type' => $type, 'parent' => $current, 'contents' => [] };
+ $current = $current->{'args'}->[-1];
+ # empty_spaces_before_argument is a transient internal type,
+ # which should end up in extra spaces_before_argument.
+ push @{$current->{'contents'}},
+ {'type' => 'empty_spaces_before_argument',
+ 'text' => '',
+ 'parent' => $current,
+ 'extra' => {'spaces_associated_command' => $current}
+ };
+ } elsif ($separator eq ',' and $current->{'type'}
+ and $current->{'type'} eq 'line_arg'
+ and $current->{'parent'}->{'cmdname'}
+ and $current->{'parent'}->{'cmdname'} eq 'node') {
+ $self->_line_warn(__("superfluous arguments for node"), $source_info);
+ # end of menu node (. must be followed by a space to stop the node).
+ } elsif (($separator =~ /[,\t.]/ and $current->{'type'}
+ and $current->{'type'} eq 'menu_entry_node')
+ or ($separator eq ':' and $current->{'type'}
+ and $current->{'type'} eq 'menu_entry_name')) {
+ $current = $current->{'parent'};
+ push @{$current->{'args'}}, { 'type' => 'menu_entry_separator',
+ 'text' => $separator,
+ 'parent' => $current };
+ } elsif ($separator eq "\f" and $current->{'type'}
+ and $current->{'type'} eq 'paragraph') {
+ # form feed stops and restart a paragraph.
+ $current = $self->_end_paragraph($current);
+ push @{$current->{'contents'}}, {'text' => $separator,
+ 'type' => 'empty_line',
+ 'parent' => $current };
+ push @{$current->{'contents'}}, { 'type' => 'empty_line',
+ 'text' => '',
+ 'parent' => $current };
+ } else {
+ $current = _merge_text($self, $current, $separator);
+ }
+ # Misc text except end of line
+ } elsif (defined $misc_text) {
+ print STDERR "MISC TEXT: $misc_text\n" if ($self->{'DEBUG'});
+ my $new_text = $misc_text;
+ substr ($line, 0, length ($misc_text)) = '';
+ $current = _merge_text($self, $current, $new_text);
+ # end of line
+ } else {
+ print STDERR "END LINE: ". _print_current($current)."\n"
+ if ($self->{'DEBUG'});
+ if ($line =~ s/^(\n)//) {
+ $current = _merge_text($self, $current, $1);
+ } else {
+ if (scalar(@{$self->{'input'}})) {
+ $self->_bug_message("Text remaining without normal text but `$line'",
+ $source_info, $current);
+ die;
+ }
+ }
+ $current = _end_line($self, $current, $source_info);
+ $retval = $GET_A_NEW_LINE;
+ goto funexit;
+ }
+
+ funexit:
+ return ($current, $line, $source_info, $retval);
+}
+
+# the main subroutine
+sub _parse_texi($$$)
+{
+ my ($self, $root, $current) = @_;
+
+ my $source_info;
+
+ NEXT_LINE:
+ while (1) {
+ my $line;
+ ($line, $source_info) = _next_text($self, $source_info);
+ last if (!defined($line));
+
+ if ($self->{'DEBUG'}) {
+ my $line_text = '';
+ $line_text = "$source_info->{'line_nr'}.$source_info->{'macro'}"
+ if ($source_info);
+ print STDERR "NEW LINE("
+ .join('|', $self->_get_context_stack())
+ .":@{$self->{'conditionals_stack'}}:$line_text): $line";
+ #print STDERR "CONTEXT_STACK
".join('|',$self->_get_context_stack())."\n";
+ #print STDERR " $current:
".Texinfo::Common::debug_print_element_short($current)."\n";
+ }
+
+ if (not
+ # all the format handled early that have specific containers
+ # 'raw' command or ignored conditional or verb or ignored raw format
+ (($current->{'cmdname'}
+ and $block_commands{$current->{'cmdname'}}
+ and ($block_commands{$current->{'cmdname'}} eq 'raw'
+ or $block_commands{$current->{'cmdname'}} eq 'conditional'))
+ or
+ ($current->{'parent'} and $current->{'parent'}->{'cmdname'}
+ and $current->{'parent'}->{'cmdname'} eq 'verb')
+ or
+ ($current->{'cmdname'}
+ and $format_raw_commands{$current->{'cmdname'}}
+ and not $self->{'expanded_formats_hash'}->{$current->{'cmdname'}})
+ )
+ # not def line
+ and $self->_top_context() ne 'ct_def') {
+ next NEXT_LINE if _check_line_directive ($self, $line, $source_info);
+ print STDERR "BEGIN LINE\n" if ($self->{'DEBUG'});
+
+ if ($current->{'contents'}
+ and $current->{'contents'}->[-1]
+ and $current->{'contents'}->[-1]->{'type'}
+ and $current->{'contents'}->[-1]->{'type'}
+ eq 'empty_spaces_before_argument') {
+ # Empty spaces after brace or comma till the end of line.
+ # Remove this element and update 'extra' values.
+ _abort_empty_line($self, $current);
+ }
+ $line =~ s/^([^\S\r\n]*)//;
+ push @{$current->{'contents'}}, { 'type' => 'empty_line',
+ 'text' => $1,
+ 'parent' => $current };
+ }
+
+ while (1) {
+ my $status;
+ ($current, $line, $source_info, $status)
+ = _process_remaining_on_line($self, $current, $line, $source_info);
+ if ($status == $GET_A_NEW_LINE) {
last;
+ } elsif ($status == $FINISHED_TOTALLY) {
+ goto finished_totally;
}
}
}
+ finished_totally:
while (@{$self->{'conditionals_stack'}}) {
my $end_conditional = pop @{$self->{'conditionals_stack'}};
$self->_line_error(sprintf(__("expected \@end %s"), $end_conditional),
diff --git a/tp/Texinfo/XS/parsetexi/parser.c b/tp/Texinfo/XS/parsetexi/parser.c
index a30758ba6f..a4f4ddebe7 100644
--- a/tp/Texinfo/XS/parsetexi/parser.c
+++ b/tp/Texinfo/XS/parsetexi/parser.c
@@ -1067,7 +1067,10 @@ check_valid_nesting (ELEMENT *current, enum command_id
cmd)
}
/* *LINEP is a pointer into the line being processed. It is advanced past any
- bytes processed. Return 0 when we need to read a new line. */
+ bytes processed.
+ Return STILL_MORE_TO_PROCESS when there is more to process on the line
+ GET_A_NEW_LINE when we need to read a new line
+ FINISHED_TOTALLY when @bye was found */
int
process_remaining_on_line (ELEMENT **current_inout, char **line_inout)
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- branch master updated: * tp/Texinfo/ParserNonXS.pm (_parse_texi, _process_remaining_on_line): add _process_remaining_on_line to match better with the XS parser.,
Patrice Dumas <=